diff options
author | Andrew Christian <andrew.christian@nokia.com> | 2012-02-09 09:02:25 -0500 |
---|---|---|
committer | Chris Craig <ext-chris.craig@nokia.com> | 2012-02-10 04:06:15 +0100 |
commit | acd5d8d6ff45c002d97af70d1b9ee6aaf6edb898 (patch) | |
tree | 81b79783e480ec368f67d15869ff2c25b3bd3717 /src | |
parent | d33cd2c25f6062d51eba713126bbe881021f693b (diff) |
Added ExecutingProcessInfo object for data display of executing processes
Change-Id: I127d41d7e5015073f96ef8d780efa50369e05e56
Reviewed-by: Chris Craig <ext-chris.craig@nokia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/procutils.cpp | 196 | ||||
-rw-r--r-- | src/core/procutils.h | 48 |
2 files changed, 244 insertions, 0 deletions
diff --git a/src/core/procutils.cpp b/src/core/procutils.cpp index 0d3f0ea..405828d 100644 --- a/src/core/procutils.cpp +++ b/src/core/procutils.cpp @@ -50,12 +50,207 @@ #include <QDebug> +#if defined(Q_OS_MAC) +#include <sys/sysctl.h> +#include <errno.h> +#endif + QT_BEGIN_NAMESPACE_PROCESSMANAGER +struct ProcessPrivateData { + pid_t pid, ppid, pgrp, sid; + uid_t uid, euid, suid; + gid_t gid, egid, sgid; + int priority, nice; +}; + +/*! + Construct a ExecutingProcessInfo object from \a pid. + */ + +ExecutingProcessInfo::ExecutingProcessInfo(pid_t pid) + : m_data(0) +{ +#if defined(Q_OS_LINUX) + QFile file(QString::fromLatin1("/proc/%1/stat").arg(pid)); + if (!file.open(QIODevice::ReadOnly)) + return; + + m_data = new ProcessPrivateData; + memset(m_data, 0, sizeof(ProcessPrivateData)); + QList<QByteArray> contents = file.readAll().split(' '); + file.close(); + /* + Index, name, format, description (from man 5 page for proc) + 0 pid %d The process ID. + 3 ppid %d The PID of the parent. + 4 pgrp %d The process group ID of the process. + 5 session %d The session ID of the process. + 17 priority %ld For processes running under a non-real-time scheduling policy, this is + the raw nice value (setpriority(2)) as represented in the kernel. + The kernel stores nice values as numbers in the range 0 (high) to 39 (low), + corresponding to the user- visible nice range of -20 to 19. + 18 nice %ld The nice value (see setpriority(2)), a value in the range + 19 (low priority) to -20 (high priority). + */ + m_data->pid = contents.at(0).toInt(); + m_data->ppid = contents.at(3).toInt(); + m_data->pgrp = contents.at(4).toInt(); + m_data->sid = contents.at(5).toInt(); + m_data->priority = contents.at(17).toLong(); + m_data->nice = contents.at(18).toLong(); + + /* Some of the contents (from kernel documentation proc.txt) + Field Content + Name filename of the executable + Pid process id + PPid process id of the parent process + Uid Real, effective, saved set, and file system UIDs + Gid Real, effective, saved set, and file system GIDs + Groups supplementary group list + ... + */ + QFile status(QString::fromLatin1("/proc/%1/status").arg(pid)); + if (!status.open(QIODevice::ReadOnly)) { + qWarning("Unable to open status file for pid=%d", pid); + return; + } + + char buf[256]; + qint64 len; + while ((len = status.readLine(buf, 256)) != -1) { + if (!strncmp("Name:", buf, 5)) + m_name = QString::fromLocal8Bit(buf + 6, len-6); + else if (!strncmp("Uid:", buf, 4)) { + QList<QByteArray> uids = QByteArray(buf + 5, len-5).split('\t'); + m_data->uid = uids.at(0).toInt(); + m_data->euid = uids.at(1).toInt(); + m_data->suid = uids.at(2).toInt(); + } + else if (!strncmp("Gid:", buf, 4)) { + QList<QByteArray> gids = QByteArray(buf + 5, len-5).split('\t'); + m_data->gid = gids.at(0).toInt(); + m_data->egid = gids.at(1).toInt(); + m_data->sgid = gids.at(2).toInt(); + } + else if (!strncmp("Groups:", buf, 7)) { + QList<QByteArray> groups = QByteArray(buf+8, len-8).split(' '); + while (groups.size()) { + bool ok; + gid_t group = groups.takeFirst().toInt(&ok); + if (ok) + m_groups.append(group); + } + } + } + status.close(); +#elif defined(Q_OS_MAC) + int name[4]; + size_t bufferSize; + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_PID; + name[3] = pid; + + if (::sysctl(name, 4, NULL, &bufferSize, NULL, 0) < 0) { + qDebug() << "error code" << errno; + return; + } + struct kinfo_proc *kinfo = (struct kinfo_proc *) malloc(bufferSize); + if (!kinfo) + return; + if (::sysctl(name, 4, kinfo, &bufferSize, NULL, 0) < 0) { + free(kinfo); + return; + } + int n = bufferSize / sizeof(struct kinfo_proc); + if (n != 1) { + free(kinfo); + return; + } + + qDebug() << "Creating data"; + m_data = new ProcessPrivateData; + memset(m_data, 0, sizeof(ProcessPrivateData)); + + // Proc data + m_data->pid = kinfo->kp_proc.p_pid; + m_data->priority = kinfo->kp_proc.p_priority; // Process priority (u_char) + m_data->nice = kinfo->kp_proc.p_nice; // Process 'nice' value (char) + + // Effective proc data + m_data->ppid = kinfo->kp_eproc.e_ppid; // Parent process id + m_data->pgrp = kinfo->kp_eproc.e_pgid; // Process group id + m_data->uid = kinfo->kp_eproc.e_pcred.p_ruid; // Real user ID + m_data->suid = kinfo->kp_eproc.e_pcred.p_svuid; // Saved user ID + m_data->gid = kinfo->kp_eproc.e_pcred.p_rgid; // Real group ID + m_data->sgid = kinfo->kp_eproc.e_pcred.p_svgid; // Saved group ID + + // Credentials + m_data->euid = kinfo->kp_eproc.e_ucred.cr_uid; // Effective user ID + for (int i = 0 ; i < kinfo->kp_eproc.e_ucred.cr_ngroups ; i++) + m_groups.append(kinfo->kp_eproc.e_ucred.cr_groups[i]); + m_data->egid = m_groups.at(0); // I believe this is correct + free(kinfo); + + // Session + m_data->sid = ::getsid(m_data->pid); + + // Name requires two additional sysctl calls + name[0] = CTL_KERN; + name[1] = KERN_ARGMAX; + int maxArgs; + bufferSize = sizeof(maxArgs); + if (::sysctl(name, 2, &maxArgs, &bufferSize, NULL, 0) == -1) + return; + char *args = (char *) malloc(maxArgs); + if (!args) + return; + + name[0] = CTL_KERN; + name[1] = KERN_PROCARGS2; + name[2] = pid; + bufferSize = (size_t) maxArgs; + if (::sysctl(name, 3, args, &bufferSize, NULL, 0) == -1) { + free(args); + return; + } + char *p = args + sizeof(int); // First few bytes are the number of arguments + char *p2 = strrchr(p, '/'); + if (p2) + m_name = QString::fromLocal8Bit(p2+1); + else + m_name = QString::fromLocal8Bit(p); + free(args); +#endif +} + +bool ExecutingProcessInfo::exists() const { return (m_data != 0); } +pid_t ExecutingProcessInfo::pid() const { return (m_data ? m_data->pid : 0); } +pid_t ExecutingProcessInfo::ppid() const { return (m_data ? m_data->ppid : 0); } +pid_t ExecutingProcessInfo::pgrp() const { return (m_data ? m_data->pgrp : 0); } +pid_t ExecutingProcessInfo::sid() const { return (m_data ? m_data->sid : 0); } +uid_t ExecutingProcessInfo::uid() const { return (m_data ? m_data->uid : 0); } +uid_t ExecutingProcessInfo::euid() const { return (m_data ? m_data->euid : 0); } +uid_t ExecutingProcessInfo::suid() const { return (m_data ? m_data->suid : 0); } +gid_t ExecutingProcessInfo::gid() const { return (m_data ? m_data->gid : 0); } +gid_t ExecutingProcessInfo::egid() const { return (m_data ? m_data->egid : 0); } +gid_t ExecutingProcessInfo::sgid() const { return (m_data ? m_data->sgid : 0); } +int ExecutingProcessInfo::priority() const { return (m_data ? m_data->priority : 0); } +int ExecutingProcessInfo::nice() const { return (m_data ? m_data->nice : 0); } + + ProcUtils::ProcUtils() { } + +/*! + Note: Under MacOSX, we need to use sysctl with CTL_KERN, KERN_PROC, KERN_PROCARGS2, pid + which returns a buffer containing the process name, all arguments, all environment variables + and sometimes other stuff. + */ + QString ProcUtils::execNameForPid(qint64 pid) { #if defined(Q_OS_LINUX) @@ -189,5 +384,6 @@ bool ProcUtils::setOomAdjustment(pid_t pid, qint32 oomAdjustment) return false; } +#include "moc_procutils.cpp" QT_END_NAMESPACE_PROCESSMANAGER diff --git a/src/core/procutils.h b/src/core/procutils.h index a56297a..c1e14c4 100644 --- a/src/core/procutils.h +++ b/src/core/procutils.h @@ -41,6 +41,8 @@ #define PROCUTILS_H #include <QString> +#include <QList> +#include <QObject> QT_FORWARD_DECLARE_CLASS(QLocalSocket) @@ -48,6 +50,52 @@ QT_FORWARD_DECLARE_CLASS(QLocalSocket) QT_BEGIN_NAMESPACE_PROCESSMANAGER +struct ProcessPrivateData; + +class Q_ADDON_PROCESSMANAGER_EXPORT ExecutingProcessInfo : public QObject +{ + Q_OBJECT + Q_PROPERTY(pid_t pid READ pid CONSTANT) + Q_PROPERTY(pid_t ppid READ ppid CONSTANT) + Q_PROPERTY(pid_t pgrp READ pgrp CONSTANT) + Q_PROPERTY(pid_t sid READ sid CONSTANT) + Q_PROPERTY(uid_t uid READ uid CONSTANT) + Q_PROPERTY(uid_t euid READ euid CONSTANT) + Q_PROPERTY(uid_t suid READ suid CONSTANT) + Q_PROPERTY(gid_t gid READ gid CONSTANT) + Q_PROPERTY(gid_t egid READ egid CONSTANT) + Q_PROPERTY(gid_t sgid READ sgid CONSTANT) + Q_PROPERTY(QList<gid_t> groups READ groups CONSTANT) + Q_PROPERTY(int priority READ priority CONSTANT) + Q_PROPERTY(int nice READ nice CONSTANT) + Q_PROPERTY(QString name READ name CONSTANT) + +public: + ExecutingProcessInfo(pid_t pid); + + bool exists() const; + pid_t pid() const; + pid_t ppid() const; + pid_t pgrp() const; + pid_t sid() const; + uid_t uid() const; + uid_t euid() const; + uid_t suid() const; + gid_t gid() const; + gid_t egid() const; + gid_t sgid() const; + int priority() const; + int nice() const; + + QList<gid_t> groups() const { return m_groups; } + QString name() const { return m_name; } + +private: + struct ProcessPrivateData *m_data; + QList<gid_t> m_groups; + QString m_name; +}; + class Q_ADDON_PROCESSMANAGER_EXPORT ProcUtils { ProcUtils(); |