summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/Proc.cpp')
-rw-r--r--daemon/Proc.cpp179
1 files changed, 179 insertions, 0 deletions
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 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Proc.h"
10
11#include <dirent.h>
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "Buffer.h"
18#include "DynBuf.h"
19#include "Logging.h"
20
21struct ProcStat {
22 // From linux-dev/include/linux/sched.h
23#define TASK_COMM_LEN 16
24 // TASK_COMM_LEN may grow, so be ready for it to get larger
25 char comm[2*TASK_COMM_LEN];
26 long numThreads;
27};
28
29static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
30 if (!b->read(pathname)) {
31 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
32 // This is not a fatal error - the thread just doesn't exist any more
33 return true;
34 }
35
36 char *comm = strchr(b->getBuf(), '(');
37 if (comm == NULL) {
38 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
39 return false;
40 }
41 ++comm;
42 char *const str = strrchr(comm, ')');
43 if (str == NULL) {
44 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47 *str = '\0';
48 strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
49 ps->comm[sizeof(ps->comm) - 1] = '\0';
50
51 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);
52 if (count != 1) {
53 logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
54 return false;
55 }
56
57 return true;
58}
59
60static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) {
61 bool result = false;
62
63 if (!b->printf("/proc/%i/task", pid)) {
64 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
65 return result;
66 }
67 DIR *task = opendir(b->getBuf());
68 if (task == NULL) {
69 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
70 return result;
71 }
72
73 struct dirent *dirent;
74 while ((dirent = readdir(task)) != NULL) {
75 char *endptr;
76 const int tid = strtol(dirent->d_name, &endptr, 10);
77 if (*endptr != '\0') {
78 // Ignore task items that are not integers like ., etc...
79 continue;
80 }
81
82 if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
83 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
84 goto fail;
85 }
86 ProcStat ps;
87 if (!readProcStat(&ps, printb->getBuf(), b)) {
88 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
89 goto fail;
90 }
91
92 buffer->comm(pid, tid, image, ps.comm);
93 }
94
95 result = true;
96
97 fail:
98 closedir(task);
99
100 return result;
101}
102
103bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
104 bool result = false;
105
106 DIR *proc = opendir("/proc");
107 if (proc == NULL) {
108 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
109 return result;
110 }
111
112 struct dirent *dirent;
113 while ((dirent = readdir(proc)) != NULL) {
114 char *endptr;
115 const int pid = strtol(dirent->d_name, &endptr, 10);
116 if (*endptr != '\0') {
117 // Ignore proc items that are not integers like ., cpuinfo, etc...
118 continue;
119 }
120
121 if (!printb->printf("/proc/%i/stat", pid)) {
122 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
123 goto fail;
124 }
125 ProcStat ps;
126 if (!readProcStat(&ps, printb->getBuf(), b1)) {
127 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
128 goto fail;
129 }
130
131 if (!printb->printf("/proc/%i/exe", pid)) {
132 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
133 goto fail;
134 }
135 const int err = b1->readlink(printb->getBuf());
136 const char *image;
137 if (err == 0) {
138 image = strrchr(b1->getBuf(), '/');
139 if (image == NULL) {
140 image = b1->getBuf();
141 } else {
142 ++image;
143 }
144 } else if (err == -ENOENT) {
145 // readlink /proc/[pid]/exe returns ENOENT for kernel threads
146 image = "\0";
147 } else {
148 logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
149 goto fail;
150 }
151
152 if (!printb->printf("/proc/%i/maps", pid)) {
153 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
154 goto fail;
155 }
156 if (!b2->read(printb->getBuf())) {
157 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
158 // This is not a fatal error - the process just doesn't exist any more
159 continue;
160 }
161
162 buffer->maps(pid, pid, b2->getBuf());
163 if (ps.numThreads <= 1) {
164 buffer->comm(pid, pid, image, ps.comm);
165 } else {
166 if (!readProcTask(buffer, pid, image, printb, b3)) {
167 logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
168 goto fail;
169 }
170 }
171 }
172
173 result = true;
174
175 fail:
176 closedir(proc);
177
178 return result;
179}