1 /*
2 *
3 * Conky, a system monitor, based on torsmo
4 *
5 * Any original torsmo code is licensed under the BSD license
6 *
7 * All code written since the fork of torsmo is licensed under the GPL
8 *
9 * Please see COPYING for details
10 *
11 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12 * Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al.
13 * (see AUTHORS)
14 * All rights reserved.
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30 #include "proc.h"
31 #include <dirent.h>
32 #include <unistd.h>
33 #include <cctype>
34 #include <memory>
35 #include <sstream>
36 #include "conky.h"
37 #include "core.h"
38 #include "logging.h"
39
readfile(const char * filename,int * total_read,char showerror)40 char *readfile(const char *filename, int *total_read, char showerror) {
41 FILE *file;
42 char *buf = nullptr;
43 int bytes_read;
44
45 *total_read = 0;
46 file = fopen(filename, "re");
47 if (file != nullptr) {
48 do {
49 buf = static_cast<char *>(realloc(buf, *total_read + READSIZE + 1));
50 bytes_read = fread(buf + *total_read, 1, READSIZE, file);
51 *total_read += bytes_read;
52 buf[*total_read] = 0;
53 } while (bytes_read != 0);
54 fclose(file);
55 } else if (showerror != 0) {
56 NORM_ERR(READERR, filename);
57 }
58 return buf;
59 }
60
pid_readlink(const char * file,char * p,unsigned int p_max_size)61 void pid_readlink(const char *file, char *p, unsigned int p_max_size) {
62 std::unique_ptr<char[]> buf(new char[p_max_size]);
63
64 memset(buf.get(), 0, p_max_size);
65 if (readlink(file, buf.get(), p_max_size) >= 0) {
66 snprintf(p, p_max_size, "%s", buf.get());
67 } else {
68 NORM_ERR(READERR, file);
69 }
70 }
71
72 struct ll_string {
73 char *string;
74 struct ll_string *next;
75 };
76
addnode(struct ll_string * end,char * string)77 struct ll_string *addnode(struct ll_string *end, char *string) {
78 auto *current =
79 static_cast<struct ll_string *>(malloc(sizeof(struct ll_string)));
80 current->string = strdup(string);
81 current->next = nullptr;
82 if (end != nullptr) { end->next = current; }
83 return current;
84 }
85
freelist(struct ll_string * front)86 void freelist(struct ll_string *front) {
87 if (front != nullptr) {
88 free(front->string);
89 if (front->next != nullptr) { freelist(front->next); }
90 free(front);
91 }
92 }
93
inlist(struct ll_string * front,char * string)94 int inlist(struct ll_string *front, char *string) {
95 struct ll_string *current;
96
97 for (current = front; current != nullptr; current = current->next) {
98 if (strcmp(current->string, string) == 0) { return 1; }
99 }
100 return 0;
101 }
102
print_pid_chroot(struct text_object * obj,char * p,unsigned int p_max_size)103 void print_pid_chroot(struct text_object *obj, char *p,
104 unsigned int p_max_size) {
105 std::ostringstream pathstream;
106 std::unique_ptr<char[]> buf(new char[max_user_text.get(*state)]);
107
108 generate_text_internal(buf.get(), max_user_text.get(*state), *obj->sub);
109 pathstream << PROCDIR "/" << buf.get() << "/root";
110 pid_readlink(pathstream.str().c_str(), p, p_max_size);
111 }
112
print_pid_cmdline(struct text_object * obj,char * p,unsigned int p_max_size)113 void print_pid_cmdline(struct text_object *obj, char *p,
114 unsigned int p_max_size) {
115 char *buf;
116 int i, bytes_read;
117 std::ostringstream pathstream;
118 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
119
120 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
121
122 if (*(objbuf.get()) != 0) {
123 pathstream << PROCDIR "/" << objbuf.get() << "/cmdline";
124 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
125 if (buf != nullptr) {
126 for (i = 0; i < bytes_read - 1; i++) {
127 if (buf[i] == 0) { buf[i] = ' '; }
128 }
129 snprintf(p, p_max_size, "%s", buf);
130 free(buf);
131 }
132 } else {
133 NORM_ERR("$pid_cmdline didn't receive a argument");
134 }
135 }
136
print_pid_cwd(struct text_object * obj,char * p,unsigned int p_max_size)137 void print_pid_cwd(struct text_object *obj, char *p, unsigned int p_max_size) {
138 std::unique_ptr<char[]> buf(new char[p_max_size]);
139 int bytes_read;
140 std::ostringstream pathstream;
141 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
142
143 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
144 pathstream << PROCDIR "/" << objbuf.get() << "/cwd";
145 bytes_read = readlink(pathstream.str().c_str(), buf.get(), p_max_size);
146 if (bytes_read != -1) {
147 buf[bytes_read] = 0;
148 snprintf(p, p_max_size, "%s", buf.get());
149 } else {
150 NORM_ERR(READERR, pathstream.str().c_str());
151 }
152 }
153
print_pid_environ(struct text_object * obj,char * p,unsigned int p_max_size)154 void print_pid_environ(struct text_object *obj, char *p,
155 unsigned int p_max_size) {
156 int i, total_read;
157 pid_t pid;
158 std::ostringstream pathstream;
159 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
160 char *buf, *var = strdup(obj->data.s);
161 ;
162
163 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
164 if (sscanf(objbuf.get(), "%d %s", &pid, var) == 2) {
165 for (i = 0; var[i] != 0; i++) {
166 var[i] = toupper(static_cast<unsigned char>(var[i]));
167 }
168 pathstream << PROCDIR "/" << pid << "/cwd";
169 buf = readfile(pathstream.str().c_str(), &total_read, 1);
170 if (buf != nullptr) {
171 for (i = 0; i < total_read; i += strlen(buf + i) + 1) {
172 if (strncmp(buf + i, var, strlen(var)) == 0 &&
173 *(buf + i + strlen(var)) == '=') {
174 snprintf(p, p_max_size, "%s", buf + i + strlen(var) + 1);
175 free(buf);
176 free(var);
177 return;
178 }
179 }
180 free(buf);
181 }
182 *p = 0;
183 }
184 free(var);
185 }
186
print_pid_environ_list(struct text_object * obj,char * p,unsigned int p_max_size)187 void print_pid_environ_list(struct text_object *obj, char *p,
188 unsigned int p_max_size) {
189 char *buf = nullptr;
190 char *buf2;
191 int bytes_read, total_read;
192 int i = 0;
193 std::ostringstream pathstream;
194 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
195
196 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
197 pathstream << PROCDIR "/" << objbuf.get() << "/environ";
198
199 buf = readfile(pathstream.str().c_str(), &total_read, 1);
200 if (buf != nullptr) {
201 for (bytes_read = 0; bytes_read < total_read; buf[i - 1] = ';') {
202 buf2 = strdup(buf + bytes_read);
203 bytes_read += strlen(buf2) + 1;
204 sscanf(buf2, "%[^=]", buf + i);
205 free(buf2);
206 i = strlen(buf) + 1;
207 }
208 buf[i - 1] = 0;
209 snprintf(p, p_max_size, "%s", buf);
210 free(buf);
211 }
212 }
213
print_pid_exe(struct text_object * obj,char * p,unsigned int p_max_size)214 void print_pid_exe(struct text_object *obj, char *p, unsigned int p_max_size) {
215 std::ostringstream pathstream;
216 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
217
218 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
219 pathstream << PROCDIR "/" << objbuf.get() << "/exe";
220 pid_readlink(pathstream.str().c_str(), p, p_max_size);
221 }
222
print_pid_nice(struct text_object * obj,char * p,unsigned int p_max_size)223 void print_pid_nice(struct text_object *obj, char *p, unsigned int p_max_size) {
224 char *buf = nullptr;
225 int bytes_read;
226 long int nice_value;
227 std::ostringstream pathstream;
228 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
229
230 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
231
232 if (!obj->data.s) {
233 pathstream << PROCDIR "/" << objbuf.get() << "/stat";
234 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
235 if (buf != nullptr) {
236 sscanf(buf,
237 "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d "
238 "%*d %*d %ld",
239 &nice_value);
240 snprintf(p, p_max_size, "%ld", nice_value);
241 free(buf);
242 }
243 } else {
244 NORM_ERR("$pid_nice didn't receive a argument");
245 }
246 }
247
print_pid_openfiles(struct text_object * obj,char * p,unsigned int p_max_size)248 void print_pid_openfiles(struct text_object *obj, char *p,
249 unsigned int p_max_size) {
250 DIR *dir;
251 struct dirent *entry;
252 std::unique_ptr<char[]> buf(new char[p_max_size]);
253 int length, totallength = 0;
254 struct ll_string *files_front = nullptr;
255 struct ll_string *files_back = nullptr;
256 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
257
258 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
259
260 dir = opendir(objbuf.get());
261 if (dir != nullptr) {
262 while ((entry = readdir(dir)) != nullptr) {
263 if (entry->d_name[0] != '.') {
264 snprintf(buf.get(), p_max_size, "%s/%s", objbuf.get(), entry->d_name);
265 length = readlink(buf.get(), buf.get(), p_max_size);
266 buf[length] = 0;
267 if (inlist(files_front, buf.get()) == 0) {
268 files_back = addnode(files_back, buf.get());
269 snprintf(p + totallength, p_max_size - totallength, "%s; ",
270 buf.get());
271 totallength += length + strlen("; ");
272 }
273 if (files_front == nullptr) { files_front = files_back; }
274 }
275 }
276 closedir(dir);
277 freelist(files_front);
278 p[totallength - strlen("; ")] = 0;
279 } else {
280 p[0] = 0;
281 }
282 }
283
print_pid_parent(struct text_object * obj,char * p,unsigned int p_max_size)284 void print_pid_parent(struct text_object *obj, char *p,
285 unsigned int p_max_size) {
286 #define PARENT_ENTRY "PPid:\t"
287 #define PARENTNOTFOUND "Can't find the process parent in '%s'"
288 char *begin, *end, *buf = nullptr;
289 int bytes_read;
290 std::ostringstream pathstream;
291 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
292
293 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
294 pathstream << PROCDIR "/" << objbuf.get() << "/status";
295
296 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
297 if (buf != nullptr) {
298 begin = strstr(buf, PARENT_ENTRY);
299 if (begin != nullptr) {
300 begin += strlen(PARENT_ENTRY);
301 end = strchr(begin, '\n');
302 if (end != nullptr) { *(end) = 0; }
303 snprintf(p, p_max_size, "%s", begin);
304 } else {
305 NORM_ERR(PARENTNOTFOUND, pathstream.str().c_str());
306 }
307 free(buf);
308 }
309 }
310
print_pid_priority(struct text_object * obj,char * p,unsigned int p_max_size)311 void print_pid_priority(struct text_object *obj, char *p,
312 unsigned int p_max_size) {
313 char *buf = nullptr;
314 int bytes_read;
315 long int priority;
316 std::ostringstream pathstream;
317 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
318
319 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
320
321 if (*(objbuf.get()) != 0) {
322 pathstream << PROCDIR "/" << objbuf.get() << "/stat";
323 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
324 if (buf != nullptr) {
325 sscanf(buf,
326 "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u %*d "
327 "%*d %ld",
328 &priority);
329 snprintf(p, p_max_size, "%ld", priority);
330 free(buf);
331 }
332 } else {
333 NORM_ERR("$pid_priority didn't receive a argument");
334 }
335 }
336
print_pid_state(struct text_object * obj,char * p,unsigned int p_max_size)337 void print_pid_state(struct text_object *obj, char *p,
338 unsigned int p_max_size) {
339 #define STATE_ENTRY "State:\t"
340 #define STATENOTFOUND "Can't find the process state in '%s'"
341 char *begin, *end, *buf = nullptr;
342 int bytes_read;
343 std::ostringstream pathstream;
344 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
345
346 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
347 pathstream << PROCDIR "/" << objbuf.get() << "/status";
348
349 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
350 if (buf != nullptr) {
351 begin = strstr(buf, STATE_ENTRY);
352 if (begin != nullptr) {
353 begin += strlen(STATE_ENTRY) +
354 3; // +3 will strip the char representing the short state and
355 // the space and '(' that follow
356 end = strchr(begin, '\n');
357 if (end != nullptr) {
358 *(end - 1) = 0; // -1 strips the ')'
359 }
360 snprintf(p, p_max_size, "%s", begin);
361 } else {
362 NORM_ERR(STATENOTFOUND, pathstream.str().c_str());
363 }
364 free(buf);
365 }
366 }
367
print_pid_state_short(struct text_object * obj,char * p,unsigned int p_max_size)368 void print_pid_state_short(struct text_object *obj, char *p,
369 unsigned int p_max_size) {
370 char *begin, *buf = nullptr;
371 int bytes_read;
372 std::ostringstream pathstream;
373 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
374
375 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
376
377 pathstream << PROCDIR "/" << objbuf.get() << "/status";
378
379 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
380 if (buf != nullptr) {
381 begin = strstr(buf, STATE_ENTRY);
382 if (begin != nullptr) {
383 snprintf(p, p_max_size, "%c", *begin);
384 } else {
385 NORM_ERR(STATENOTFOUND, pathstream.str().c_str());
386 }
387 free(buf);
388 }
389 }
390
print_pid_stderr(struct text_object * obj,char * p,unsigned int p_max_size)391 void print_pid_stderr(struct text_object *obj, char *p,
392 unsigned int p_max_size) {
393 std::ostringstream pathstream;
394 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
395
396 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
397
398 pathstream << PROCDIR "/" << objbuf.get() << "/fd/2";
399 pid_readlink(pathstream.str().c_str(), p, p_max_size);
400 }
401
print_pid_stdin(struct text_object * obj,char * p,unsigned int p_max_size)402 void print_pid_stdin(struct text_object *obj, char *p,
403 unsigned int p_max_size) {
404 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
405 std::ostringstream pathstream;
406
407 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
408
409 pathstream << PROCDIR "/" << objbuf.get() << "/fd/0";
410 pid_readlink(pathstream.str().c_str(), p, p_max_size);
411 }
412
print_pid_stdout(struct text_object * obj,char * p,unsigned int p_max_size)413 void print_pid_stdout(struct text_object *obj, char *p,
414 unsigned int p_max_size) {
415 std::ostringstream pathstream;
416 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
417
418 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
419
420 pathstream << PROCDIR "/" << objbuf.get() << "/fd/1";
421 pid_readlink(pathstream.str().c_str(), p, p_max_size);
422 }
423
scan_cmdline_to_pid_arg(struct text_object * obj,const char * arg,void * free_at_crash)424 void scan_cmdline_to_pid_arg(struct text_object *obj, const char *arg,
425 void *free_at_crash) {
426 unsigned int i;
427 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
428
429 /* FIXME */
430 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
431
432 if (strlen(arg) > 0) {
433 obj->data.s = strdup(arg);
434 for (i = 0; obj->data.s[i] != 0; i++) {
435 while (obj->data.s[i] == ' ' && obj->data.s[i + 1] == ' ') {
436 memmove(obj->data.s + i, obj->data.s + i + 1,
437 strlen(obj->data.s + i + 1) + 1);
438 }
439 }
440 if (obj->data.s[i - 1] == ' ') { obj->data.s[i - 1] = 0; }
441 } else {
442 CRIT_ERR(obj, free_at_crash, "${cmdline_to_pid commandline}");
443 }
444 }
445
print_cmdline_to_pid(struct text_object * obj,char * p,unsigned int p_max_size)446 void print_cmdline_to_pid(struct text_object *obj, char *p,
447 unsigned int p_max_size) {
448 DIR *dir;
449 struct dirent *entry;
450 char *buf;
451 int bytes_read, i;
452 std::ostringstream pathstream;
453
454 dir = opendir(PROCDIR);
455 if (dir != nullptr) {
456 while ((entry = readdir(dir)) != nullptr) {
457 pathstream << PROCDIR "/" << entry->d_name << "/cmdline";
458
459 buf = readfile(pathstream.str().c_str(), &bytes_read, 0);
460 if (buf != nullptr) {
461 for (i = 0; i < bytes_read - 1; i++) {
462 if (buf[i] == 0) { buf[i] = ' '; }
463 }
464 if (strstr(buf, obj->data.s) != nullptr) {
465 snprintf(p, p_max_size, "%s", entry->d_name);
466 free(buf);
467 closedir(dir);
468 return;
469 }
470 free(buf);
471 }
472 }
473 closedir(dir);
474 } else {
475 NORM_ERR(READERR, PROCDIR);
476 }
477 }
478
print_pid_threads(struct text_object * obj,char * p,unsigned int p_max_size)479 void print_pid_threads(struct text_object *obj, char *p,
480 unsigned int p_max_size) {
481 #define THREADS_ENTRY "Threads:\t"
482 #define THREADSNOTFOUND \
483 "Can't find the number of the threads of the process in '%s'"
484 char *begin, *end, *buf = nullptr;
485 int bytes_read;
486 std::ostringstream pathstream;
487 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
488
489 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
490 pathstream << PROCDIR "/" << objbuf.get() << "/status";
491
492 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
493 if (buf != nullptr) {
494 begin = strstr(buf, THREADS_ENTRY);
495 if (begin != nullptr) {
496 begin += strlen(THREADS_ENTRY);
497 end = strchr(begin, '\n');
498 if (end != nullptr) { *(end) = 0; }
499 snprintf(p, p_max_size, "%s", begin);
500 } else {
501 NORM_ERR(THREADSNOTFOUND, pathstream.str().c_str());
502 }
503 free(buf);
504 }
505 }
506
print_pid_thread_list(struct text_object * obj,char * p,unsigned int p_max_size)507 void print_pid_thread_list(struct text_object *obj, char *p,
508 unsigned int p_max_size) {
509 DIR *dir;
510 struct dirent *entry;
511 int totallength = 0;
512 std::ostringstream pathstream;
513 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
514
515 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
516 pathstream << PROCDIR "/" << objbuf.get() << "/task";
517
518 dir = opendir(pathstream.str().c_str());
519 if (dir != nullptr) {
520 while ((entry = readdir(dir)) != nullptr) {
521 if (entry->d_name[0] != '.') {
522 snprintf(p + totallength, p_max_size - totallength, "%s,",
523 entry->d_name);
524 totallength += strlen(entry->d_name) + 1;
525 }
526 }
527 closedir(dir);
528 if (totallength > 0 && p[totallength - 1] == ',') {
529 p[totallength - 1] = 0;
530 }
531 } else {
532 p[0] = 0;
533 }
534 }
535
print_pid_time_kernelmode(struct text_object * obj,char * p,unsigned int p_max_size)536 void print_pid_time_kernelmode(struct text_object *obj, char *p,
537 unsigned int p_max_size) {
538 char *buf = nullptr;
539 int bytes_read;
540 unsigned long int umtime;
541 std::ostringstream pathstream;
542 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
543
544 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
545
546 if (*(objbuf.get()) != 0) {
547 pathstream << PROCDIR "/" << objbuf.get() << "/stat";
548 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
549 if (buf != nullptr) {
550 sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu",
551 &umtime);
552 snprintf(p, p_max_size, "%.2f", static_cast<float>(umtime) / 100);
553 free(buf);
554 }
555 } else {
556 NORM_ERR("$pid_time_kernelmode didn't receive a argument");
557 }
558 }
559
print_pid_time_usermode(struct text_object * obj,char * p,unsigned int p_max_size)560 void print_pid_time_usermode(struct text_object *obj, char *p,
561 unsigned int p_max_size) {
562 char *buf = nullptr;
563 int bytes_read;
564 unsigned long int kmtime;
565 std::ostringstream pathstream;
566 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
567
568 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
569
570 if (*(objbuf.get()) != 0) {
571 pathstream << PROCDIR "/" << objbuf.get() << "/stat";
572 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
573 if (buf != nullptr) {
574 sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %lu",
575 &kmtime);
576 snprintf(p, p_max_size, "%.2f", static_cast<float>(kmtime) / 100);
577 free(buf);
578 }
579 } else {
580 NORM_ERR("$pid_time_usermode didn't receive a argument");
581 }
582 }
583
print_pid_time(struct text_object * obj,char * p,unsigned int p_max_size)584 void print_pid_time(struct text_object *obj, char *p, unsigned int p_max_size) {
585 char *buf = nullptr;
586 int bytes_read;
587 unsigned long int umtime, kmtime;
588 std::ostringstream pathstream;
589 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
590
591 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
592
593 if (*(objbuf.get()) != 0) {
594 pathstream << PROCDIR "/" << objbuf.get() << "/stat";
595 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
596 if (buf != nullptr) {
597 sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu",
598 &umtime, &kmtime);
599 snprintf(p, p_max_size, "%.2f",
600 static_cast<float>(umtime + kmtime) / 100);
601 free(buf);
602 }
603 } else {
604 NORM_ERR("$pid_time didn't receive a argument");
605 }
606 }
607
608 enum xid_type { egid, euid, fsgid, fsuid, gid, sgid, suid, uid };
609
print_pid_Xid(struct text_object * obj,char * p,int p_max_size,xid_type type)610 void print_pid_Xid(struct text_object *obj, char *p, int p_max_size,
611 xid_type type) {
612 char *begin, *end, *buf = nullptr;
613 int bytes_read;
614 std::ostringstream pathstream;
615 std::string errorstring;
616 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
617
618 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
619 pathstream << PROCDIR "/" << objbuf.get() << "/status";
620
621 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
622 if (buf != nullptr) {
623 switch (type) {
624 case egid:
625 begin = strstr(buf, "Gid:\t");
626 break;
627 case euid:
628 begin = strstr(buf, "Uid:\t");
629 break;
630 case fsgid:
631 begin = strstr(buf, "Gid:\t");
632 break;
633 case fsuid:
634 begin = strstr(buf, "Uid:\t");
635 break;
636 case gid:
637 begin = strstr(buf, "Gid:\t");
638 break;
639 case sgid:
640 begin = strstr(buf, "Gid:\t");
641 break;
642 case suid:
643 begin = strstr(buf, "Uid:\t");
644 break;
645 case uid:
646 begin = strstr(buf, "Uid:\t");
647 break;
648 default:
649 break;
650 }
651 if (begin != nullptr) {
652 switch (type) {
653 case gid:
654 begin += strlen("Gid:\t");
655 break;
656 case uid:
657 begin += strlen("Uid:\t");
658 break;
659 case egid:
660 case euid:
661 begin = strchr(begin, '\t');
662 begin++;
663 begin = strchr(begin, '\t');
664 begin++;
665 break;
666 case sgid:
667 case suid:
668 begin = strchr(begin, '\t');
669 begin++;
670 begin = strchr(begin, '\t');
671 begin++;
672 begin = strchr(begin, '\t');
673 begin++;
674 break;
675 case fsgid:
676 case fsuid:
677 begin = strchr(begin, '\t');
678 begin++;
679 begin = strchr(begin, '\t');
680 begin++;
681 begin = strchr(begin, '\t');
682 begin++;
683 begin = strchr(begin, '\t');
684 begin++;
685 break;
686 default:
687 break;
688 }
689 if (type == fsgid || type == fsuid) {
690 end = strchr(begin, '\n');
691 } else {
692 end = strchr(begin, '\t');
693 }
694 if (end != nullptr) { *(end) = 0; }
695 snprintf(p, p_max_size, "%s", begin);
696 } else {
697 errorstring = "Can't find the process ";
698 switch (type) {
699 case egid:
700 errorstring.append("effective gid");
701 break;
702 case euid:
703 errorstring.append("effective uid");
704 break;
705 case fsgid:
706 errorstring.append("process file system gid");
707 break;
708 case fsuid:
709 errorstring.append("process file system uid");
710 break;
711 case gid:
712 errorstring.append("real gid");
713 break;
714 case sgid:
715 errorstring.append("saved set gid");
716 break;
717 case suid:
718 errorstring.append("saved set uid");
719 break;
720 case uid:
721 errorstring.append("real uid");
722 break;
723 default:
724 break;
725 }
726 errorstring.append(" in '%s'");
727 NORM_ERR(errorstring.c_str(), pathstream.str().c_str());
728 }
729 free(buf);
730 }
731 }
732
print_pid_egid(struct text_object * obj,char * p,unsigned int p_max_size)733 void print_pid_egid(struct text_object *obj, char *p, unsigned int p_max_size) {
734 print_pid_Xid(obj, p, p_max_size, egid);
735 }
736
print_pid_euid(struct text_object * obj,char * p,unsigned int p_max_size)737 void print_pid_euid(struct text_object *obj, char *p, unsigned int p_max_size) {
738 print_pid_Xid(obj, p, p_max_size, euid);
739 }
740
print_pid_fsgid(struct text_object * obj,char * p,unsigned int p_max_size)741 void print_pid_fsgid(struct text_object *obj, char *p,
742 unsigned int p_max_size) {
743 print_pid_Xid(obj, p, p_max_size, fsgid);
744 }
745
print_pid_fsuid(struct text_object * obj,char * p,unsigned int p_max_size)746 void print_pid_fsuid(struct text_object *obj, char *p,
747 unsigned int p_max_size) {
748 print_pid_Xid(obj, p, p_max_size, fsuid);
749 }
750
print_pid_gid(struct text_object * obj,char * p,unsigned int p_max_size)751 void print_pid_gid(struct text_object *obj, char *p, unsigned int p_max_size) {
752 print_pid_Xid(obj, p, p_max_size, gid);
753 }
754
print_pid_sgid(struct text_object * obj,char * p,unsigned int p_max_size)755 void print_pid_sgid(struct text_object *obj, char *p, unsigned int p_max_size) {
756 print_pid_Xid(obj, p, p_max_size, sgid);
757 }
758
print_pid_suid(struct text_object * obj,char * p,unsigned int p_max_size)759 void print_pid_suid(struct text_object *obj, char *p, unsigned int p_max_size) {
760 print_pid_Xid(obj, p, p_max_size, suid);
761 }
762
print_pid_uid(struct text_object * obj,char * p,unsigned int p_max_size)763 void print_pid_uid(struct text_object *obj, char *p, unsigned int p_max_size) {
764 print_pid_Xid(obj, p, p_max_size, uid);
765 }
766
internal_print_pid_vm(struct text_object * obj,char * p,int p_max_size,const char * entry,const char * errorstring)767 void internal_print_pid_vm(struct text_object *obj, char *p, int p_max_size,
768 const char *entry, const char *errorstring) {
769 char *begin, *end, *buf = nullptr;
770 int bytes_read;
771 std::ostringstream pathstream;
772 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
773
774 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
775 pathstream << PROCDIR "/" << objbuf.get() << "/status";
776
777 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
778 if (buf != nullptr) {
779 begin = strstr(buf, entry);
780 if (begin != nullptr) {
781 begin += strlen(entry);
782 while (*begin == '\t' || *begin == ' ') { begin++; }
783 end = strchr(begin, '\n');
784 if (end != nullptr) { *(end) = 0; }
785 snprintf(p, p_max_size, "%s", begin);
786 } else {
787 NORM_ERR(errorstring, pathstream.str().c_str());
788 }
789 free(buf);
790 }
791 }
792
print_pid_vmpeak(struct text_object * obj,char * p,unsigned int p_max_size)793 void print_pid_vmpeak(struct text_object *obj, char *p,
794 unsigned int p_max_size) {
795 internal_print_pid_vm(
796 obj, p, p_max_size, "VmPeak:\t",
797 "Can't find the process peak virtual memory size in '%s'");
798 }
799
print_pid_vmsize(struct text_object * obj,char * p,unsigned int p_max_size)800 void print_pid_vmsize(struct text_object *obj, char *p,
801 unsigned int p_max_size) {
802 internal_print_pid_vm(obj, p, p_max_size, "VmSize:\t",
803 "Can't find the process virtual memory size in '%s'");
804 }
805
print_pid_vmlck(struct text_object * obj,char * p,unsigned int p_max_size)806 void print_pid_vmlck(struct text_object *obj, char *p,
807 unsigned int p_max_size) {
808 internal_print_pid_vm(obj, p, p_max_size, "VmLck:\t",
809 "Can't find the process locked memory size in '%s'");
810 }
811
print_pid_vmhwm(struct text_object * obj,char * p,unsigned int p_max_size)812 void print_pid_vmhwm(struct text_object *obj, char *p,
813 unsigned int p_max_size) {
814 internal_print_pid_vm(
815 obj, p, p_max_size, "VmHWM:\t",
816 "Can't find the process peak resident set size in '%s'");
817 }
818
print_pid_vmrss(struct text_object * obj,char * p,unsigned int p_max_size)819 void print_pid_vmrss(struct text_object *obj, char *p,
820 unsigned int p_max_size) {
821 internal_print_pid_vm(obj, p, p_max_size, "VmHWM:\t",
822 "Can't find the process resident set size in '%s'");
823 }
824
print_pid_vmdata(struct text_object * obj,char * p,unsigned int p_max_size)825 void print_pid_vmdata(struct text_object *obj, char *p,
826 unsigned int p_max_size) {
827 internal_print_pid_vm(obj, p, p_max_size, "VmData:\t",
828 "Can't find the process data segment size in '%s'");
829 }
830
print_pid_vmstk(struct text_object * obj,char * p,unsigned int p_max_size)831 void print_pid_vmstk(struct text_object *obj, char *p,
832 unsigned int p_max_size) {
833 internal_print_pid_vm(obj, p, p_max_size, "VmData:\t",
834 "Can't find the process stack segment size in '%s'");
835 }
836
print_pid_vmexe(struct text_object * obj,char * p,unsigned int p_max_size)837 void print_pid_vmexe(struct text_object *obj, char *p,
838 unsigned int p_max_size) {
839 internal_print_pid_vm(obj, p, p_max_size, "VmData:\t",
840 "Can't find the process text segment size in '%s'");
841 }
842
print_pid_vmlib(struct text_object * obj,char * p,unsigned int p_max_size)843 void print_pid_vmlib(struct text_object *obj, char *p,
844 unsigned int p_max_size) {
845 internal_print_pid_vm(
846 obj, p, p_max_size, "VmLib:\t",
847 "Can't find the process shared library code size in '%s'");
848 }
849
print_pid_vmpte(struct text_object * obj,char * p,unsigned int p_max_size)850 void print_pid_vmpte(struct text_object *obj, char *p,
851 unsigned int p_max_size) {
852 internal_print_pid_vm(
853 obj, p, p_max_size, "VmPTE:\t",
854 "Can't find the process page table entries size in '%s'");
855 }
856
857 #define READ_ENTRY "read_bytes: "
858 #define READNOTFOUND "Can't find the amount of bytes read in '%s'"
print_pid_read(struct text_object * obj,char * p,unsigned int p_max_size)859 void print_pid_read(struct text_object *obj, char *p, unsigned int p_max_size) {
860 char *begin, *end, *buf = nullptr;
861 int bytes_read;
862 std::ostringstream pathstream;
863 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
864
865 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
866 pathstream << PROCDIR "/" << objbuf.get() << "/io";
867
868 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
869 if (buf != nullptr) {
870 begin = strstr(buf, READ_ENTRY);
871 if (begin != nullptr) {
872 end = strchr(begin, '\n');
873 if (end != nullptr) { *(end) = 0; }
874 snprintf(p, p_max_size, "%s", begin);
875 } else {
876 NORM_ERR(READNOTFOUND, pathstream.str().c_str());
877 }
878 free(buf);
879 }
880 }
881
882 #define WRITE_ENTRY "write_bytes: "
883 #define WRITENOTFOUND "Can't find the amount of bytes written in '%s'"
print_pid_write(struct text_object * obj,char * p,unsigned int p_max_size)884 void print_pid_write(struct text_object *obj, char *p,
885 unsigned int p_max_size) {
886 char *begin, *end, *buf = nullptr;
887 int bytes_read;
888 std::ostringstream pathstream;
889 std::unique_ptr<char[]> objbuf(new char[max_user_text.get(*state)]);
890
891 generate_text_internal(objbuf.get(), max_user_text.get(*state), *obj->sub);
892 pathstream << PROCDIR "/" << objbuf.get() << "/io";
893
894 buf = readfile(pathstream.str().c_str(), &bytes_read, 1);
895 if (buf != nullptr) {
896 begin = strstr(buf, WRITE_ENTRY);
897 if (begin != nullptr) {
898 end = strchr(begin, '\n');
899 if (end != nullptr) { *(end) = 0; }
900 snprintf(p, p_max_size, "%s", begin);
901 } else {
902 NORM_ERR(WRITENOTFOUND, pathstream.str().c_str());
903 }
904 free(buf);
905 }
906 }
907