chiark / gitweb /
Prep v227: Clean up various *-util.[hc] files
[elogind.git] / src / basic / process-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdbool.h>
21 #include <sys/types.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <sys/wait.h>
28 #include <signal.h>
29 #include <ctype.h>
30
31 #include "fileio.h"
32 #include "util.h"
33 #include "log.h"
34 #include "signal-util.h"
35 #include "process-util.h"
36
37 int get_process_state(pid_t pid) {
38         const char *p;
39         char state;
40         int r;
41         _cleanup_free_ char *line = NULL;
42
43         assert(pid >= 0);
44
45         p = procfs_file_alloca(pid, "stat");
46
47         r = read_one_line_file(p, &line);
48         if (r == -ENOENT)
49                 return -ESRCH;
50         if (r < 0)
51                 return r;
52
53         p = strrchr(line, ')');
54         if (!p)
55                 return -EIO;
56
57         p++;
58
59         if (sscanf(p, " %c", &state) != 1)
60                 return -EIO;
61
62         return (unsigned char) state;
63 }
64
65 int get_process_comm(pid_t pid, char **name) {
66         const char *p;
67         int r;
68
69         assert(name);
70         assert(pid >= 0);
71
72         p = procfs_file_alloca(pid, "comm");
73
74         r = read_one_line_file(p, name);
75         if (r == -ENOENT)
76                 return -ESRCH;
77
78         return r;
79 }
80
81 int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
82         _cleanup_fclose_ FILE *f = NULL;
83         char *r = NULL, *k;
84         const char *p;
85         int c;
86
87         assert(line);
88         assert(pid >= 0);
89
90         p = procfs_file_alloca(pid, "cmdline");
91
92         f = fopen(p, "re");
93         if (!f) {
94                 if (errno == ENOENT)
95                         return -ESRCH;
96                 return -errno;
97         }
98
99         if (max_length == 0) {
100                 size_t len = 0, allocated = 0;
101
102                 while ((c = getc(f)) != EOF) {
103
104                         if (!GREEDY_REALLOC(r, allocated, len+2)) {
105                                 free(r);
106                                 return -ENOMEM;
107                         }
108
109                         r[len++] = isprint(c) ? c : ' ';
110                 }
111
112                 if (len > 0)
113                         r[len-1] = 0;
114
115         } else {
116                 bool space = false;
117                 size_t left;
118
119                 r = new(char, max_length);
120                 if (!r)
121                         return -ENOMEM;
122
123                 k = r;
124                 left = max_length;
125                 while ((c = getc(f)) != EOF) {
126
127                         if (isprint(c)) {
128                                 if (space) {
129                                         if (left <= 4)
130                                                 break;
131
132                                         *(k++) = ' ';
133                                         left--;
134                                         space = false;
135                                 }
136
137                                 if (left <= 4)
138                                         break;
139
140                                 *(k++) = (char) c;
141                                 left--;
142                         }  else
143                                 space = true;
144                 }
145
146                 if (left <= 4) {
147                         size_t n = MIN(left-1, 3U);
148                         memcpy(k, "...", n);
149                         k[n] = 0;
150                 } else
151                         *k = 0;
152         }
153
154         /* Kernel threads have no argv[] */
155         if (isempty(r)) {
156                 _cleanup_free_ char *t = NULL;
157                 int h;
158
159                 free(r);
160
161                 if (!comm_fallback)
162                         return -ENOENT;
163
164                 h = get_process_comm(pid, &t);
165                 if (h < 0)
166                         return h;
167
168                 r = strjoin("[", t, "]", NULL);
169                 if (!r)
170                         return -ENOMEM;
171         }
172
173         *line = r;
174         return 0;
175 }
176
177 int is_kernel_thread(pid_t pid) {
178         const char *p;
179         size_t count;
180         char c;
181         bool eof;
182         FILE *f;
183
184         if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */
185                 return 0;
186
187         assert(pid > 1);
188
189         p = procfs_file_alloca(pid, "cmdline");
190         f = fopen(p, "re");
191         if (!f) {
192                 if (errno == ENOENT)
193                         return -ESRCH;
194                 return -errno;
195         }
196
197         count = fread(&c, 1, 1, f);
198         eof = feof(f);
199         fclose(f);
200
201         /* Kernel threads have an empty cmdline */
202
203         if (count <= 0)
204                 return eof ? 1 : -errno;
205
206         return 0;
207 }
208
209 /// UNNEEDED by elogind
210 #if 0
211 int get_process_capeff(pid_t pid, char **capeff) {
212         const char *p;
213         int r;
214
215         assert(capeff);
216         assert(pid >= 0);
217
218         p = procfs_file_alloca(pid, "status");
219
220         r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
221         if (r == -ENOENT)
222                 return -ESRCH;
223
224         return r;
225 }
226 #endif // 0
227
228 static int get_process_link_contents(const char *proc_file, char **name) {
229         int r;
230
231         assert(proc_file);
232         assert(name);
233
234         r = readlink_malloc(proc_file, name);
235         if (r == -ENOENT)
236                 return -ESRCH;
237         if (r < 0)
238                 return r;
239
240         return 0;
241 }
242
243 int get_process_exe(pid_t pid, char **name) {
244         const char *p;
245         char *d;
246         int r;
247
248         assert(pid >= 0);
249
250         p = procfs_file_alloca(pid, "exe");
251         r = get_process_link_contents(p, name);
252         if (r < 0)
253                 return r;
254
255         d = endswith(*name, " (deleted)");
256         if (d)
257                 *d = '\0';
258
259         return 0;
260 }
261
262 /// UNNEEDED by elogind
263 #if 0
264 static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
265         _cleanup_fclose_ FILE *f = NULL;
266         char line[LINE_MAX];
267         const char *p;
268
269         assert(field);
270         assert(uid);
271
272         if (pid == 0)
273                 return getuid();
274
275         p = procfs_file_alloca(pid, "status");
276         f = fopen(p, "re");
277         if (!f) {
278                 if (errno == ENOENT)
279                         return -ESRCH;
280                 return -errno;
281         }
282
283         FOREACH_LINE(line, f, return -errno) {
284                 char *l;
285
286                 l = strstrip(line);
287
288                 if (startswith(l, field)) {
289                         l += strlen(field);
290                         l += strspn(l, WHITESPACE);
291
292                         l[strcspn(l, WHITESPACE)] = 0;
293
294                         return parse_uid(l, uid);
295                 }
296         }
297
298         return -EIO;
299 }
300
301 int get_process_uid(pid_t pid, uid_t *uid) {
302         return get_process_id(pid, "Uid:", uid);
303 }
304
305 int get_process_gid(pid_t pid, gid_t *gid) {
306         assert_cc(sizeof(uid_t) == sizeof(gid_t));
307         return get_process_id(pid, "Gid:", gid);
308 }
309
310 int get_process_cwd(pid_t pid, char **cwd) {
311         const char *p;
312
313         assert(pid >= 0);
314
315         p = procfs_file_alloca(pid, "cwd");
316
317         return get_process_link_contents(p, cwd);
318 }
319
320 int get_process_root(pid_t pid, char **root) {
321         const char *p;
322
323         assert(pid >= 0);
324
325         p = procfs_file_alloca(pid, "root");
326
327         return get_process_link_contents(p, root);
328 }
329
330 int get_process_environ(pid_t pid, char **env) {
331         _cleanup_fclose_ FILE *f = NULL;
332         _cleanup_free_ char *outcome = NULL;
333         int c;
334         const char *p;
335         size_t allocated = 0, sz = 0;
336
337         assert(pid >= 0);
338         assert(env);
339
340         p = procfs_file_alloca(pid, "environ");
341
342         f = fopen(p, "re");
343         if (!f) {
344                 if (errno == ENOENT)
345                         return -ESRCH;
346                 return -errno;
347         }
348
349         while ((c = fgetc(f)) != EOF) {
350                 if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
351                         return -ENOMEM;
352
353                 if (c == '\0')
354                         outcome[sz++] = '\n';
355                 else
356                         sz += cescape_char(c, outcome + sz);
357         }
358
359         if (!outcome) {
360                 outcome = strdup("");
361                 if (!outcome)
362                         return -ENOMEM;
363         } else
364         outcome[sz] = '\0';
365
366         *env = outcome;
367         outcome = NULL;
368
369         return 0;
370 }
371
372 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
373         int r;
374         _cleanup_free_ char *line = NULL;
375         long unsigned ppid;
376         const char *p;
377
378         assert(pid >= 0);
379         assert(_ppid);
380
381         if (pid == 0) {
382                 *_ppid = getppid();
383                 return 0;
384         }
385
386         p = procfs_file_alloca(pid, "stat");
387         r = read_one_line_file(p, &line);
388         if (r == -ENOENT)
389                 return -ESRCH;
390         if (r < 0)
391                 return r;
392
393         /* Let's skip the pid and comm fields. The latter is enclosed
394          * in () but does not escape any () in its value, so let's
395          * skip over it manually */
396
397         p = strrchr(line, ')');
398         if (!p)
399                 return -EIO;
400
401         p++;
402
403         if (sscanf(p, " "
404                    "%*c "  /* state */
405                    "%lu ", /* ppid */
406                    &ppid) != 1)
407                 return -EIO;
408
409         if ((long unsigned) (pid_t) ppid != ppid)
410                 return -ERANGE;
411
412         *_ppid = (pid_t) ppid;
413
414         return 0;
415 }
416 #endif // 0
417
418 int wait_for_terminate(pid_t pid, siginfo_t *status) {
419         siginfo_t dummy;
420
421         assert(pid >= 1);
422
423         if (!status)
424                 status = &dummy;
425
426         for (;;) {
427                 zero(*status);
428
429                 if (waitid(P_PID, pid, status, WEXITED) < 0) {
430
431                         if (errno == EINTR)
432                                 continue;
433
434                         return -errno;
435                 }
436
437                 return 0;
438         }
439 }
440
441 /*
442  * Return values:
443  * < 0 : wait_for_terminate() failed to get the state of the
444  *       process, the process was terminated by a signal, or
445  *       failed for an unknown reason.
446  * >=0 : The process terminated normally, and its exit code is
447  *       returned.
448  *
449  * That is, success is indicated by a return value of zero, and an
450  * error is indicated by a non-zero value.
451  *
452  * A warning is emitted if the process terminates abnormally,
453  * and also if it returns non-zero unless check_exit_code is true.
454  */
455 int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
456         int r;
457         siginfo_t status;
458
459         assert(name);
460         assert(pid > 1);
461
462         r = wait_for_terminate(pid, &status);
463         if (r < 0)
464                 return log_warning_errno(r, "Failed to wait for %s: %m", name);
465
466         if (status.si_code == CLD_EXITED) {
467                 if (status.si_status != 0)
468                         log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
469                                  "%s failed with error code %i.", name, status.si_status);
470                 else
471                         log_debug("%s succeeded.", name);
472
473                 return status.si_status;
474         } else if (status.si_code == CLD_KILLED ||
475                    status.si_code == CLD_DUMPED) {
476
477                 log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
478                 return -EPROTO;
479         }
480
481         log_warning("%s failed due to unknown reason.", name);
482         return -EPROTO;
483 }
484
485 /// UNNEEDED by elogind
486 #if 0
487 int kill_and_sigcont(pid_t pid, int sig) {
488         int r;
489
490         r = kill(pid, sig) < 0 ? -errno : 0;
491
492         if (r >= 0)
493                 kill(pid, SIGCONT);
494
495         return r;
496 }
497 #endif // 0
498
499 int getenv_for_pid(pid_t pid, const char *field, char **_value) {
500         _cleanup_fclose_ FILE *f = NULL;
501         char *value = NULL;
502         int r;
503         bool done = false;
504         size_t l;
505         const char *path;
506
507         assert(pid >= 0);
508         assert(field);
509         assert(_value);
510
511         path = procfs_file_alloca(pid, "environ");
512
513         f = fopen(path, "re");
514         if (!f) {
515                 if (errno == ENOENT)
516                         return -ESRCH;
517                 return -errno;
518         }
519
520         l = strlen(field);
521         r = 0;
522
523         do {
524                 char line[LINE_MAX];
525                 unsigned i;
526
527                 for (i = 0; i < sizeof(line)-1; i++) {
528                         int c;
529
530                         c = getc(f);
531                         if (_unlikely_(c == EOF)) {
532                                 done = true;
533                                 break;
534                         } else if (c == 0)
535                                 break;
536
537                         line[i] = c;
538                 }
539                 line[i] = 0;
540
541                 if (memcmp(line, field, l) == 0 && line[l] == '=') {
542                         value = strdup(line + l + 1);
543                         if (!value)
544                                 return -ENOMEM;
545
546                         r = 1;
547                         break;
548                 }
549
550         } while (!done);
551
552         *_value = value;
553         return r;
554 }
555
556 bool pid_is_unwaited(pid_t pid) {
557         /* Checks whether a PID is still valid at all, including a zombie */
558
559         if (pid <= 0)
560                 return false;
561
562         if (kill(pid, 0) >= 0)
563                 return true;
564
565         return errno != ESRCH;
566 }
567
568 bool pid_is_alive(pid_t pid) {
569         int r;
570
571         /* Checks whether a PID is still valid and not a zombie */
572
573         if (pid <= 0)
574                 return false;
575
576         r = get_process_state(pid);
577         if (r == -ESRCH || r == 'Z')
578                 return false;
579
580         return true;
581 }