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