]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/process-util.c
fileio: make get_status_field() more generic
[thirdparty/systemd.git] / src / basic / process-util.c
CommitLineData
0b452006
RC
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
0b452006
RC
31#include "fileio.h"
32#include "util.h"
33#include "log.h"
24882e06
LP
34#include "signal-util.h"
35#include "process-util.h"
0b452006
RC
36
37int 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");
a644184a 46
0b452006 47 r = read_one_line_file(p, &line);
a644184a
LP
48 if (r == -ENOENT)
49 return -ESRCH;
0b452006
RC
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
65int 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
81int 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");
a644184a
LP
93 if (!f) {
94 if (errno == ENOENT)
95 return -ESRCH;
0b452006 96 return -errno;
a644184a 97 }
0b452006
RC
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
177int is_kernel_thread(pid_t pid) {
178 const char *p;
179 size_t count;
180 char c;
181 bool eof;
182 FILE *f;
183
a6149b93 184 if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */
0b452006
RC
185 return 0;
186
a6149b93 187 assert(pid > 1);
0b452006
RC
188
189 p = procfs_file_alloca(pid, "cmdline");
190 f = fopen(p, "re");
a644184a
LP
191 if (!f) {
192 if (errno == ENOENT)
193 return -ESRCH;
0b452006 194 return -errno;
a644184a 195 }
0b452006
RC
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
209int get_process_capeff(pid_t pid, char **capeff) {
210 const char *p;
a644184a 211 int r;
0b452006
RC
212
213 assert(capeff);
214 assert(pid >= 0);
215
216 p = procfs_file_alloca(pid, "status");
217
c4cd1d4d 218 r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
a644184a
LP
219 if (r == -ENOENT)
220 return -ESRCH;
221
222 return r;
0b452006
RC
223}
224
225static int get_process_link_contents(const char *proc_file, char **name) {
226 int r;
227
228 assert(proc_file);
229 assert(name);
230
231 r = readlink_malloc(proc_file, name);
a644184a
LP
232 if (r == -ENOENT)
233 return -ESRCH;
0b452006 234 if (r < 0)
a644184a 235 return r;
0b452006
RC
236
237 return 0;
238}
239
240int get_process_exe(pid_t pid, char **name) {
241 const char *p;
242 char *d;
243 int r;
244
245 assert(pid >= 0);
246
247 p = procfs_file_alloca(pid, "exe");
248 r = get_process_link_contents(p, name);
249 if (r < 0)
250 return r;
251
252 d = endswith(*name, " (deleted)");
253 if (d)
254 *d = '\0';
255
256 return 0;
257}
258
259static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
260 _cleanup_fclose_ FILE *f = NULL;
261 char line[LINE_MAX];
262 const char *p;
263
264 assert(field);
265 assert(uid);
266
267 if (pid == 0)
268 return getuid();
269
270 p = procfs_file_alloca(pid, "status");
271 f = fopen(p, "re");
a644184a
LP
272 if (!f) {
273 if (errno == ENOENT)
274 return -ESRCH;
0b452006 275 return -errno;
a644184a 276 }
0b452006
RC
277
278 FOREACH_LINE(line, f, return -errno) {
279 char *l;
280
281 l = strstrip(line);
282
283 if (startswith(l, field)) {
284 l += strlen(field);
285 l += strspn(l, WHITESPACE);
286
287 l[strcspn(l, WHITESPACE)] = 0;
288
289 return parse_uid(l, uid);
290 }
291 }
292
293 return -EIO;
294}
295
296int get_process_uid(pid_t pid, uid_t *uid) {
297 return get_process_id(pid, "Uid:", uid);
298}
299
300int get_process_gid(pid_t pid, gid_t *gid) {
301 assert_cc(sizeof(uid_t) == sizeof(gid_t));
302 return get_process_id(pid, "Gid:", gid);
303}
304
305int get_process_cwd(pid_t pid, char **cwd) {
306 const char *p;
307
308 assert(pid >= 0);
309
310 p = procfs_file_alloca(pid, "cwd");
311
312 return get_process_link_contents(p, cwd);
313}
314
315int get_process_root(pid_t pid, char **root) {
316 const char *p;
317
318 assert(pid >= 0);
319
320 p = procfs_file_alloca(pid, "root");
321
322 return get_process_link_contents(p, root);
323}
324
325int get_process_environ(pid_t pid, char **env) {
326 _cleanup_fclose_ FILE *f = NULL;
327 _cleanup_free_ char *outcome = NULL;
328 int c;
329 const char *p;
330 size_t allocated = 0, sz = 0;
331
332 assert(pid >= 0);
333 assert(env);
334
335 p = procfs_file_alloca(pid, "environ");
336
337 f = fopen(p, "re");
a644184a
LP
338 if (!f) {
339 if (errno == ENOENT)
340 return -ESRCH;
0b452006 341 return -errno;
a644184a 342 }
0b452006
RC
343
344 while ((c = fgetc(f)) != EOF) {
345 if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
346 return -ENOMEM;
347
348 if (c == '\0')
349 outcome[sz++] = '\n';
350 else
351 sz += cescape_char(c, outcome + sz);
352 }
353
03c55bc0
LP
354 if (!outcome) {
355 outcome = strdup("");
356 if (!outcome)
357 return -ENOMEM;
358 } else
359 outcome[sz] = '\0';
de8763b6 360
0b452006
RC
361 *env = outcome;
362 outcome = NULL;
363
364 return 0;
365}
366
367int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
368 int r;
369 _cleanup_free_ char *line = NULL;
370 long unsigned ppid;
371 const char *p;
372
373 assert(pid >= 0);
374 assert(_ppid);
375
376 if (pid == 0) {
377 *_ppid = getppid();
378 return 0;
379 }
380
381 p = procfs_file_alloca(pid, "stat");
382 r = read_one_line_file(p, &line);
a644184a
LP
383 if (r == -ENOENT)
384 return -ESRCH;
0b452006
RC
385 if (r < 0)
386 return r;
387
388 /* Let's skip the pid and comm fields. The latter is enclosed
389 * in () but does not escape any () in its value, so let's
390 * skip over it manually */
391
392 p = strrchr(line, ')');
393 if (!p)
394 return -EIO;
395
396 p++;
397
398 if (sscanf(p, " "
399 "%*c " /* state */
400 "%lu ", /* ppid */
401 &ppid) != 1)
402 return -EIO;
403
404 if ((long unsigned) (pid_t) ppid != ppid)
405 return -ERANGE;
406
407 *_ppid = (pid_t) ppid;
408
409 return 0;
410}
411
412int wait_for_terminate(pid_t pid, siginfo_t *status) {
413 siginfo_t dummy;
414
415 assert(pid >= 1);
416
417 if (!status)
418 status = &dummy;
419
420 for (;;) {
421 zero(*status);
422
423 if (waitid(P_PID, pid, status, WEXITED) < 0) {
424
425 if (errno == EINTR)
426 continue;
427
428 return -errno;
429 }
430
431 return 0;
432 }
433}
434
435/*
436 * Return values:
437 * < 0 : wait_for_terminate() failed to get the state of the
438 * process, the process was terminated by a signal, or
439 * failed for an unknown reason.
440 * >=0 : The process terminated normally, and its exit code is
441 * returned.
442 *
443 * That is, success is indicated by a return value of zero, and an
444 * error is indicated by a non-zero value.
445 *
446 * A warning is emitted if the process terminates abnormally,
447 * and also if it returns non-zero unless check_exit_code is true.
448 */
449int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
450 int r;
451 siginfo_t status;
452
453 assert(name);
454 assert(pid > 1);
455
456 r = wait_for_terminate(pid, &status);
457 if (r < 0)
458 return log_warning_errno(r, "Failed to wait for %s: %m", name);
459
460 if (status.si_code == CLD_EXITED) {
461 if (status.si_status != 0)
462 log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
463 "%s failed with error code %i.", name, status.si_status);
464 else
465 log_debug("%s succeeded.", name);
466
467 return status.si_status;
468 } else if (status.si_code == CLD_KILLED ||
469 status.si_code == CLD_DUMPED) {
470
471 log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
472 return -EPROTO;
473 }
474
475 log_warning("%s failed due to unknown reason.", name);
476 return -EPROTO;
477}
478
479int kill_and_sigcont(pid_t pid, int sig) {
480 int r;
481
482 r = kill(pid, sig) < 0 ? -errno : 0;
483
484 if (r >= 0)
485 kill(pid, SIGCONT);
486
487 return r;
488}
489
490int getenv_for_pid(pid_t pid, const char *field, char **_value) {
491 _cleanup_fclose_ FILE *f = NULL;
492 char *value = NULL;
493 int r;
494 bool done = false;
495 size_t l;
496 const char *path;
497
498 assert(pid >= 0);
499 assert(field);
500 assert(_value);
501
502 path = procfs_file_alloca(pid, "environ");
503
504 f = fopen(path, "re");
a644184a
LP
505 if (!f) {
506 if (errno == ENOENT)
507 return -ESRCH;
0b452006 508 return -errno;
a644184a 509 }
0b452006
RC
510
511 l = strlen(field);
512 r = 0;
513
514 do {
515 char line[LINE_MAX];
516 unsigned i;
517
518 for (i = 0; i < sizeof(line)-1; i++) {
519 int c;
520
521 c = getc(f);
522 if (_unlikely_(c == EOF)) {
523 done = true;
524 break;
525 } else if (c == 0)
526 break;
527
528 line[i] = c;
529 }
530 line[i] = 0;
531
532 if (memcmp(line, field, l) == 0 && line[l] == '=') {
533 value = strdup(line + l + 1);
534 if (!value)
535 return -ENOMEM;
536
537 r = 1;
538 break;
539 }
540
541 } while (!done);
542
543 *_value = value;
544 return r;
545}
546
547bool pid_is_unwaited(pid_t pid) {
548 /* Checks whether a PID is still valid at all, including a zombie */
549
550 if (pid <= 0)
551 return false;
552
553 if (kill(pid, 0) >= 0)
554 return true;
555
556 return errno != ESRCH;
557}
558
559bool pid_is_alive(pid_t pid) {
560 int r;
561
562 /* Checks whether a PID is still valid and not a zombie */
563
564 if (pid <= 0)
565 return false;
566
567 r = get_process_state(pid);
a644184a 568 if (r == -ESRCH || r == 'Z')
0b452006
RC
569 return false;
570
571 return true;
572}