diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,8 +61,20 @@ set(HAVE_SYS_INOTIFY_H FALSE) endif() +option(ENABLE_PROCSTAT "Try to use libprocstat for process information" ON) +if (ENABLE_PROCSTAT) + # Find libprocstat + find_package(Procstat) + set_package_properties(Procstat PROPERTIES + PURPOSE "Process information using libprocstat") + set(HAVE_PROCSTAT ${PROCSTAT_FOUND}) +else() + set(HAVE_PROCSTAT FALSE) +endif() + # Generate io/config-kdirwatch.h configure_file(src/lib/io/config-kdirwatch.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/lib/io/config-kdirwatch.h) +configure_file(src/lib/util/config-kprocesslist.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/lib/util/config-kprocesslist.h) include(ECMPoQmTools) diff --git a/cmake/FindProcstat.cmake b/cmake/FindProcstat.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindProcstat.cmake @@ -0,0 +1,48 @@ +# - Try to find procstat library +# Once done this will define +# +# PROCSTAT_FOUND - system has procstat +# PROCSTAT_INCLUDE_DIR - the procstat include directory +# PROCSTAT_LIBRARIES - The libraries needed to use procstat + +# Copyright (c) 2019, Tobias C. Berner +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + + +FIND_PATH(PROCSTAT_INCLUDE_DIR libprocstat.h) + +FIND_LIBRARY(PROCSTAT_LIBRARIES NAMES procstat ) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PROCSTAT DEFAULT_MSG PROCSTAT_INCLUDE_DIR PROCSTAT_LIBRARIES ) + +set_package_properties(PROCSTAT PROPERTIES + URL "https://github.com/freebsd/freebsd/tree/master/lib/libprocstat" + DESCRIPTION "Library to access process information" +) + +MARK_AS_ADVANCED(PROCSTAT_INCLUDE_DIR PROCSTAT_LIBRARIES) + diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -108,6 +108,13 @@ ${CMAKE_CURRENT_SOURCE_DIR}/util/ ) +if (HAVE_PROCSTAT) + set(kcoreaddons_INCLUDE_DIRS + ${kcoreaddons_INCLUDE_DIRS} + ${PROCSTAT_INCLUDE_DIR} + ) +endif() + ecm_qt_declare_logging_category(libkcoreaddons_SRCS HEADER kcoreaddons_debug.h IDENTIFIER KCOREADDONS_DEBUG @@ -132,6 +139,10 @@ target_link_libraries(KF5CoreAddons PRIVATE netapi32 userenv) endif() +if(HAVE_PROCSTAT) + target_link_libraries(KF5CoreAddons PRIVATE ${PROCSTAT_LIBRARIES}) +endif() + target_include_directories(KF5CoreAddons INTERFACE "$" ) target_compile_definitions(KF5CoreAddons INTERFACE "$") diff --git a/src/lib/util/config-kprocesslist.h.cmake b/src/lib/util/config-kprocesslist.h.cmake new file mode 100644 --- /dev/null +++ b/src/lib/util/config-kprocesslist.h.cmake @@ -0,0 +1 @@ +#cmakedefine01 HAVE_PROCSTAT diff --git a/src/lib/util/kprocesslist_unix.cpp b/src/lib/util/kprocesslist_unix.cpp --- a/src/lib/util/kprocesslist_unix.cpp +++ b/src/lib/util/kprocesslist_unix.cpp @@ -28,11 +28,21 @@ ** **************************************************************************/ +#include "config-kprocesslist.h" #include "kprocesslist.h" #include #include +#if HAVE_PROCSTAT +#include +#include +#include +#include +#include +#include +#endif + using namespace KProcessList; namespace { @@ -46,14 +56,77 @@ return true; } +KProcessInfoList unixProcessListKinfoProcStat() +{ + KProcessInfoList rc; + + struct procstat *pstat; + pstat = procstat_open_sysctl(); + + if (!pstat) { + return rc; + } + + unsigned int proc_count; + struct kinfo_proc *procs; + procs = procstat_getprocs(pstat, KERN_PROC_PROC, 0, &proc_count); + + if (!procs || proc_count == 0) + { + procstat_close(pstat); + return rc; + } + + for (unsigned int i = 0; i < proc_count; i++) + { + struct kinfo_proc *proc = &procs[i]; + + QStringList command_line; + pid_t pid = proc->ki_pid; + QString user = QString::fromLocal8Bit(proc->ki_login); + QString cmd ; + char pathname[PATH_MAX]; + if (procstat_getpathname(pstat, proc, pathname, sizeof(pathname)) != 0) + { + cmd = QString::fromLocal8Bit(pathname); + } else { + cmd = QString::fromLocal8Bit(proc->ki_comm); + } + command_line << cmd; + + char **args; + args = procstat_getargv(pstat, proc, 0); + if (args) + { + for (int i = 0; args[i] != nullptr; i++) + { + QString argument = QString::fromLocal8Bit(args[i]); + command_line << argument; + } + } + + QString name = command_line.join(QString::fromLocal8Bit(" ")); + rc.push_back(KProcessInfo(pid, name, user)); + } + + procstat_freeprocs(pstat, procs); + procstat_close(pstat); + + return rc; +} + // Determine UNIX processes by running ps KProcessInfoList unixProcessListPS() { #ifdef Q_OS_MAC // command goes last, otherwise it is cut off static const char formatC[] = "pid state user command"; #else +# ifdef Q_OS_FREEBSD + static const char formatC[] = "pid,state,user,command"; +# else static const char formatC[] = "pid,state,user,cmd"; +# endif #endif KProcessInfoList rc; QProcess psProcess; @@ -93,6 +166,11 @@ KProcessInfoList KProcessList::processInfoList() { const QDir procDir(QStringLiteral("/proc/")); + +#ifdef HAVE_PROCSTAT + return unixProcessListKinfoProcStat(); +#endif + #ifdef Q_OS_FREEBSD QString statusFileName(QStringLiteral("/status")); #else