From 020278c1a682ea75ddb63fe4e0d373116935199f Mon Sep 17 00:00:00 2001 From: Drew Richardson Date: Mon, 7 Apr 2014 12:00:00 -0700 Subject: gator: Version 5.18 Signed-off-by: Drew Richardson --- daemon/Proc.cpp | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 daemon/Proc.cpp (limited to 'daemon/Proc.cpp') diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp new file mode 100644 index 0000000..e0b9e22 --- /dev/null +++ b/daemon/Proc.cpp @@ -0,0 +1,179 @@ +/** + * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "Proc.h" + +#include +#include +#include +#include +#include + +#include "Buffer.h" +#include "DynBuf.h" +#include "Logging.h" + +struct ProcStat { + // From linux-dev/include/linux/sched.h +#define TASK_COMM_LEN 16 + // TASK_COMM_LEN may grow, so be ready for it to get larger + char comm[2*TASK_COMM_LEN]; + long numThreads; +}; + +static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) { + if (!b->read(pathname)) { + logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__); + // This is not a fatal error - the thread just doesn't exist any more + return true; + } + + char *comm = strchr(b->getBuf(), '('); + if (comm == NULL) { + logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__); + return false; + } + ++comm; + char *const str = strrchr(comm, ')'); + if (str == NULL) { + logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__); + return false; + } + *str = '\0'; + strncpy(ps->comm, comm, sizeof(ps->comm) - 1); + ps->comm[sizeof(ps->comm) - 1] = '\0'; + + const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads); + if (count != 1) { + logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__); + return false; + } + + return true; +} + +static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) { + bool result = false; + + if (!b->printf("/proc/%i/task", pid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + return result; + } + DIR *task = opendir(b->getBuf()); + if (task == NULL) { + logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); + return result; + } + + struct dirent *dirent; + while ((dirent = readdir(task)) != NULL) { + char *endptr; + const int tid = strtol(dirent->d_name, &endptr, 10); + if (*endptr != '\0') { + // Ignore task items that are not integers like ., etc... + continue; + } + + if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + ProcStat ps; + if (!readProcStat(&ps, printb->getBuf(), b)) { + logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + + buffer->comm(pid, tid, image, ps.comm); + } + + result = true; + + fail: + closedir(task); + + return result; +} + +bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) { + bool result = false; + + DIR *proc = opendir("/proc"); + if (proc == NULL) { + logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); + return result; + } + + struct dirent *dirent; + while ((dirent = readdir(proc)) != NULL) { + char *endptr; + const int pid = strtol(dirent->d_name, &endptr, 10); + if (*endptr != '\0') { + // Ignore proc items that are not integers like ., cpuinfo, etc... + continue; + } + + if (!printb->printf("/proc/%i/stat", pid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + ProcStat ps; + if (!readProcStat(&ps, printb->getBuf(), b1)) { + logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + + if (!printb->printf("/proc/%i/exe", pid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + const int err = b1->readlink(printb->getBuf()); + const char *image; + if (err == 0) { + image = strrchr(b1->getBuf(), '/'); + if (image == NULL) { + image = b1->getBuf(); + } else { + ++image; + } + } else if (err == -ENOENT) { + // readlink /proc/[pid]/exe returns ENOENT for kernel threads + image = "\0"; + } else { + logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + + if (!printb->printf("/proc/%i/maps", pid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + if (!b2->read(printb->getBuf())) { + logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__); + // This is not a fatal error - the process just doesn't exist any more + continue; + } + + buffer->maps(pid, pid, b2->getBuf()); + if (ps.numThreads <= 1) { + buffer->comm(pid, pid, image, ps.comm); + } else { + if (!readProcTask(buffer, pid, image, printb, b3)) { + logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + } + } + + result = true; + + fail: + closedir(proc); + + return result; +} -- cgit v1.2.3