line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#ifndef _GNU_SOURCE |
2
|
|
|
|
|
|
|
#define _GNU_SOURCE /* for canonicalize_file_name */ |
3
|
|
|
|
|
|
|
#endif |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#include /* is_digit */ |
6
|
|
|
|
|
|
|
#include /* opendir, readdir_r */ |
7
|
|
|
|
|
|
|
#include |
8
|
|
|
|
|
|
|
#include /* BOOL */ |
9
|
|
|
|
|
|
|
#include /* *scanf family */ |
10
|
|
|
|
|
|
|
#include /* malloc family */ |
11
|
|
|
|
|
|
|
#include /* strchr */ |
12
|
|
|
|
|
|
|
#include /* time_t */ |
13
|
|
|
|
|
|
|
#include |
14
|
|
|
|
|
|
|
#include |
15
|
|
|
|
|
|
|
#include |
16
|
|
|
|
|
|
|
#include /* statfs */ |
17
|
|
|
|
|
|
|
/* glibc only goodness */ |
18
|
|
|
|
|
|
|
#include /* glibc's handy obstacks */ |
19
|
|
|
|
|
|
|
/* pthreads */ |
20
|
|
|
|
|
|
|
#include /* pthread_once */ |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#define obstack_chunk_alloc malloc |
23
|
|
|
|
|
|
|
#define obstack_chunk_free free |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#include "os/Linux.h" |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
/* NOTE: Before this was actually milliseconds even though it said microseconds, now it is correct. */ |
28
|
|
|
|
|
|
|
#define JIFFIES_TO_MICROSECONDS(x) (((x) * 1e6) / system_hertz) |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
/* some static values that won't change, */ |
31
|
|
|
|
|
|
|
static pthread_once_t globals_init = PTHREAD_ONCE_INIT; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
static long long boot_time; |
34
|
|
|
|
|
|
|
static unsigned page_size; |
35
|
|
|
|
|
|
|
static unsigned long long system_memory; |
36
|
|
|
|
|
|
|
static unsigned system_hertz; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
static bool init_failed = false; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
/* get_string() |
42
|
|
|
|
|
|
|
* |
43
|
|
|
|
|
|
|
* Access strings in read only section |
44
|
|
|
|
|
|
|
* |
45
|
|
|
|
|
|
|
* @param elem String we want to retrive (look at enum strings) |
46
|
|
|
|
|
|
|
* @return Address of string |
47
|
|
|
|
|
|
|
*/ |
48
|
106
|
|
|
|
|
|
inline static const char *get_string(int elem) |
49
|
|
|
|
|
|
|
{ |
50
|
106
|
|
|
|
|
|
return strings + strings_index[elem]; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
/* init_static_vars() |
54
|
|
|
|
|
|
|
* |
55
|
|
|
|
|
|
|
* Called by pthread_once to initialize global variables (system settings that don't change) |
56
|
|
|
|
|
|
|
*/ |
57
|
3
|
|
|
|
|
|
static void init_static_vars() |
58
|
|
|
|
|
|
|
{ |
59
|
|
|
|
|
|
|
struct obstack mem_pool; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
char *file_text, *file_off; |
62
|
|
|
|
|
|
|
off_t file_len; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
unsigned long long total_memory; |
65
|
|
|
|
|
|
|
|
66
|
3
|
|
|
|
|
|
boot_time = -1; |
67
|
3
|
|
|
|
|
|
system_memory = -1; |
68
|
|
|
|
|
|
|
|
69
|
3
|
|
|
|
|
|
page_size = getpagesize(); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
/* initilize our mem stack, tempoary memory */ |
72
|
3
|
|
|
|
|
|
obstack_init(&mem_pool); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
/* find hertz size, I'm hoping this is gotten from elf note AT_CLKTCK */ |
75
|
3
|
|
|
|
|
|
system_hertz = sysconf(_SC_CLK_TCK); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
/* find boot time */ |
78
|
|
|
|
|
|
|
/* read /proc/stat in */ |
79
|
3
|
50
|
|
|
|
|
if((file_text = read_file("stat", NULL, &file_len, &mem_pool)) == NULL) { |
80
|
0
|
|
|
|
|
|
goto fail; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
/* look for the line that starts with btime |
84
|
|
|
|
|
|
|
* NOTE: incrementing file_off after strchr is legal because file_text will |
85
|
|
|
|
|
|
|
* be null terminated, so worst case after '\n' there will be '\0' and |
86
|
|
|
|
|
|
|
* strncmp will fail or sscanf won't return 1 |
87
|
|
|
|
|
|
|
* Only increment on the first line */ |
88
|
60
|
50
|
|
|
|
|
for(file_off = file_text; file_off; file_off = strchr(file_off, '\n')) { |
89
|
60
|
100
|
|
|
|
|
if(file_off != file_text) { |
90
|
57
|
|
|
|
|
|
file_off++; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
60
|
100
|
|
|
|
|
if(strncmp(file_off, "btime", 5) == 0) { |
94
|
3
|
50
|
|
|
|
|
if(sscanf(file_off, "btime %lld", &boot_time) == 1) { |
95
|
3
|
|
|
|
|
|
break; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
3
|
50
|
|
|
|
|
obstack_free(&mem_pool, file_text); |
|
|
50
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
/* did we scrape the number of pages successfuly? */ |
103
|
3
|
50
|
|
|
|
|
if(boot_time == -1) { |
104
|
0
|
|
|
|
|
|
goto fail; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
/* find total number of system pages */ |
108
|
|
|
|
|
|
|
/* read /proc/meminfo */ |
109
|
3
|
50
|
|
|
|
|
if((file_text = read_file("meminfo", NULL, &file_len, &mem_pool)) == NULL) { |
110
|
0
|
|
|
|
|
|
goto fail; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
/* look for the line that starts with: MemTotal */ |
114
|
3
|
50
|
|
|
|
|
for(file_off = file_text; file_off; file_off = strchr(file_off, '\n')) { |
115
|
3
|
50
|
|
|
|
|
if(file_off != file_text) { |
116
|
0
|
|
|
|
|
|
file_off++; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
3
|
50
|
|
|
|
|
if(strncmp(file_off, "MemTotal:", 9) == 0) { |
120
|
3
|
50
|
|
|
|
|
if(sscanf(file_off, "MemTotal: %llu", &system_memory) == 1) { |
121
|
3
|
|
|
|
|
|
system_memory *= 1024; /* convert to bytes */ |
122
|
3
|
|
|
|
|
|
break; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
3
|
50
|
|
|
|
|
obstack_free(&mem_pool, file_text); |
|
|
50
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
/* did we scrape the number of pages successfuly? */ |
130
|
3
|
50
|
|
|
|
|
if(total_memory == -1) { |
131
|
0
|
|
|
|
|
|
goto fail; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
/* initialize system hertz value */ |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
/* cleanup */ |
137
|
3
|
50
|
|
|
|
|
obstack_free(&mem_pool, NULL); |
|
|
0
|
|
|
|
|
|
138
|
3
|
|
|
|
|
|
return; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
/* mark failure and cleanup allocated resources */ |
141
|
|
|
|
|
|
|
fail: |
142
|
0
|
0
|
|
|
|
|
obstack_free(&mem_pool, NULL); |
|
|
0
|
|
|
|
|
|
143
|
0
|
|
|
|
|
|
init_failed = true; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
/* OS_initialize() |
147
|
|
|
|
|
|
|
* |
148
|
|
|
|
|
|
|
* Called by XS parts whenever Proc::ProcessTable::new is called |
149
|
|
|
|
|
|
|
* |
150
|
|
|
|
|
|
|
* NOTE: There's a const char* -> char* conversion that's evil, but can't fix |
151
|
|
|
|
|
|
|
* this without breaking the Proc::ProcessTable XS API. |
152
|
|
|
|
|
|
|
*/ |
153
|
3
|
|
|
|
|
|
char *OS_initialize() |
154
|
|
|
|
|
|
|
{ |
155
|
|
|
|
|
|
|
struct statfs sfs; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
/* did we already try to initilize before and fail, if pthrad_once only |
158
|
|
|
|
|
|
|
* let us flag a failure from the init function; behavor of longjmp is |
159
|
|
|
|
|
|
|
* undefined, so that avaue is out out of the question */ |
160
|
3
|
50
|
|
|
|
|
if(init_failed) { |
161
|
0
|
|
|
|
|
|
return (char *)get_string(STR_ERR_INIT); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
/* check if /proc is mounted, let this go before initializing globals (below), |
165
|
|
|
|
|
|
|
* since the missing /proc message might me helpful */ |
166
|
3
|
50
|
|
|
|
|
if(statfs("/proc", &sfs) == -1) { |
167
|
0
|
|
|
|
|
|
return (char *)get_string(STR_ERR_PROC_STATFS); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
/* one time initialization of some values that won't change */ |
171
|
3
|
|
|
|
|
|
pthread_once(&globals_init, init_static_vars); |
172
|
|
|
|
|
|
|
|
173
|
3
|
|
|
|
|
|
return NULL; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
583
|
|
|
|
|
|
inline static void field_enable(char *format_str, enum field field) |
177
|
|
|
|
|
|
|
{ |
178
|
583
|
|
|
|
|
|
format_str[field] = tolower(format_str[field]); |
179
|
583
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
212
|
|
|
|
|
|
inline static void field_enable_range(char *format_str, enum field field1, |
182
|
|
|
|
|
|
|
enum field field2) |
183
|
|
|
|
|
|
|
{ |
184
|
|
|
|
|
|
|
int i; |
185
|
|
|
|
|
|
|
|
186
|
1696
|
100
|
|
|
|
|
for(i = field1; i <= field2; i++) { |
187
|
1484
|
|
|
|
|
|
format_str[i] = tolower(format_str[i]); |
188
|
|
|
|
|
|
|
} |
189
|
212
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
/* proc_pid_file() |
192
|
|
|
|
|
|
|
* |
193
|
|
|
|
|
|
|
* Build a path to the pid directory in proc '/proc/${pid}' with an optional |
194
|
|
|
|
|
|
|
* relative path at the end. Put the resultant path on top of the obstack. |
195
|
|
|
|
|
|
|
* |
196
|
|
|
|
|
|
|
* @return Address of the create path string. |
197
|
|
|
|
|
|
|
*/ |
198
|
430
|
|
|
|
|
|
inline static char *proc_pid_file(const char *pid, const char *file, |
199
|
|
|
|
|
|
|
struct obstack *mem_pool) |
200
|
|
|
|
|
|
|
{ |
201
|
|
|
|
|
|
|
/* path to dir */ |
202
|
430
|
|
|
|
|
|
obstack_printf(mem_pool, "/proc/%s", pid); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
/* additional path (not just the dir) */ |
205
|
430
|
100
|
|
|
|
|
if(file) { |
206
|
371
|
|
|
|
|
|
obstack_printf(mem_pool, "/%s", file); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
430
|
50
|
|
|
|
|
obstack_1grow(mem_pool, '\0'); |
210
|
|
|
|
|
|
|
|
211
|
430
|
50
|
|
|
|
|
return (char *)obstack_finish(mem_pool); |
|
|
50
|
|
|
|
|
|
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
/* read_file() |
215
|
|
|
|
|
|
|
* |
216
|
|
|
|
|
|
|
* Reads the contents of a file using an obstack for memory. It can read files like |
217
|
|
|
|
|
|
|
* /proc/stat or /proc/${pid}/stat. |
218
|
|
|
|
|
|
|
* |
219
|
|
|
|
|
|
|
* @param path String representing the part following /proc (usualy this is |
220
|
|
|
|
|
|
|
* the process pid number) |
221
|
|
|
|
|
|
|
* @param extra_path Path to the file to read in (relative to /proc/${path}/) |
222
|
|
|
|
|
|
|
* @param len Pointer to the value where the length will be saved |
223
|
|
|
|
|
|
|
* |
224
|
|
|
|
|
|
|
* @return Pointer to a null terminate string allocated on the obstack, or |
225
|
|
|
|
|
|
|
* NULL when it fails (doesn't clean up the obstack). |
226
|
|
|
|
|
|
|
*/ |
227
|
271
|
|
|
|
|
|
static char *read_file(const char *path, const char *extra_path, |
228
|
|
|
|
|
|
|
off_t *len, struct obstack *mem_pool) |
229
|
|
|
|
|
|
|
{ |
230
|
271
|
|
|
|
|
|
int fd, result = -1; |
231
|
|
|
|
|
|
|
char *text, *file, *start; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
/* build the filename in our tempoary storage */ |
234
|
271
|
|
|
|
|
|
file = proc_pid_file(path, extra_path, mem_pool); |
235
|
|
|
|
|
|
|
|
236
|
271
|
|
|
|
|
|
fd = open(file, O_RDONLY); |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
/* free tmp memory we allocated for the file contents, this way we are not |
239
|
|
|
|
|
|
|
* poluting the obstack and the only thing left on it is the file */ |
240
|
271
|
50
|
|
|
|
|
obstack_free(mem_pool, file); |
|
|
50
|
|
|
|
|
|
241
|
|
|
|
|
|
|
|
242
|
271
|
50
|
|
|
|
|
if(fd == -1) { |
243
|
0
|
|
|
|
|
|
return NULL; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
/* read file into our buffer */ |
247
|
883
|
100
|
|
|
|
|
for(*len = 0; result; *len += result) { |
248
|
612
|
100
|
|
|
|
|
obstack_blank(mem_pool, 1024); |
249
|
612
|
|
|
|
|
|
start = obstack_base(mem_pool) + *len; |
250
|
|
|
|
|
|
|
|
251
|
612
|
50
|
|
|
|
|
if((result = read(fd, start, 1024)) == -1) { |
252
|
0
|
0
|
|
|
|
|
obstack_free(mem_pool, obstack_finish(mem_pool)); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
253
|
0
|
|
|
|
|
|
close(fd); |
254
|
0
|
|
|
|
|
|
return NULL; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
271
|
|
|
|
|
|
start = obstack_base(mem_pool) + *len; |
259
|
271
|
|
|
|
|
|
*start = '\0'; |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
/* finalize our text buffer */ |
262
|
271
|
50
|
|
|
|
|
text = obstack_finish(mem_pool); |
|
|
50
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
/* not bothering checking return value, because it's possible that the |
265
|
|
|
|
|
|
|
* process went away */ |
266
|
271
|
|
|
|
|
|
close(fd); |
267
|
|
|
|
|
|
|
|
268
|
271
|
|
|
|
|
|
return text; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
/* get_user_info() |
272
|
|
|
|
|
|
|
* |
273
|
|
|
|
|
|
|
* Find the user/group id of the process |
274
|
|
|
|
|
|
|
* |
275
|
|
|
|
|
|
|
* @param pid String representing the pid |
276
|
|
|
|
|
|
|
* @param prs Data structure where to put the scraped values |
277
|
|
|
|
|
|
|
* @param mem_pool Obstack to use for temory storage |
278
|
|
|
|
|
|
|
*/ |
279
|
53
|
|
|
|
|
|
static void get_user_info(char *pid, char *format_str, struct procstat *prs, |
280
|
|
|
|
|
|
|
struct obstack *mem_pool) |
281
|
|
|
|
|
|
|
{ |
282
|
|
|
|
|
|
|
char * path_pid; |
283
|
|
|
|
|
|
|
struct stat stat_pid; |
284
|
|
|
|
|
|
|
int result; |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
/* (temp) /proc/${pid} */ |
287
|
53
|
|
|
|
|
|
path_pid = proc_pid_file(pid, NULL, mem_pool); |
288
|
|
|
|
|
|
|
|
289
|
53
|
|
|
|
|
|
result = stat(path_pid, &stat_pid); |
290
|
|
|
|
|
|
|
|
291
|
53
|
50
|
|
|
|
|
obstack_free(mem_pool, path_pid); |
|
|
50
|
|
|
|
|
|
292
|
|
|
|
|
|
|
|
293
|
53
|
50
|
|
|
|
|
if(result == -1) { |
294
|
0
|
|
|
|
|
|
return; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
53
|
|
|
|
|
|
prs->uid = stat_pid.st_uid; |
298
|
53
|
|
|
|
|
|
prs->gid = stat_pid.st_gid; |
299
|
|
|
|
|
|
|
|
300
|
53
|
|
|
|
|
|
field_enable(format_str, F_UID); |
301
|
53
|
|
|
|
|
|
field_enable(format_str, F_GID); |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
/* get_proc_stat() |
305
|
|
|
|
|
|
|
* |
306
|
|
|
|
|
|
|
* Reads a processes stat file in the proc filesystem '/proc/${pid}/stat' and |
307
|
|
|
|
|
|
|
* fills the procstat structure with the values. |
308
|
|
|
|
|
|
|
* |
309
|
|
|
|
|
|
|
* @param pid String representing the pid |
310
|
|
|
|
|
|
|
* @param prs Data structure where to put the scraped values |
311
|
|
|
|
|
|
|
* @param mem_pool Obstack to use for temory storage |
312
|
|
|
|
|
|
|
*/ |
313
|
53
|
|
|
|
|
|
static bool get_proc_stat(char *pid, char *format_str, struct procstat *prs, |
314
|
|
|
|
|
|
|
struct obstack *mem_pool) |
315
|
|
|
|
|
|
|
{ |
316
|
|
|
|
|
|
|
char *stat_text, *stat_cont, *close_paren, *open_paren; |
317
|
|
|
|
|
|
|
int result; |
318
|
|
|
|
|
|
|
off_t stat_len; |
319
|
|
|
|
|
|
|
long dummy_l; |
320
|
|
|
|
|
|
|
int dummy_i; |
321
|
|
|
|
|
|
|
|
322
|
53
|
|
|
|
|
|
bool read_ok = true; |
323
|
|
|
|
|
|
|
|
324
|
53
|
50
|
|
|
|
|
if((stat_text = read_file(pid, "stat", &stat_len, mem_pool)) == NULL) { |
325
|
0
|
|
|
|
|
|
return false; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
53
|
50
|
|
|
|
|
if(sscanf(stat_text, "%d (", &prs->pid) != 1) { |
329
|
0
|
|
|
|
|
|
goto done; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
/* replace the first ')' with a '\0', the contents look like this: |
333
|
|
|
|
|
|
|
* pid (program_name) state ... |
334
|
|
|
|
|
|
|
* if we don't find ')' then it's incorrectly formated */ |
335
|
53
|
50
|
|
|
|
|
if((close_paren = strrchr(stat_text, ')')) == NULL) { |
336
|
0
|
|
|
|
|
|
read_ok = false; |
337
|
0
|
|
|
|
|
|
goto done; |
338
|
|
|
|
|
|
|
} |
339
|
53
|
|
|
|
|
|
*close_paren = '\0'; |
340
|
|
|
|
|
|
|
|
341
|
53
|
50
|
|
|
|
|
if((open_paren = strchr(stat_text, '(')) == NULL) { |
342
|
0
|
|
|
|
|
|
read_ok = false; |
343
|
0
|
|
|
|
|
|
goto done; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
53
|
|
|
|
|
|
int comm_esize = sizeof(prs->comm) - 1; |
348
|
53
|
|
|
|
|
|
int comm_len = close_paren - open_paren - 1; |
349
|
|
|
|
|
|
|
|
350
|
53
|
50
|
|
|
|
|
if(comm_len > comm_esize) { |
351
|
0
|
|
|
|
|
|
comm_len = comm_esize; |
352
|
|
|
|
|
|
|
} |
353
|
53
|
50
|
|
|
|
|
if(comm_len > 0) { |
354
|
53
|
|
|
|
|
|
strncpy(prs->comm, open_paren + 1, comm_esize); |
355
|
53
|
|
|
|
|
|
prs->comm[comm_esize] = '\0'; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
/* address at which we pickup again, after the ')' |
360
|
|
|
|
|
|
|
* NOTE: we don't bother checking bounds since strchr didn't return NULL |
361
|
|
|
|
|
|
|
* thus the NULL terminator will be at least close_paren+1, which is ok */ |
362
|
53
|
|
|
|
|
|
stat_cont = close_paren + 1; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
/* scrape the remaining values */ |
365
|
53
|
|
|
|
|
|
result = sscanf(stat_cont, |
366
|
|
|
|
|
|
|
" %c" /* state */ |
367
|
|
|
|
|
|
|
" %d" /* ppid */ |
368
|
|
|
|
|
|
|
" %d" /* pgrp */ |
369
|
|
|
|
|
|
|
" %d" /* sid */ |
370
|
|
|
|
|
|
|
" %d" /* tty */ |
371
|
|
|
|
|
|
|
" %d" /* tty_pgid (dummy) */ |
372
|
|
|
|
|
|
|
" %u" /* flags */ |
373
|
|
|
|
|
|
|
" %lu" /* minflt */ |
374
|
|
|
|
|
|
|
" %lu" /* cminflt */ |
375
|
|
|
|
|
|
|
" %lu" /* majflt */ |
376
|
|
|
|
|
|
|
" %lu" /* cmajflt */ |
377
|
|
|
|
|
|
|
" %llu" /* utime */ |
378
|
|
|
|
|
|
|
" %llu" /* stime */ |
379
|
|
|
|
|
|
|
" %llu" /* cutime */ |
380
|
|
|
|
|
|
|
" %lld" /* cstime */ |
381
|
|
|
|
|
|
|
" %ld" /* priority */ |
382
|
|
|
|
|
|
|
" %ld" /* nice (dummy) */ |
383
|
|
|
|
|
|
|
" %ld" /* num_threads (dummy) */ |
384
|
|
|
|
|
|
|
" %d" /* itrealvalue (dummy) */ |
385
|
|
|
|
|
|
|
" %llu" /* start_time */ |
386
|
|
|
|
|
|
|
" %lu" /* vsize */ |
387
|
|
|
|
|
|
|
" %ld" /* rss */ |
388
|
|
|
|
|
|
|
" %ld" /* rsslim */ |
389
|
|
|
|
|
|
|
" %lu" /* start_code (dummy) */ |
390
|
|
|
|
|
|
|
" %lu" /* end_code (dummy) */ |
391
|
|
|
|
|
|
|
" %lu" /* start_stack (dummy) */ |
392
|
|
|
|
|
|
|
" %lu" /* esp (dummy) */ |
393
|
|
|
|
|
|
|
" %lu" /* eip (dummy) */ |
394
|
|
|
|
|
|
|
" %lu" /* pending (dummy) */ |
395
|
|
|
|
|
|
|
" %lu" /* blocked (dummy) */ |
396
|
|
|
|
|
|
|
" %lu" /* sigign (dummy) */ |
397
|
|
|
|
|
|
|
" %lu" /* sigcatch (dummy) */ |
398
|
|
|
|
|
|
|
" %lu" /* wchan (obsolete) */ |
399
|
|
|
|
|
|
|
, |
400
|
|
|
|
|
|
|
&prs->state_c, /* %c */ |
401
|
|
|
|
|
|
|
&prs->ppid, &prs->pgrp, /* %d %d */ |
402
|
|
|
|
|
|
|
&prs->sid, /* %d */ |
403
|
|
|
|
|
|
|
&prs->tty, &dummy_i, /* tty, tty_pgid */ |
404
|
|
|
|
|
|
|
&prs->flags, /* %u */ |
405
|
|
|
|
|
|
|
&prs->minflt, &prs->cminflt, |
406
|
|
|
|
|
|
|
&prs->majflt, &prs->cmajflt, /* %lu %lu %lu %lu */ |
407
|
|
|
|
|
|
|
&prs->utime, &prs->stime, |
408
|
|
|
|
|
|
|
&prs->cutime, &prs->cstime, |
409
|
|
|
|
|
|
|
&prs->priority, |
410
|
|
|
|
|
|
|
&dummy_l, /* nice */ |
411
|
|
|
|
|
|
|
&dummy_l, /* num threads */ |
412
|
|
|
|
|
|
|
&dummy_i, /* timeout obsolete */ |
413
|
|
|
|
|
|
|
&prs->start_time, |
414
|
|
|
|
|
|
|
&prs->vsize, &prs->rss, |
415
|
|
|
|
|
|
|
&dummy_l, |
416
|
|
|
|
|
|
|
&dummy_l, &dummy_l, |
417
|
|
|
|
|
|
|
&dummy_l, |
418
|
|
|
|
|
|
|
&dummy_l, &dummy_l, |
419
|
|
|
|
|
|
|
&dummy_l, &dummy_l, &dummy_l, &dummy_l, |
420
|
|
|
|
|
|
|
&prs->wchan); |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
/* 33 items in scanf's list... It's all or nothing baby */ |
423
|
53
|
50
|
|
|
|
|
if(result != 33) { |
424
|
0
|
|
|
|
|
|
read_ok = false; |
425
|
0
|
|
|
|
|
|
goto done; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
/* enable fields; F_STATE is not the range */ |
429
|
53
|
|
|
|
|
|
field_enable_range(format_str, F_PID, F_WCHAN); |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
done: |
432
|
53
|
50
|
|
|
|
|
obstack_free(mem_pool, stat_text); |
|
|
50
|
|
|
|
|
|
433
|
53
|
|
|
|
|
|
return read_ok; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
106
|
|
|
|
|
|
static void eval_link(char *pid, char *link_rel, enum field field, char **ptr, |
437
|
|
|
|
|
|
|
char *format_str, struct obstack *mem_pool) |
438
|
|
|
|
|
|
|
{ |
439
|
|
|
|
|
|
|
char *link_file, *link; |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
/* path to the link file like. /proc/{pid}/{link_rel} */ |
442
|
106
|
|
|
|
|
|
link_file = proc_pid_file(pid, link_rel, mem_pool); |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
/* It's okay to use canonicalize_file_name instead of readlink on linux |
445
|
|
|
|
|
|
|
* for the cwd symlink, since on linux the links we care about will never |
446
|
|
|
|
|
|
|
* be relative links (cwd, exec) |
447
|
|
|
|
|
|
|
* Doing this because readlink works on static buffers */ |
448
|
|
|
|
|
|
|
/* canonicalize_file_name is no good for musl, use realpath instead */ |
449
|
106
|
|
|
|
|
|
link = realpath(link_file, NULL); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
/* we no longer need need the path to the link file */ |
452
|
106
|
50
|
|
|
|
|
obstack_free(mem_pool, link_file); |
|
|
50
|
|
|
|
|
|
453
|
|
|
|
|
|
|
|
454
|
106
|
50
|
|
|
|
|
if(link == NULL) { |
455
|
0
|
|
|
|
|
|
return; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
/* copy the path onto our obstack, set the value (somewhere in pts) |
459
|
|
|
|
|
|
|
* and free the results of canonicalize_file_name */ |
460
|
106
|
|
|
|
|
|
obstack_printf(mem_pool, "%s", link); |
461
|
106
|
50
|
|
|
|
|
obstack_1grow(mem_pool, '\0'); |
462
|
|
|
|
|
|
|
|
463
|
106
|
50
|
|
|
|
|
*ptr = (char *)obstack_finish(mem_pool); |
|
|
50
|
|
|
|
|
|
464
|
106
|
|
|
|
|
|
free(link); |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
/* enable whatever field we successfuly retrived */ |
467
|
106
|
|
|
|
|
|
field_enable(format_str, field); |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
53
|
|
|
|
|
|
static void get_proc_cmndline(char *pid, char *format_str, struct procstat *prs, |
471
|
|
|
|
|
|
|
struct obstack *mem_pool) |
472
|
|
|
|
|
|
|
{ |
473
|
|
|
|
|
|
|
char *cmndline_text, *cur; |
474
|
|
|
|
|
|
|
off_t cmndline_off; |
475
|
|
|
|
|
|
|
|
476
|
53
|
50
|
|
|
|
|
if((cmndline_text = read_file(pid, "cmdline", &cmndline_off, mem_pool)) == NULL) { |
477
|
0
|
|
|
|
|
|
return; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
/* replace all '\0' with spaces (except for the last one */ |
481
|
7483
|
100
|
|
|
|
|
for(cur = cmndline_text; cur < cmndline_text + cmndline_off - 1; cur++) { |
482
|
7430
|
100
|
|
|
|
|
if(*cur == '\0') { |
483
|
342
|
|
|
|
|
|
*cur = ' '; |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
53
|
|
|
|
|
|
prs->cmndline = cmndline_text; |
488
|
53
|
|
|
|
|
|
field_enable(format_str, F_CMNDLINE); |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
53
|
|
|
|
|
|
static void get_proc_cmdline(char *pid, char *format_str, struct procstat *prs, |
492
|
|
|
|
|
|
|
struct obstack *mem_pool) |
493
|
|
|
|
|
|
|
{ |
494
|
|
|
|
|
|
|
char *cmdline_text; |
495
|
|
|
|
|
|
|
off_t cmdline_off; |
496
|
|
|
|
|
|
|
|
497
|
53
|
50
|
|
|
|
|
if((cmdline_text = read_file(pid, "cmdline", &cmdline_off, mem_pool)) == NULL) { |
498
|
0
|
|
|
|
|
|
return; |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
53
|
|
|
|
|
|
prs->cmdline = cmdline_text; |
502
|
53
|
|
|
|
|
|
prs->cmdline_len = cmdline_off; |
503
|
53
|
|
|
|
|
|
field_enable(format_str, F_CMDLINE); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
53
|
|
|
|
|
|
static void get_proc_environ(char *pid, char *format_str, struct procstat *prs, |
507
|
|
|
|
|
|
|
struct obstack *mem_pool) |
508
|
|
|
|
|
|
|
{ |
509
|
|
|
|
|
|
|
char *environ_text; |
510
|
|
|
|
|
|
|
off_t environ_off; |
511
|
|
|
|
|
|
|
|
512
|
53
|
50
|
|
|
|
|
if((environ_text = read_file(pid, "environ", &environ_off, mem_pool)) == NULL) { |
513
|
0
|
|
|
|
|
|
return; |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
53
|
|
|
|
|
|
prs->environ = environ_text; |
517
|
53
|
|
|
|
|
|
prs->environ_len = environ_off; |
518
|
53
|
|
|
|
|
|
field_enable(format_str, F_ENVIRON); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
53
|
|
|
|
|
|
static void get_proc_status(char *pid, char *format_str, struct procstat *prs, |
522
|
|
|
|
|
|
|
struct obstack *mem_pool) |
523
|
|
|
|
|
|
|
{ |
524
|
|
|
|
|
|
|
char *status_text, *loc; |
525
|
|
|
|
|
|
|
off_t status_len; |
526
|
|
|
|
|
|
|
int dummy_i; |
527
|
|
|
|
|
|
|
|
528
|
53
|
50
|
|
|
|
|
if((status_text = read_file(pid, "status", &status_len, mem_pool)) == NULL) { |
529
|
0
|
|
|
|
|
|
return; |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
53
|
|
|
|
|
|
loc = status_text; |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
/* |
535
|
|
|
|
|
|
|
* get the euid, egid and so on out of /proc/$$/status |
536
|
|
|
|
|
|
|
* where the 2 lines in which we are interested in are: |
537
|
|
|
|
|
|
|
* [5] Uid: 500 500 500 500 |
538
|
|
|
|
|
|
|
* [6] Gid: 500 500 500 500 |
539
|
|
|
|
|
|
|
* added by scip |
540
|
|
|
|
|
|
|
*/ |
541
|
|
|
|
|
|
|
|
542
|
530
|
50
|
|
|
|
|
for(loc = status_text; loc; loc = strchr(loc, '\n')) { |
543
|
|
|
|
|
|
|
/* skip past the \n character */ |
544
|
530
|
100
|
|
|
|
|
if(loc != status_text) { |
545
|
477
|
|
|
|
|
|
loc++; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
530
|
100
|
|
|
|
|
if(strncmp(loc, "Uid:", 4) == 0) { |
549
|
53
|
|
|
|
|
|
sscanf(loc + 4, " %d %d %d %d", &dummy_i, &prs->euid, &prs->suid, &prs->fuid); |
550
|
53
|
|
|
|
|
|
field_enable_range(format_str, F_EUID, F_FUID); |
551
|
477
|
100
|
|
|
|
|
} else if(strncmp(loc, "Gid:", 4) == 0) { |
552
|
53
|
|
|
|
|
|
sscanf(loc + 4, " %d %d %d %d", &dummy_i, &prs->egid, &prs->sgid, &prs->fgid); |
553
|
53
|
|
|
|
|
|
field_enable_range(format_str, F_EGID, F_FGID); |
554
|
424
|
100
|
|
|
|
|
} else if(strncmp(loc, "TracerPid:", 10) == 0) { |
555
|
53
|
|
|
|
|
|
sscanf(loc + 10, " %d", &prs->tracer); |
556
|
53
|
|
|
|
|
|
field_enable(format_str, F_TRACER); |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
/* short circuit condition */ |
560
|
530
|
100
|
|
|
|
|
if(islower(format_str[F_EUID]) && islower(format_str[F_EGID]) && islower(format_str[F_TRACER])) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
561
|
53
|
|
|
|
|
|
goto done; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
done: |
566
|
53
|
50
|
|
|
|
|
obstack_free(mem_pool, status_text); |
|
|
50
|
|
|
|
|
|
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
/* fixup_stat_values() |
570
|
|
|
|
|
|
|
* |
571
|
|
|
|
|
|
|
* Correct, calculate, covert values to user expected values. |
572
|
|
|
|
|
|
|
* |
573
|
|
|
|
|
|
|
* @param format_str String containing field index types |
574
|
|
|
|
|
|
|
* @param prs Data structure to peform fixups on |
575
|
|
|
|
|
|
|
*/ |
576
|
53
|
|
|
|
|
|
static void fixup_stat_values(char *format_str, struct procstat *prs) |
577
|
|
|
|
|
|
|
{ |
578
|
|
|
|
|
|
|
/* set the state pointer to the right (const) string */ |
579
|
53
|
|
|
|
|
|
switch(prs->state_c) { |
580
|
|
|
|
|
|
|
case 'S': |
581
|
48
|
|
|
|
|
|
prs->state = get_string(SLEEP); |
582
|
48
|
|
|
|
|
|
break; |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
case 'W': |
585
|
0
|
|
|
|
|
|
prs->state = get_string(WAIT); /*Waking state. Could be mapped to WAKING, but would break backward compatibility */ |
586
|
0
|
|
|
|
|
|
break; |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
case 'R': |
589
|
5
|
|
|
|
|
|
prs->state = get_string(RUN); |
590
|
5
|
|
|
|
|
|
break; |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
case 'I': |
593
|
0
|
|
|
|
|
|
prs->state = get_string(IDLE); |
594
|
0
|
|
|
|
|
|
break; |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
case 'Z': |
597
|
0
|
|
|
|
|
|
prs->state = get_string(DEFUNCT); |
598
|
0
|
|
|
|
|
|
break; |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
case 'D': |
601
|
0
|
|
|
|
|
|
prs->state = get_string(UWAIT); |
602
|
0
|
|
|
|
|
|
break; |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
case 'T': |
605
|
|
|
|
|
|
|
case 'H': /* GNU Hurd HALTED state */ |
606
|
0
|
|
|
|
|
|
prs->state = get_string(STOP); |
607
|
0
|
|
|
|
|
|
break; |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
case 'x': |
610
|
0
|
|
|
|
|
|
prs->state = get_string(DEAD); |
611
|
0
|
|
|
|
|
|
break; |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
case 'X': |
614
|
0
|
|
|
|
|
|
prs->state = get_string(DEAD); |
615
|
0
|
|
|
|
|
|
break; |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
case 'K': |
618
|
0
|
|
|
|
|
|
prs->state = get_string(WAKEKILL); |
619
|
0
|
|
|
|
|
|
break; |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
case 't': |
622
|
0
|
|
|
|
|
|
prs->state = get_string(TRACINGSTOP); |
623
|
0
|
|
|
|
|
|
break; |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
case 'P': |
626
|
0
|
|
|
|
|
|
prs->state = get_string(PARKED); |
627
|
0
|
|
|
|
|
|
break; |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
/* unknown state, state is already set to NULL */ |
630
|
|
|
|
|
|
|
default: |
631
|
0
|
|
|
|
|
|
ppt_warn("Ran into unknown state (hex char: %x)", (int)prs->state_c); |
632
|
0
|
|
|
|
|
|
goto skip_state_format; |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
|
635
|
53
|
|
|
|
|
|
field_enable(format_str, F_STATE); |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
skip_state_format: |
638
|
|
|
|
|
|
|
|
639
|
53
|
|
|
|
|
|
prs->start_time = (prs->start_time / system_hertz) + boot_time; |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
/* fix time */ |
642
|
|
|
|
|
|
|
|
643
|
53
|
|
|
|
|
|
prs->stime = JIFFIES_TO_MICROSECONDS(prs->stime); |
644
|
53
|
|
|
|
|
|
prs->utime = JIFFIES_TO_MICROSECONDS(prs->utime); |
645
|
53
|
|
|
|
|
|
prs->cstime = JIFFIES_TO_MICROSECONDS(prs->cstime); |
646
|
53
|
|
|
|
|
|
prs->cutime = JIFFIES_TO_MICROSECONDS(prs->cutime); |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
/* derived time values */ |
649
|
53
|
|
|
|
|
|
prs->time = prs->utime + prs->stime; |
650
|
53
|
|
|
|
|
|
prs->ctime = prs->cutime + prs->cstime; |
651
|
|
|
|
|
|
|
|
652
|
53
|
|
|
|
|
|
field_enable_range(format_str, F_TIME, F_CTIME); |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
/* fix rss to be in bytes (returned from kernel in pages) */ |
655
|
53
|
|
|
|
|
|
prs->rss *= page_size; |
656
|
53
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
/* calc_prec() |
659
|
|
|
|
|
|
|
* |
660
|
|
|
|
|
|
|
* calculate the two cpu/memory precentage values |
661
|
|
|
|
|
|
|
*/ |
662
|
53
|
|
|
|
|
|
static void calc_prec(char *format_str, struct procstat *prs, struct obstack *mem_pool) |
663
|
|
|
|
|
|
|
{ |
664
|
|
|
|
|
|
|
int len; |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
/* calculate pctcpu - NOTE: This assumes the cpu time is in microsecond units! |
667
|
|
|
|
|
|
|
* multiplying by 1/1e6 puts all units back in seconds. Then multiply by 100.0f to get a percentage. |
668
|
|
|
|
|
|
|
*/ |
669
|
|
|
|
|
|
|
|
670
|
53
|
|
|
|
|
|
float pctcpu = (100.0f * (prs->utime + prs->stime) * 1 / 1e6) / (time(NULL) - prs->start_time); |
671
|
|
|
|
|
|
|
|
672
|
53
|
|
|
|
|
|
len = snprintf(prs->pctcpu, LENGTH_PCTCPU, "%6.2f", pctcpu); |
673
|
53
|
50
|
|
|
|
|
if(len >= LENGTH_PCTCPU) { |
674
|
0
|
|
|
|
|
|
ppt_warn("percent cpu truncated from %d, set LENGTH_PCTCPU to at least: %d)", len, len + 1); |
675
|
|
|
|
|
|
|
} |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
|
678
|
53
|
|
|
|
|
|
field_enable(format_str, F_PCTCPU); |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
/* calculate pctmem */ |
681
|
53
|
50
|
|
|
|
|
if(system_memory > 0) { |
682
|
53
|
|
|
|
|
|
sprintf(prs->pctmem, "%3.2f", (float)prs->rss / system_memory * 100.f); |
683
|
53
|
|
|
|
|
|
field_enable(format_str, F_PCTMEM); |
684
|
|
|
|
|
|
|
} |
685
|
53
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
/* is_pid() |
688
|
|
|
|
|
|
|
* |
689
|
|
|
|
|
|
|
* |
690
|
|
|
|
|
|
|
* @return Boolean value. |
691
|
|
|
|
|
|
|
*/ |
692
|
363
|
|
|
|
|
|
inline static bool is_pid(const char *str) |
693
|
|
|
|
|
|
|
{ |
694
|
502
|
100
|
|
|
|
|
for(; *str; str++) { |
695
|
449
|
100
|
|
|
|
|
if(!isdigit(*str)) { |
696
|
310
|
|
|
|
|
|
return false; |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
53
|
|
|
|
|
|
return true; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
0
|
|
|
|
|
|
inline static bool pid_exists(const char *str, struct obstack *mem_pool) |
704
|
|
|
|
|
|
|
{ |
705
|
0
|
|
|
|
|
|
char *pid_dir_path = NULL; |
706
|
|
|
|
|
|
|
int result; |
707
|
|
|
|
|
|
|
|
708
|
0
|
|
|
|
|
|
obstack_printf(mem_pool, "/proc/%s", str); |
709
|
0
|
0
|
|
|
|
|
obstack_1grow(mem_pool, '\0'); |
710
|
0
|
0
|
|
|
|
|
pid_dir_path = obstack_finish(mem_pool); |
|
|
0
|
|
|
|
|
|
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
/* directory exists? */ |
713
|
0
|
|
|
|
|
|
result = (access(pid_dir_path, F_OK) != -1); |
714
|
|
|
|
|
|
|
|
715
|
0
|
0
|
|
|
|
|
obstack_free(mem_pool, pid_dir_path); |
|
|
0
|
|
|
|
|
|
716
|
|
|
|
|
|
|
|
717
|
0
|
|
|
|
|
|
return result; |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
5
|
|
|
|
|
|
void OS_get_table() |
721
|
|
|
|
|
|
|
{ |
722
|
|
|
|
|
|
|
/* dir walker storage */ |
723
|
|
|
|
|
|
|
DIR * dir; |
724
|
|
|
|
|
|
|
struct dirent *dir_ent, *dir_result; |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
/* all our storage is going to be here */ |
727
|
|
|
|
|
|
|
struct obstack mem_pool; |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
/* container for scraped process values */ |
730
|
|
|
|
|
|
|
struct procstat *prs; |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
/* string containing our local copy of format_str, elements will be |
733
|
|
|
|
|
|
|
* lower cased if we are able to figure them out */ |
734
|
|
|
|
|
|
|
char *format_str; |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
/* initialize a small memory pool for this function */ |
737
|
5
|
|
|
|
|
|
obstack_init(&mem_pool); |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
/* put the dirent on the obstack, since it's rather large */ |
740
|
5
|
50
|
|
|
|
|
dir_ent = obstack_alloc(&mem_pool, sizeof(struct dirent)); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
741
|
|
|
|
|
|
|
|
742
|
5
|
50
|
|
|
|
|
if((dir = opendir("/proc")) == NULL) { |
743
|
0
|
|
|
|
|
|
return; |
744
|
|
|
|
|
|
|
} |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
/* Iterate through all the process entries (numeric) under /proc */ |
747
|
368
|
50
|
|
|
|
|
while(readdir_r(dir, dir_ent, &dir_result) == 0 && dir_result) { |
|
|
100
|
|
|
|
|
|
748
|
|
|
|
|
|
|
/* Only look at this file if it's a proc id; that is, all numbers */ |
749
|
363
|
100
|
|
|
|
|
if(!is_pid(dir_result->d_name)) { |
750
|
310
|
|
|
|
|
|
continue; |
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
/* allocate container for storing process values */ |
754
|
53
|
50
|
|
|
|
|
prs = obstack_alloc(&mem_pool, sizeof(struct procstat)); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
755
|
53
|
|
|
|
|
|
bzero(prs, sizeof(struct procstat)); |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
/* initialize the format string */ |
758
|
53
|
|
|
|
|
|
obstack_printf(&mem_pool, "%s", get_string(STR_DEFAULT_FORMAT)); |
759
|
53
|
50
|
|
|
|
|
obstack_1grow(&mem_pool, '\0'); |
760
|
53
|
50
|
|
|
|
|
format_str = (char *)obstack_finish(&mem_pool); |
|
|
50
|
|
|
|
|
|
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
/* get process' uid/guid */ |
763
|
53
|
|
|
|
|
|
get_user_info(dir_result->d_name, format_str, prs, &mem_pool); |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
/* scrape /proc/${pid}/stat */ |
766
|
53
|
50
|
|
|
|
|
if(get_proc_stat(dir_result->d_name, format_str, prs, &mem_pool) == false) { |
767
|
|
|
|
|
|
|
/* did the pid directory go away mid flight? */ |
768
|
0
|
0
|
|
|
|
|
if(pid_exists(dir_result->d_name, &mem_pool) == false) { |
769
|
0
|
|
|
|
|
|
continue; |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
/* correct values (times) found in /proc/${pid}/stat */ |
774
|
53
|
|
|
|
|
|
fixup_stat_values(format_str, prs); |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
/* get process' cmndline */ |
777
|
53
|
|
|
|
|
|
get_proc_cmndline(dir_result->d_name, format_str, prs, &mem_pool); |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
/* get process' cmdline */ |
780
|
53
|
|
|
|
|
|
get_proc_cmdline(dir_result->d_name, format_str, prs, &mem_pool); |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
/* get process' environ */ |
783
|
53
|
|
|
|
|
|
get_proc_environ(dir_result->d_name, format_str, prs, &mem_pool); |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
/* get process' cwd & exec values from the symblink */ |
786
|
53
|
|
|
|
|
|
eval_link(dir_result->d_name, "cwd", F_CWD, &prs->cwd, format_str, |
787
|
|
|
|
|
|
|
&mem_pool); |
788
|
53
|
|
|
|
|
|
eval_link(dir_result->d_name, "exe", F_EXEC, &prs->exec, format_str, |
789
|
|
|
|
|
|
|
&mem_pool); |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
/* scrape from /proc/{$pid}/status */ |
792
|
53
|
|
|
|
|
|
get_proc_status(dir_result->d_name, format_str, prs, &mem_pool); |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
/* calculate precent cpu & mem values */ |
795
|
53
|
|
|
|
|
|
calc_prec(format_str, prs, &mem_pool); |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
/* Go ahead and bless into a perl object */ |
798
|
|
|
|
|
|
|
/* Linux.h defines const char* const* Fiels, but we cast it away, as bless_into_proc only understands char** */ |
799
|
53
|
|
|
|
|
|
bless_into_proc(format_str, (char **)field_names, |
800
|
|
|
|
|
|
|
prs->uid, |
801
|
|
|
|
|
|
|
prs->gid, |
802
|
|
|
|
|
|
|
prs->pid, |
803
|
53
|
|
|
|
|
|
prs->comm, |
804
|
|
|
|
|
|
|
prs->ppid, |
805
|
|
|
|
|
|
|
prs->pgrp, |
806
|
|
|
|
|
|
|
prs->sid, |
807
|
|
|
|
|
|
|
prs->tty, |
808
|
|
|
|
|
|
|
prs->flags, |
809
|
|
|
|
|
|
|
prs->minflt, |
810
|
|
|
|
|
|
|
prs->cminflt, |
811
|
|
|
|
|
|
|
prs->majflt, |
812
|
|
|
|
|
|
|
prs->cmajflt, |
813
|
|
|
|
|
|
|
prs->utime, |
814
|
|
|
|
|
|
|
prs->stime, |
815
|
|
|
|
|
|
|
prs->cutime, |
816
|
|
|
|
|
|
|
prs->cstime, |
817
|
|
|
|
|
|
|
prs->priority, |
818
|
|
|
|
|
|
|
prs->start_time, |
819
|
|
|
|
|
|
|
prs->vsize, |
820
|
|
|
|
|
|
|
prs->rss, |
821
|
|
|
|
|
|
|
prs->wchan, |
822
|
|
|
|
|
|
|
prs->time, |
823
|
|
|
|
|
|
|
prs->ctime, |
824
|
|
|
|
|
|
|
prs->state, |
825
|
|
|
|
|
|
|
prs->euid, |
826
|
|
|
|
|
|
|
prs->suid, |
827
|
|
|
|
|
|
|
prs->fuid, |
828
|
|
|
|
|
|
|
prs->egid, |
829
|
|
|
|
|
|
|
prs->sgid, |
830
|
|
|
|
|
|
|
prs->fgid, |
831
|
53
|
|
|
|
|
|
prs->pctcpu, |
832
|
53
|
|
|
|
|
|
prs->pctmem, |
833
|
|
|
|
|
|
|
prs->cmndline, |
834
|
|
|
|
|
|
|
prs->exec, |
835
|
|
|
|
|
|
|
prs->cwd, |
836
|
|
|
|
|
|
|
prs->cmdline, |
837
|
|
|
|
|
|
|
prs->cmdline_len, |
838
|
|
|
|
|
|
|
prs->environ, |
839
|
|
|
|
|
|
|
prs->environ_len, |
840
|
|
|
|
|
|
|
prs->tracer |
841
|
|
|
|
|
|
|
); |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
/* we want a new prs, for the next itteration */ |
844
|
53
|
50
|
|
|
|
|
obstack_free(&mem_pool, prs); |
|
|
0
|
|
|
|
|
|
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
|
847
|
5
|
|
|
|
|
|
closedir(dir); |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
/* free all our tempoary memory */ |
850
|
5
|
50
|
|
|
|
|
obstack_free(&mem_pool, NULL); |
|
|
0
|
|
|
|
|
|
851
|
|
|
|
|
|
|
} |