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