Shrink proc.c
[monky] / src / proc.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  * vim: ts=4 sw=4 noet ai cindent syntax=c
3  *
4  * Conky, a system monitor, based on torsmo
5  *
6  * Any original torsmo code is licensed under the BSD license
7  *
8  * All code written since the fork of torsmo is licensed under the GPL
9  *
10  * Please see COPYING for details
11  *
12  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
13  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14  *   (see AUTHORS)
15  * All rights reserved.
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * You should have received a copy of the GNU General Public License
27  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28  *
29  */
30
31 #include <logging.h>
32 #include "conky.h"
33 #include "proc.h"
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <dirent.h>
37
38 void scan_pid_arg(struct text_object *obj, const char *arg, void* free_at_crash, const char *file)
39 {
40         pid_t pid;
41
42         if(sscanf(arg, "%d", &pid) == 1) {
43                 asprintf(&obj->data.s, PROCDIR "/%d/%s", pid, file);
44         } else {
45                 CRIT_ERR(obj, free_at_crash, "syntax error: ${pid_%s pid}", file);
46         }
47 }
48
49 void scan_pid_cmdline_arg(struct text_object *obj, const char *arg, void* free_at_crash)
50 {
51         scan_pid_arg(obj, arg, free_at_crash, "cmdline");
52 }
53
54 char* readfile(char* filename, int* total_read) {
55         FILE* file;
56         char* buf = NULL;
57         int bytes_read;
58
59         *total_read = 0;
60         file = fopen(filename, "r");
61         if(file) {
62                 do {
63                         buf = realloc(buf, *total_read + READSIZE + 1);
64                         bytes_read = fread(buf + *total_read, 1, READSIZE, file);
65                         *total_read += bytes_read;
66                         buf[*total_read] = 0;
67                 }while(bytes_read != 0);
68                 fclose(file);
69         } else {
70                 NORM_ERR(READERR, filename);
71         }
72         return buf;
73 }
74
75 void print_pid_cmdline(struct text_object *obj, char *p, int p_max_size)
76 {
77         char* buf;
78         int i, bytes_read;
79
80         buf = readfile(obj->data.s, &bytes_read);
81         if(buf != NULL) {
82                 for(i = 0; i < bytes_read-1; i++) {
83                         if(buf[i] == 0) {
84                                 buf[i] = ' ';
85                         }
86                 }
87                 snprintf(p, p_max_size, "%s", buf);
88                 free(buf);
89         }
90 }
91
92 void scan_pid_cwd_arg(struct text_object *obj, const char *arg, void* free_at_crash)
93 {
94         scan_pid_arg(obj, arg, free_at_crash, "cwd");
95 }
96
97 void print_pid_cwd(struct text_object *obj, char *p, int p_max_size)
98 {
99         char buf[p_max_size];
100         int bytes_read;
101
102         memset(buf, 0, p_max_size);
103         bytes_read = readlink(obj->data.s, buf, p_max_size);
104         if(bytes_read != -1) {
105                 snprintf(p, p_max_size, "%s", buf);
106         } else {
107                 NORM_ERR(READERR, obj->data.s);
108         }
109 }
110
111 void scan_pid_environ_arg(struct text_object *obj, const char *arg, void* free_at_crash)
112 {
113         pid_t pid;
114         int i;
115         struct environ_data* ed = malloc(sizeof(struct environ_data));
116
117         ed->var = malloc(strlen(arg));
118         if(sscanf(arg, "%d %s", &pid, ed->var) == 2) {
119                 asprintf(&ed->file, PROCDIR "/%d/environ", pid);
120                 for(i = 0; ed->var[i] != 0; i++) {
121                         ed->var[i] = toupper(ed->var[i]);
122                 }
123                 obj->data.opaque = ed;
124         } else {
125                 free(ed->var);
126                 free(ed);
127                 CRIT_ERR(obj, free_at_crash, "${pid_environ pid varname}");
128         }
129 }
130
131 void print_pid_environ(struct text_object *obj, char *p, int p_max_size)
132 {
133         char *buf = NULL;
134         char *searchstring = ((struct environ_data*) obj->data.opaque)->var;
135         int bytes_read, total_read = 0;
136
137         buf = readfile(((struct environ_data*) obj->data.opaque)->file, &total_read);
138         if(buf != NULL) {
139                 for(bytes_read = 0; bytes_read < total_read; bytes_read += strlen(buf + bytes_read) + 1) {
140                         if(strncmp(buf + bytes_read, searchstring, strlen(searchstring)) == 0 && *(buf + bytes_read + strlen(searchstring)) == '=') {
141                                 snprintf(p, p_max_size, "%s", buf + bytes_read + strlen(searchstring) + 1);
142                                 free(buf);
143                                 return;
144                         }
145                 }
146                 p[0] = 0;
147                 free(buf);
148         }
149 }
150
151 void free_pid_environ(struct text_object *obj) {
152         free(((struct environ_data*) obj->data.opaque)->file);
153         free(((struct environ_data*) obj->data.opaque)->var);
154         free(obj->data.opaque);
155 }
156
157 void scan_pid_environ_list_arg(struct text_object *obj, const char *arg, void* free_at_crash)
158 {
159         scan_pid_arg(obj, arg, free_at_crash, "environ");
160 }
161
162 void print_pid_environ_list(struct text_object *obj, char *p, int p_max_size)
163 {
164         char *buf = NULL;
165         char *buf2;
166         int bytes_read, total_read;
167         int i = 0;
168
169         buf = readfile(obj->data.s, &total_read);
170         if(buf != NULL) {
171                 for(bytes_read = 0; bytes_read < total_read; buf[i-1] = ';') {
172                         buf2 = strdup(buf+bytes_read);
173                         bytes_read += strlen(buf2)+1;
174                         sscanf(buf2, "%[^=]", buf+i);
175                         free(buf2);
176                         i = strlen(buf) + 1;
177                 }
178                 buf[i-1] = 0;
179                 snprintf(p, p_max_size, "%s", buf);
180                 free(buf);
181         }
182 }
183
184 void scan_pid_exe_arg(struct text_object *obj, const char *arg, void* free_at_crash)
185 {
186         scan_pid_arg(obj, arg, free_at_crash, "exe");
187 }
188
189 void print_pid_readlink(struct text_object *obj, char *p, int p_max_size)
190 {
191         char buf[p_max_size];
192
193         memset(buf, 0, p_max_size);
194         if(readlink(obj->data.s, buf, p_max_size) >= 0) {
195                 snprintf(p, p_max_size, "%s", buf);
196         } else {
197                 NORM_ERR(READERR, obj->data.s);
198         }
199 }
200
201 void scan_pid_chroot_arg(struct text_object *obj, const char *arg, void* free_at_crash) {
202         scan_pid_arg(obj, arg, free_at_crash, "root");
203 }
204
205 void print_pid_chroot(struct text_object *obj, char *p, int p_max_size) {
206         print_pid_readlink(obj, p, p_max_size);
207 }
208
209 void print_pid_exe(struct text_object *obj, char *p, int p_max_size) {
210         print_pid_readlink(obj, p, p_max_size);
211 }
212
213 void scan_pid_state_arg(struct text_object *obj, const char *arg, void* free_at_crash) {
214         scan_pid_arg(obj, arg, free_at_crash, "status");
215 }
216
217 void print_pid_state(struct text_object *obj, char *p, int p_max_size) {
218         char *begin, *end, *buf = NULL;
219         int bytes_read;
220
221         buf = readfile(obj->data.s, &bytes_read);
222         if(buf != NULL) {
223                 begin = strstr(buf, STATE_ENTRY);
224                 if(begin != NULL) {
225                         begin += strlen(STATE_ENTRY) + 3;       // +3 will strip the char representing the short state and the space and '(' that follow
226                         end = strchr(begin, '\n');
227                         if(end != NULL) {
228                                 *(end-1) = 0;
229                         }
230                         snprintf(p, p_max_size, "%s", begin);
231                 } else {
232                         NORM_ERR(STATENOTFOUND, obj->data.s);
233                 }
234                 free(buf);
235         }
236 }
237
238 void scan_pid_stderr_arg(struct text_object *obj, const char *arg, void* free_at_crash) {
239         scan_pid_arg(obj, arg, free_at_crash, "fd/2");
240 }
241
242 void print_pid_stderr(struct text_object *obj, char *p, int p_max_size) {
243         print_pid_readlink(obj, p, p_max_size);
244 }
245
246 void scan_pid_stdin_arg(struct text_object *obj, const char *arg, void* free_at_crash) {
247         scan_pid_arg(obj, arg, free_at_crash, "fd/0");
248 }
249
250 void print_pid_stdin(struct text_object *obj, char *p, int p_max_size) {
251         print_pid_readlink(obj, p, p_max_size);
252 }
253
254 void scan_pid_stdout_arg(struct text_object *obj, const char *arg, void* free_at_crash) {
255         scan_pid_arg(obj, arg, free_at_crash, "fd/1");
256 }
257
258 void print_pid_stdout(struct text_object *obj, char *p, int p_max_size) {
259         print_pid_readlink(obj, p, p_max_size);
260 }
261
262 void scan_pid_openfiles_arg(struct text_object *obj, const char *arg, void* free_at_crash) {
263         scan_pid_arg(obj, arg, free_at_crash, "fd");
264 }
265
266 struct ll_string {
267         char *string;
268         struct ll_string* next;
269 };
270
271 struct ll_string* addnode(struct ll_string* end, char* string) {
272         struct ll_string* current = malloc(sizeof(struct ll_string));
273         current->string = strdup(string);
274         current->next = NULL;
275         if(end != NULL) end->next = current;
276         return current;
277 }
278
279 void freelist(struct ll_string* front) {
280         if(front != NULL) {
281                 free(front->string);
282                 if(front->next != NULL) {
283                         freelist(front->next);
284                 }
285                 free(front);
286         }
287 }
288
289 int inlist(struct ll_string* front, char* string) {
290         struct ll_string* current;
291
292         for(current = front; current != NULL; current = current->next) {
293                 if(strcmp(current->string, string) == 0) {
294                         return 1;
295                 }
296         }
297         return 0;
298 }
299
300 void print_pid_openfiles(struct text_object *obj, char *p, int p_max_size) {
301         DIR* dir;
302         struct dirent *entry;
303         char buf[p_max_size];
304         int length, totallength = 0;
305         struct ll_string* files_front = NULL;
306         struct ll_string* files_back = NULL;
307
308         dir = opendir(obj->data.s);
309         if(dir != NULL) {
310                 while ((entry = readdir(dir))) {
311                         if(entry->d_name[0] != '.') {
312                                 snprintf(buf, p_max_size, "%s/%s", obj->data.s, entry->d_name);
313                                 length = readlink(buf, buf, p_max_size);
314                                 buf[length] = 0;
315                                 if(inlist(files_front, buf) == 0) {
316                                         files_back = addnode(files_back, buf);
317                                         snprintf(p + totallength, p_max_size - totallength, "%s; " , buf);
318                                         totallength += length + strlen("; ");
319                                 }
320                                 if(files_front == NULL) {
321                                         files_front = files_back;
322                                 }
323                         }
324                 }
325                 closedir(dir);
326                 freelist(files_front);
327                 p[totallength - strlen("; ")] = 0;
328         } else {
329                 p[0] = 0;
330         }
331 }