]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/process-util.c
sd-bus: cleanup ssh sessions (Closes: #8076)
[thirdparty/systemd.git] / src / basic / process-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
0b452006
RC
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
4f5dd394 21#include <ctype.h>
0b452006 22#include <errno.h>
11c3a366
TA
23#include <limits.h>
24#include <linux/oom.h>
7b3e062c 25#include <sched.h>
0b452006 26#include <signal.h>
4f5dd394
LP
27#include <stdbool.h>
28#include <stdio.h>
35bbbf85 29#include <stdio_ext.h>
11c3a366 30#include <stdlib.h>
4f5dd394 31#include <string.h>
9bfaffd5 32#include <sys/mman.h>
7b3e062c 33#include <sys/personality.h>
405f8907 34#include <sys/prctl.h>
4f5dd394
LP
35#include <sys/types.h>
36#include <sys/wait.h>
11c3a366 37#include <syslog.h>
4f5dd394 38#include <unistd.h>
349cc4a5 39#if HAVE_VALGRIND_VALGRIND_H
dcadc967
EV
40#include <valgrind/valgrind.h>
41#endif
0b452006 42
b5efdb8a 43#include "alloc-util.h"
6e5f1b57 44#include "architecture.h"
4f5dd394 45#include "escape.h"
3ffd4af2 46#include "fd-util.h"
0b452006 47#include "fileio.h"
f4f15635 48#include "fs-util.h"
7b3e062c 49#include "ioprio.h"
0b452006 50#include "log.h"
11c3a366
TA
51#include "macro.h"
52#include "missing.h"
93cc7779 53#include "process-util.h"
8869a0b4 54#include "raw-clone.h"
93cc7779 55#include "signal-util.h"
1359fffa 56#include "stat-util.h"
7b3e062c 57#include "string-table.h"
07630cea 58#include "string-util.h"
4c253ed1 59#include "terminal-util.h"
b1d4f8e1 60#include "user-util.h"
4f5dd394 61#include "util.h"
0b452006
RC
62
63int get_process_state(pid_t pid) {
64 const char *p;
65 char state;
66 int r;
67 _cleanup_free_ char *line = NULL;
68
69 assert(pid >= 0);
70
71 p = procfs_file_alloca(pid, "stat");
a644184a 72
0b452006 73 r = read_one_line_file(p, &line);
a644184a
LP
74 if (r == -ENOENT)
75 return -ESRCH;
0b452006
RC
76 if (r < 0)
77 return r;
78
79 p = strrchr(line, ')');
80 if (!p)
81 return -EIO;
82
83 p++;
84
85 if (sscanf(p, " %c", &state) != 1)
86 return -EIO;
87
88 return (unsigned char) state;
89}
90
91int get_process_comm(pid_t pid, char **name) {
92 const char *p;
93 int r;
94
95 assert(name);
96 assert(pid >= 0);
97
98 p = procfs_file_alloca(pid, "comm");
99
100 r = read_one_line_file(p, name);
101 if (r == -ENOENT)
102 return -ESRCH;
103
104 return r;
105}
106
107int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
108 _cleanup_fclose_ FILE *f = NULL;
ba4cd7e2 109 bool space = false;
c0534780 110 char *k, *ans = NULL;
0b452006
RC
111 const char *p;
112 int c;
113
114 assert(line);
115 assert(pid >= 0);
116
69281c49
LP
117 /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing
118 * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most
119 * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If
120 * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a
121 * command line that resolves to the empty string will return the "comm" name of the process instead.
122 *
123 * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and
c0534780 124 * comm_fallback is false). Returns 0 and sets *line otherwise. */
69281c49 125
0b452006
RC
126 p = procfs_file_alloca(pid, "cmdline");
127
128 f = fopen(p, "re");
a644184a
LP
129 if (!f) {
130 if (errno == ENOENT)
131 return -ESRCH;
0b452006 132 return -errno;
a644184a 133 }
0b452006 134
35bbbf85
LP
135 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
136
69281c49
LP
137 if (max_length == 1) {
138
139 /* If there's only room for one byte, return the empty string */
c0534780
ZJS
140 ans = new0(char, 1);
141 if (!ans)
69281c49
LP
142 return -ENOMEM;
143
c0534780 144 *line = ans;
69281c49
LP
145 return 0;
146
147 } else if (max_length == 0) {
0b452006
RC
148 size_t len = 0, allocated = 0;
149
150 while ((c = getc(f)) != EOF) {
151
c0534780
ZJS
152 if (!GREEDY_REALLOC(ans, allocated, len+3)) {
153 free(ans);
0b452006
RC
154 return -ENOMEM;
155 }
156
ba4cd7e2
MP
157 if (isprint(c)) {
158 if (space) {
c0534780 159 ans[len++] = ' ';
ba4cd7e2
MP
160 space = false;
161 }
162
c0534780 163 ans[len++] = c;
69281c49 164 } else if (len > 0)
ba4cd7e2
MP
165 space = true;
166 }
0b452006
RC
167
168 if (len > 0)
c0534780 169 ans[len] = '\0';
b09df4e2 170 else
c0534780 171 ans = mfree(ans);
0b452006
RC
172
173 } else {
69281c49 174 bool dotdotdot = false;
0b452006
RC
175 size_t left;
176
c0534780
ZJS
177 ans = new(char, max_length);
178 if (!ans)
0b452006
RC
179 return -ENOMEM;
180
c0534780 181 k = ans;
0b452006
RC
182 left = max_length;
183 while ((c = getc(f)) != EOF) {
184
185 if (isprint(c)) {
69281c49 186
0b452006 187 if (space) {
69281c49
LP
188 if (left <= 2) {
189 dotdotdot = true;
0b452006 190 break;
69281c49 191 }
0b452006
RC
192
193 *(k++) = ' ';
194 left--;
195 space = false;
196 }
197
69281c49
LP
198 if (left <= 1) {
199 dotdotdot = true;
0b452006 200 break;
69281c49 201 }
0b452006
RC
202
203 *(k++) = (char) c;
204 left--;
c0534780 205 } else if (k > ans)
0b452006
RC
206 space = true;
207 }
208
69281c49
LP
209 if (dotdotdot) {
210 if (max_length <= 4) {
c0534780 211 k = ans;
69281c49
LP
212 left = max_length;
213 } else {
c0534780 214 k = ans + max_length - 4;
69281c49
LP
215 left = 4;
216
217 /* Eat up final spaces */
c0534780 218 while (k > ans && isspace(k[-1])) {
69281c49
LP
219 k--;
220 left++;
221 }
222 }
223
224 strncpy(k, "...", left-1);
b09df4e2 225 k[left-1] = 0;
0b452006
RC
226 } else
227 *k = 0;
228 }
229
230 /* Kernel threads have no argv[] */
c0534780 231 if (isempty(ans)) {
0b452006
RC
232 _cleanup_free_ char *t = NULL;
233 int h;
234
c0534780 235 free(ans);
0b452006
RC
236
237 if (!comm_fallback)
238 return -ENOENT;
239
240 h = get_process_comm(pid, &t);
241 if (h < 0)
242 return h;
243
69281c49 244 if (max_length == 0)
c0534780 245 ans = strjoin("[", t, "]");
69281c49
LP
246 else {
247 size_t l;
248
249 l = strlen(t);
250
251 if (l + 3 <= max_length)
c0534780 252 ans = strjoin("[", t, "]");
69281c49
LP
253 else if (max_length <= 6) {
254
c0534780
ZJS
255 ans = new(char, max_length);
256 if (!ans)
69281c49
LP
257 return -ENOMEM;
258
c0534780
ZJS
259 memcpy(ans, "[...]", max_length-1);
260 ans[max_length-1] = 0;
69281c49
LP
261 } else {
262 char *e;
263
264 t[max_length - 6] = 0;
265
266 /* Chop off final spaces */
267 e = strchr(t, 0);
268 while (e > t && isspace(e[-1]))
269 e--;
270 *e = 0;
271
c0534780 272 ans = strjoin("[", t, "...]");
69281c49
LP
273 }
274 }
c0534780 275 if (!ans)
0b452006
RC
276 return -ENOMEM;
277 }
278
c0534780 279 *line = ans;
0b452006
RC
280 return 0;
281}
282
9bfaffd5
LP
283int rename_process(const char name[]) {
284 static size_t mm_size = 0;
285 static char *mm = NULL;
286 bool truncated = false;
287 size_t l;
288
289 /* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's
290 * internally used name of the process. For the first one a limit of 16 chars applies; to the second one in
291 * many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded;
292 * to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be
293 * truncated.
294 *
295 * Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */
296
297 if (isempty(name))
298 return -EINVAL; /* let's not confuse users unnecessarily with an empty name */
405f8907 299
1096bb8a
LP
300 if (!is_main_thread())
301 return -EPERM; /* Let's not allow setting the process name from other threads than the main one, as we
302 * cache things without locking, and we make assumptions that PR_SET_NAME sets the
303 * process name that isn't correct on any other threads */
304
9bfaffd5 305 l = strlen(name);
405f8907 306
5a8af747
LP
307 /* First step, change the comm field. The main thread's comm is identical to the process comm. This means we
308 * can use PR_SET_NAME, which sets the thread name for the calling thread. */
309 if (prctl(PR_SET_NAME, name) < 0)
310 log_debug_errno(errno, "PR_SET_NAME failed: %m");
9bfaffd5
LP
311 if (l > 15) /* Linux process names can be 15 chars at max */
312 truncated = true;
313
314 /* Second step, change glibc's ID of the process name. */
315 if (program_invocation_name) {
316 size_t k;
317
318 k = strlen(program_invocation_name);
319 strncpy(program_invocation_name, name, k);
320 if (l > k)
321 truncated = true;
322 }
323
324 /* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
325 * has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
13e785f7 326 * the end. This is the best option for changing /proc/self/cmdline. */
01f989c6
JW
327
328 /* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
329 * CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
330 * present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
331 * PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
332 * mmap() is not. */
333 if (geteuid() != 0)
334 log_debug("Skipping PR_SET_MM, as we don't have privileges.");
335 else if (mm_size < l+1) {
9bfaffd5
LP
336 size_t nn_size;
337 char *nn;
338
9bfaffd5
LP
339 nn_size = PAGE_ALIGN(l+1);
340 nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
341 if (nn == MAP_FAILED) {
342 log_debug_errno(errno, "mmap() failed: %m");
343 goto use_saved_argv;
344 }
405f8907 345
9bfaffd5
LP
346 strncpy(nn, name, nn_size);
347
348 /* Now, let's tell the kernel about this new memory */
349 if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
350 log_debug_errno(errno, "PR_SET_MM_ARG_START failed, proceeding without: %m");
351 (void) munmap(nn, nn_size);
352 goto use_saved_argv;
353 }
354
355 /* And update the end pointer to the new end, too. If this fails, we don't really know what to do, it's
356 * pretty unlikely that we can rollback, hence we'll just accept the failure, and continue. */
357 if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
358 log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
359
360 if (mm)
361 (void) munmap(mm, mm_size);
362
363 mm = nn;
364 mm_size = nn_size;
01f989c6 365 } else {
9bfaffd5
LP
366 strncpy(mm, name, mm_size);
367
01f989c6
JW
368 /* Update the end pointer, continuing regardless of any failure. */
369 if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
370 log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
371 }
372
9bfaffd5
LP
373use_saved_argv:
374 /* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
375 * it still looks here */
405f8907
LP
376
377 if (saved_argc > 0) {
378 int i;
379
9bfaffd5
LP
380 if (saved_argv[0]) {
381 size_t k;
382
383 k = strlen(saved_argv[0]);
384 strncpy(saved_argv[0], name, k);
385 if (l > k)
386 truncated = true;
387 }
405f8907
LP
388
389 for (i = 1; i < saved_argc; i++) {
390 if (!saved_argv[i])
391 break;
392
393 memzero(saved_argv[i], strlen(saved_argv[i]));
394 }
395 }
9bfaffd5
LP
396
397 return !truncated;
405f8907
LP
398}
399
0b452006
RC
400int is_kernel_thread(pid_t pid) {
401 const char *p;
402 size_t count;
403 char c;
404 bool eof;
405 FILE *f;
406
4c701096 407 if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
0b452006
RC
408 return 0;
409
a6149b93 410 assert(pid > 1);
0b452006
RC
411
412 p = procfs_file_alloca(pid, "cmdline");
413 f = fopen(p, "re");
a644184a
LP
414 if (!f) {
415 if (errno == ENOENT)
416 return -ESRCH;
0b452006 417 return -errno;
a644184a 418 }
0b452006 419
35bbbf85
LP
420 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
421
0b452006
RC
422 count = fread(&c, 1, 1, f);
423 eof = feof(f);
424 fclose(f);
425
426 /* Kernel threads have an empty cmdline */
427
428 if (count <= 0)
429 return eof ? 1 : -errno;
430
431 return 0;
432}
433
434int get_process_capeff(pid_t pid, char **capeff) {
435 const char *p;
a644184a 436 int r;
0b452006
RC
437
438 assert(capeff);
439 assert(pid >= 0);
440
441 p = procfs_file_alloca(pid, "status");
442
c4cd1d4d 443 r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
a644184a
LP
444 if (r == -ENOENT)
445 return -ESRCH;
446
447 return r;
0b452006
RC
448}
449
450static int get_process_link_contents(const char *proc_file, char **name) {
451 int r;
452
453 assert(proc_file);
454 assert(name);
455
456 r = readlink_malloc(proc_file, name);
a644184a
LP
457 if (r == -ENOENT)
458 return -ESRCH;
0b452006 459 if (r < 0)
a644184a 460 return r;
0b452006
RC
461
462 return 0;
463}
464
465int get_process_exe(pid_t pid, char **name) {
466 const char *p;
467 char *d;
468 int r;
469
470 assert(pid >= 0);
471
472 p = procfs_file_alloca(pid, "exe");
473 r = get_process_link_contents(p, name);
474 if (r < 0)
475 return r;
476
477 d = endswith(*name, " (deleted)");
478 if (d)
479 *d = '\0';
480
481 return 0;
482}
483
484static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
485 _cleanup_fclose_ FILE *f = NULL;
486 char line[LINE_MAX];
487 const char *p;
488
489 assert(field);
490 assert(uid);
491
07b38ba5 492 if (pid < 0)
6f8cbcdb
LP
493 return -EINVAL;
494
0b452006
RC
495 p = procfs_file_alloca(pid, "status");
496 f = fopen(p, "re");
a644184a
LP
497 if (!f) {
498 if (errno == ENOENT)
499 return -ESRCH;
0b452006 500 return -errno;
a644184a 501 }
0b452006 502
35bbbf85
LP
503 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
504
0b452006
RC
505 FOREACH_LINE(line, f, return -errno) {
506 char *l;
507
508 l = strstrip(line);
509
510 if (startswith(l, field)) {
511 l += strlen(field);
512 l += strspn(l, WHITESPACE);
513
514 l[strcspn(l, WHITESPACE)] = 0;
515
516 return parse_uid(l, uid);
517 }
518 }
519
520 return -EIO;
521}
522
523int get_process_uid(pid_t pid, uid_t *uid) {
6f8cbcdb
LP
524
525 if (pid == 0 || pid == getpid_cached()) {
526 *uid = getuid();
527 return 0;
528 }
529
0b452006
RC
530 return get_process_id(pid, "Uid:", uid);
531}
532
533int get_process_gid(pid_t pid, gid_t *gid) {
6f8cbcdb
LP
534
535 if (pid == 0 || pid == getpid_cached()) {
536 *gid = getgid();
537 return 0;
538 }
539
0b452006
RC
540 assert_cc(sizeof(uid_t) == sizeof(gid_t));
541 return get_process_id(pid, "Gid:", gid);
542}
543
544int get_process_cwd(pid_t pid, char **cwd) {
545 const char *p;
546
547 assert(pid >= 0);
548
549 p = procfs_file_alloca(pid, "cwd");
550
551 return get_process_link_contents(p, cwd);
552}
553
554int get_process_root(pid_t pid, char **root) {
555 const char *p;
556
557 assert(pid >= 0);
558
559 p = procfs_file_alloca(pid, "root");
560
561 return get_process_link_contents(p, root);
562}
563
564int get_process_environ(pid_t pid, char **env) {
565 _cleanup_fclose_ FILE *f = NULL;
566 _cleanup_free_ char *outcome = NULL;
567 int c;
568 const char *p;
569 size_t allocated = 0, sz = 0;
570
571 assert(pid >= 0);
572 assert(env);
573
574 p = procfs_file_alloca(pid, "environ");
575
576 f = fopen(p, "re");
a644184a
LP
577 if (!f) {
578 if (errno == ENOENT)
579 return -ESRCH;
0b452006 580 return -errno;
a644184a 581 }
0b452006 582
35bbbf85
LP
583 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
584
0b452006
RC
585 while ((c = fgetc(f)) != EOF) {
586 if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
587 return -ENOMEM;
588
589 if (c == '\0')
590 outcome[sz++] = '\n';
591 else
592 sz += cescape_char(c, outcome + sz);
593 }
594
03c55bc0
LP
595 if (!outcome) {
596 outcome = strdup("");
597 if (!outcome)
598 return -ENOMEM;
599 } else
600 outcome[sz] = '\0';
de8763b6 601
0b452006
RC
602 *env = outcome;
603 outcome = NULL;
604
605 return 0;
606}
607
6bc73acb 608int get_process_ppid(pid_t pid, pid_t *_ppid) {
0b452006
RC
609 int r;
610 _cleanup_free_ char *line = NULL;
611 long unsigned ppid;
612 const char *p;
613
614 assert(pid >= 0);
615 assert(_ppid);
616
6f8cbcdb 617 if (pid == 0 || pid == getpid_cached()) {
0b452006
RC
618 *_ppid = getppid();
619 return 0;
620 }
621
622 p = procfs_file_alloca(pid, "stat");
623 r = read_one_line_file(p, &line);
a644184a
LP
624 if (r == -ENOENT)
625 return -ESRCH;
0b452006
RC
626 if (r < 0)
627 return r;
628
629 /* Let's skip the pid and comm fields. The latter is enclosed
630 * in () but does not escape any () in its value, so let's
631 * skip over it manually */
632
633 p = strrchr(line, ')');
634 if (!p)
635 return -EIO;
636
637 p++;
638
639 if (sscanf(p, " "
640 "%*c " /* state */
641 "%lu ", /* ppid */
642 &ppid) != 1)
643 return -EIO;
644
645 if ((long unsigned) (pid_t) ppid != ppid)
646 return -ERANGE;
647
648 *_ppid = (pid_t) ppid;
649
650 return 0;
651}
652
653int wait_for_terminate(pid_t pid, siginfo_t *status) {
654 siginfo_t dummy;
655
656 assert(pid >= 1);
657
658 if (!status)
659 status = &dummy;
660
661 for (;;) {
662 zero(*status);
663
664 if (waitid(P_PID, pid, status, WEXITED) < 0) {
665
666 if (errno == EINTR)
667 continue;
668
3f0083a2 669 return negative_errno();
0b452006
RC
670 }
671
672 return 0;
673 }
674}
675
676/*
677 * Return values:
678 * < 0 : wait_for_terminate() failed to get the state of the
679 * process, the process was terminated by a signal, or
680 * failed for an unknown reason.
681 * >=0 : The process terminated normally, and its exit code is
682 * returned.
683 *
684 * That is, success is indicated by a return value of zero, and an
685 * error is indicated by a non-zero value.
686 *
687 * A warning is emitted if the process terminates abnormally,
688 * and also if it returns non-zero unless check_exit_code is true.
689 */
7d4904fe
LP
690int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) {
691 _cleanup_free_ char *buffer = NULL;
0b452006 692 siginfo_t status;
7d4904fe 693 int r, prio;
0b452006 694
0b452006
RC
695 assert(pid > 1);
696
7d4904fe
LP
697 if (!name) {
698 r = get_process_comm(pid, &buffer);
699 if (r < 0)
700 log_debug_errno(r, "Failed to acquire process name of " PID_FMT ", ignoring: %m", pid);
701 else
702 name = buffer;
703 }
704
705 prio = flags & WAIT_LOG_ABNORMAL ? LOG_ERR : LOG_DEBUG;
706
0b452006
RC
707 r = wait_for_terminate(pid, &status);
708 if (r < 0)
7d4904fe 709 return log_full_errno(prio, r, "Failed to wait for %s: %m", strna(name));
0b452006
RC
710
711 if (status.si_code == CLD_EXITED) {
7d4904fe
LP
712 if (status.si_status != EXIT_SUCCESS)
713 log_full(flags & WAIT_LOG_NON_ZERO_EXIT_STATUS ? LOG_ERR : LOG_DEBUG,
714 "%s failed with exit status %i.", strna(name), status.si_status);
0b452006
RC
715 else
716 log_debug("%s succeeded.", name);
717
718 return status.si_status;
7d4904fe 719
3742095b 720 } else if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED)) {
0b452006 721
7d4904fe 722 log_full(prio, "%s terminated by signal %s.", strna(name), signal_to_string(status.si_status));
0b452006
RC
723 return -EPROTO;
724 }
725
7d4904fe 726 log_full(prio, "%s failed due to unknown reason.", strna(name));
0b452006
RC
727 return -EPROTO;
728}
729
d5641e0d
KW
730/*
731 * Return values:
732 * < 0 : wait_for_terminate_with_timeout() failed to get the state of the
733 * process, the process timed out, the process was terminated by a
734 * signal, or failed for an unknown reason.
735 * >=0 : The process terminated normally with no failures.
736 *
737 * Success is indicated by a return value of zero, a timeout is indicated
738 * by ETIMEDOUT, and all other child failure states are indicated by error
739 * is indicated by a non-zero value.
740 */
741int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
742 sigset_t mask;
743 int r;
744 usec_t until;
745
746 assert_se(sigemptyset(&mask) == 0);
747 assert_se(sigaddset(&mask, SIGCHLD) == 0);
748
749 /* Drop into a sigtimewait-based timeout. Waiting for the
750 * pid to exit. */
751 until = now(CLOCK_MONOTONIC) + timeout;
752 for (;;) {
753 usec_t n;
754 siginfo_t status = {};
755 struct timespec ts;
756
757 n = now(CLOCK_MONOTONIC);
758 if (n >= until)
759 break;
760
761 r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0;
762 /* Assuming we woke due to the child exiting. */
763 if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
764 if (status.si_pid == pid) {
765 /* This is the correct child.*/
766 if (status.si_code == CLD_EXITED)
767 return (status.si_status == 0) ? 0 : -EPROTO;
768 else
769 return -EPROTO;
770 }
771 }
772 /* Not the child, check for errors and proceed appropriately */
773 if (r < 0) {
774 switch (r) {
775 case -EAGAIN:
776 /* Timed out, child is likely hung. */
777 return -ETIMEDOUT;
778 case -EINTR:
779 /* Received a different signal and should retry */
780 continue;
781 default:
782 /* Return any unexpected errors */
783 return r;
784 }
785 }
786 }
787
788 return -EPROTO;
789}
790
89c9030d
LP
791void sigkill_wait(pid_t pid) {
792 assert(pid > 1);
793
794 if (kill(pid, SIGKILL) > 0)
795 (void) wait_for_terminate(pid, NULL);
796}
797
798void sigkill_waitp(pid_t *pid) {
dfd14786
LP
799 PROTECT_ERRNO;
800
4d0d3d41
LP
801 if (!pid)
802 return;
803 if (*pid <= 1)
804 return;
805
89c9030d 806 sigkill_wait(*pid);
4d0d3d41
LP
807}
808
392cf1d0
SL
809void sigterm_wait(pid_t pid) {
810 assert(pid > 1);
811
812 if (kill_and_sigcont(pid, SIGTERM) > 0)
813 (void) wait_for_terminate(pid, NULL);
814}
815
0b452006
RC
816int kill_and_sigcont(pid_t pid, int sig) {
817 int r;
818
819 r = kill(pid, sig) < 0 ? -errno : 0;
820
26f417d3
LP
821 /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
822 * affected by a process being suspended anyway. */
a3d8d68c 823 if (r >= 0 && !IN_SET(sig, SIGCONT, SIGKILL))
26f417d3 824 (void) kill(pid, SIGCONT);
0b452006
RC
825
826 return r;
827}
828
829int getenv_for_pid(pid_t pid, const char *field, char **_value) {
830 _cleanup_fclose_ FILE *f = NULL;
831 char *value = NULL;
832 int r;
833 bool done = false;
834 size_t l;
835 const char *path;
836
837 assert(pid >= 0);
838 assert(field);
839 assert(_value);
840
841 path = procfs_file_alloca(pid, "environ");
842
843 f = fopen(path, "re");
a644184a
LP
844 if (!f) {
845 if (errno == ENOENT)
846 return -ESRCH;
0b452006 847 return -errno;
a644184a 848 }
0b452006 849
35bbbf85
LP
850 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
851
0b452006
RC
852 l = strlen(field);
853 r = 0;
854
855 do {
856 char line[LINE_MAX];
857 unsigned i;
858
859 for (i = 0; i < sizeof(line)-1; i++) {
860 int c;
861
862 c = getc(f);
863 if (_unlikely_(c == EOF)) {
864 done = true;
865 break;
866 } else if (c == 0)
867 break;
868
869 line[i] = c;
870 }
871 line[i] = 0;
872
041b5ae1 873 if (strneq(line, field, l) && line[l] == '=') {
0b452006
RC
874 value = strdup(line + l + 1);
875 if (!value)
876 return -ENOMEM;
877
878 r = 1;
879 break;
880 }
881
882 } while (!done);
883
884 *_value = value;
885 return r;
886}
887
888bool pid_is_unwaited(pid_t pid) {
889 /* Checks whether a PID is still valid at all, including a zombie */
890
07b38ba5 891 if (pid < 0)
0b452006
RC
892 return false;
893
5fd9b2c5
LP
894 if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
895 return true;
896
6f8cbcdb
LP
897 if (pid == getpid_cached())
898 return true;
899
0b452006
RC
900 if (kill(pid, 0) >= 0)
901 return true;
902
903 return errno != ESRCH;
904}
905
906bool pid_is_alive(pid_t pid) {
907 int r;
908
909 /* Checks whether a PID is still valid and not a zombie */
910
07b38ba5 911 if (pid < 0)
0b452006
RC
912 return false;
913
5fd9b2c5
LP
914 if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
915 return true;
916
6f8cbcdb
LP
917 if (pid == getpid_cached())
918 return true;
919
0b452006 920 r = get_process_state(pid);
4c701096 921 if (IN_SET(r, -ESRCH, 'Z'))
0b452006
RC
922 return false;
923
924 return true;
925}
d4510856 926
1359fffa
MS
927int pid_from_same_root_fs(pid_t pid) {
928 const char *root;
929
07b38ba5 930 if (pid < 0)
6f8cbcdb
LP
931 return false;
932
933 if (pid == 0 || pid == getpid_cached())
934 return true;
1359fffa
MS
935
936 root = procfs_file_alloca(pid, "root");
937
e3f791a2 938 return files_same(root, "/proc/1/root", 0);
1359fffa
MS
939}
940
d4510856
LP
941bool is_main_thread(void) {
942 static thread_local int cached = 0;
943
944 if (_unlikely_(cached == 0))
df0ff127 945 cached = getpid_cached() == gettid() ? 1 : -1;
d4510856
LP
946
947 return cached > 0;
948}
7b3e062c
LP
949
950noreturn void freeze(void) {
951
3da48d7a
EV
952 log_close();
953
7b3e062c
LP
954 /* Make sure nobody waits for us on a socket anymore */
955 close_all_fds(NULL, 0);
956
957 sync();
958
8647283e
MS
959 /* Let's not freeze right away, but keep reaping zombies. */
960 for (;;) {
961 int r;
962 siginfo_t si = {};
963
964 r = waitid(P_ALL, 0, &si, WEXITED);
965 if (r < 0 && errno != EINTR)
966 break;
967 }
968
969 /* waitid() failed with an unexpected error, things are really borked. Freeze now! */
7b3e062c
LP
970 for (;;)
971 pause();
972}
973
974bool oom_score_adjust_is_valid(int oa) {
975 return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
976}
977
978unsigned long personality_from_string(const char *p) {
6e5f1b57 979 int architecture;
7b3e062c 980
0c0fea07
LP
981 if (!p)
982 return PERSONALITY_INVALID;
983
6e5f1b57
LP
984 /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just
985 * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for
986 * the same register size. */
987
988 architecture = architecture_from_string(p);
989 if (architecture < 0)
990 return PERSONALITY_INVALID;
7b3e062c 991
0c0fea07 992 if (architecture == native_architecture())
7b3e062c 993 return PER_LINUX;
0c0fea07
LP
994#ifdef SECONDARY_ARCHITECTURE
995 if (architecture == SECONDARY_ARCHITECTURE)
f2d1736c 996 return PER_LINUX32;
7b3e062c
LP
997#endif
998
999 return PERSONALITY_INVALID;
1000}
1001
1002const char* personality_to_string(unsigned long p) {
6e5f1b57 1003 int architecture = _ARCHITECTURE_INVALID;
7b3e062c 1004
7b3e062c 1005 if (p == PER_LINUX)
0c0fea07
LP
1006 architecture = native_architecture();
1007#ifdef SECONDARY_ARCHITECTURE
6e5f1b57 1008 else if (p == PER_LINUX32)
0c0fea07 1009 architecture = SECONDARY_ARCHITECTURE;
7b3e062c
LP
1010#endif
1011
6e5f1b57
LP
1012 if (architecture < 0)
1013 return NULL;
1014
1015 return architecture_to_string(architecture);
7b3e062c
LP
1016}
1017
21022b9d
LP
1018int safe_personality(unsigned long p) {
1019 int ret;
1020
1021 /* So here's the deal, personality() is weirdly defined by glibc. In some cases it returns a failure via errno,
1022 * and in others as negative return value containing an errno-like value. Let's work around this: this is a
1023 * wrapper that uses errno if it is set, and uses the return value otherwise. And then it sets both errno and
1024 * the return value indicating the same issue, so that we are definitely on the safe side.
1025 *
1026 * See https://github.com/systemd/systemd/issues/6737 */
1027
1028 errno = 0;
1029 ret = personality(p);
1030 if (ret < 0) {
1031 if (errno != 0)
1032 return -errno;
1033
1034 errno = -ret;
1035 }
1036
1037 return ret;
1038}
1039
e8132d63
LP
1040int opinionated_personality(unsigned long *ret) {
1041 int current;
1042
1043 /* Returns the current personality, or PERSONALITY_INVALID if we can't determine it. This function is a bit
1044 * opinionated though, and ignores all the finer-grained bits and exotic personalities, only distinguishing the
1045 * two most relevant personalities: PER_LINUX and PER_LINUX32. */
1046
21022b9d 1047 current = safe_personality(PERSONALITY_INVALID);
e8132d63 1048 if (current < 0)
21022b9d 1049 return current;
e8132d63
LP
1050
1051 if (((unsigned long) current & 0xffff) == PER_LINUX32)
1052 *ret = PER_LINUX32;
1053 else
1054 *ret = PER_LINUX;
1055
1056 return 0;
1057}
1058
dcadc967 1059void valgrind_summary_hack(void) {
349cc4a5 1060#if HAVE_VALGRIND_VALGRIND_H
df0ff127 1061 if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
dcadc967 1062 pid_t pid;
8869a0b4 1063 pid = raw_clone(SIGCHLD);
dcadc967
EV
1064 if (pid < 0)
1065 log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
1066 else if (pid == 0)
1067 exit(EXIT_SUCCESS);
1068 else {
1069 log_info("Spawned valgrind helper as PID "PID_FMT".", pid);
1070 (void) wait_for_terminate(pid, NULL);
1071 }
1072 }
1073#endif
1074}
1075
291d565a
LP
1076int pid_compare_func(const void *a, const void *b) {
1077 const pid_t *p = a, *q = b;
1078
1079 /* Suitable for usage in qsort() */
1080
1081 if (*p < *q)
1082 return -1;
1083 if (*p > *q)
1084 return 1;
1085 return 0;
1086}
1087
7f452159
LP
1088int ioprio_parse_priority(const char *s, int *ret) {
1089 int i, r;
1090
1091 assert(s);
1092 assert(ret);
1093
1094 r = safe_atoi(s, &i);
1095 if (r < 0)
1096 return r;
1097
1098 if (!ioprio_priority_is_valid(i))
1099 return -EINVAL;
1100
1101 *ret = i;
1102 return 0;
1103}
1104
5c30a6d2
LP
1105/* The cached PID, possible values:
1106 *
1107 * == UNSET [0] → cache not initialized yet
1108 * == BUSY [-1] → some thread is initializing it at the moment
1109 * any other → the cached PID
1110 */
1111
1112#define CACHED_PID_UNSET ((pid_t) 0)
1113#define CACHED_PID_BUSY ((pid_t) -1)
1114
1115static pid_t cached_pid = CACHED_PID_UNSET;
1116
799a960d 1117void reset_cached_pid(void) {
5c30a6d2
LP
1118 /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */
1119 cached_pid = CACHED_PID_UNSET;
1120}
1121
1122/* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc
1123 * headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against
1124 * libpthread, as it is part of glibc anyway. */
1125extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void * __dso_handle);
1126extern void* __dso_handle __attribute__ ((__weak__));
1127
1128pid_t getpid_cached(void) {
1129 pid_t current_value;
1130
1131 /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
1132 * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally
1133 * cached. Starting with 2.24 getpid() started to become prohibitively expensive when used for detecting when
1134 * objects were used across fork()s. With this caching the old behaviour is somewhat restored.
1135 *
1136 * https://bugzilla.redhat.com/show_bug.cgi?id=1443976
a4041e4f 1137 * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e
5c30a6d2
LP
1138 */
1139
1140 current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY);
1141
1142 switch (current_value) {
1143
1144 case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */
1145 pid_t new_pid;
1146
996def17 1147 new_pid = raw_getpid();
5c30a6d2
LP
1148
1149 if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
1150 /* OOM? Let's try again later */
1151 cached_pid = CACHED_PID_UNSET;
1152 return new_pid;
1153 }
1154
1155 cached_pid = new_pid;
1156 return new_pid;
1157 }
1158
1159 case CACHED_PID_BUSY: /* Somebody else is currently initializing */
996def17 1160 return raw_getpid();
5c30a6d2
LP
1161
1162 default: /* Properly initialized */
1163 return current_value;
1164 }
1165}
1166
fba868fa
LP
1167int must_be_root(void) {
1168
1169 if (geteuid() == 0)
1170 return 0;
1171
1172 log_error("Need to be root.");
1173 return -EPERM;
1174}
1175
4c253ed1
LP
1176int safe_fork_full(
1177 const char *name,
1178 const int except_fds[],
1179 size_t n_except_fds,
1180 ForkFlags flags,
1181 pid_t *ret_pid) {
1182
1183 pid_t original_pid, pid;
1f5d1e02 1184 sigset_t saved_ss, ss;
a41f6217 1185 bool block_signals = false;
b6e1fff1 1186 int prio, r;
4c253ed1
LP
1187
1188 /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
1189 * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
1190
b6e1fff1
LP
1191 prio = flags & FORK_LOG ? LOG_ERR : LOG_DEBUG;
1192
4c253ed1
LP
1193 original_pid = getpid_cached();
1194
1f5d1e02 1195 if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) {
4c253ed1 1196
1f5d1e02
LP
1197 /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can
1198 * be sure that SIGTERMs are not lost we might send to the child. */
4c253ed1 1199
4c253ed1 1200 if (sigfillset(&ss) < 0)
b6e1fff1 1201 return log_full_errno(prio, errno, "Failed to reset signal set: %m");
4c253ed1 1202
1f5d1e02
LP
1203 block_signals = true;
1204
1205 } else if (flags & FORK_WAIT) {
1206
1207 /* Let's block SIGCHLD at least, so that we can safely watch for the child process */
1208
1209 if (sigemptyset(&ss) < 0)
1210 return log_full_errno(prio, errno, "Failed to clear signal set: %m");
1211
1212 if (sigaddset(&ss, SIGCHLD) < 0)
1213 return log_full_errno(prio, errno, "Failed to add SIGCHLD to signal set: %m");
1214
1215 block_signals = true;
4c253ed1
LP
1216 }
1217
1f5d1e02
LP
1218 if (block_signals)
1219 if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
1220 return log_full_errno(prio, errno, "Failed to set signal mask: %m");
1221
be39f6ee
LP
1222 if (flags & FORK_NEW_MOUNTNS)
1223 pid = raw_clone(SIGCHLD|CLONE_NEWNS);
1224 else
1225 pid = fork();
4c253ed1
LP
1226 if (pid < 0) {
1227 r = -errno;
1228
1229 if (block_signals) /* undo what we did above */
1230 (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
1231
b6e1fff1 1232 return log_full_errno(prio, r, "Failed to fork: %m");
4c253ed1
LP
1233 }
1234 if (pid > 0) {
1235 /* We are in the parent process */
1236
1f5d1e02
LP
1237 log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
1238
1239 if (flags & FORK_WAIT) {
1240 r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0));
1241 if (r < 0)
1242 return r;
1243 if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
1244 return -EPROTO;
1245 }
1246
4c253ed1
LP
1247 if (block_signals) /* undo what we did above */
1248 (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
1249
4c253ed1
LP
1250 if (ret_pid)
1251 *ret_pid = pid;
1252
1253 return 1;
1254 }
1255
1256 /* We are in the child process */
1257
1258 if (flags & FORK_REOPEN_LOG) {
1259 /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */
1260 log_close();
1261 log_set_open_when_needed(true);
1262 }
1263
1264 if (name) {
1265 r = rename_process(name);
1266 if (r < 0)
b6e1fff1
LP
1267 log_full_errno(flags & FORK_LOG ? LOG_WARNING : LOG_DEBUG,
1268 r, "Failed to rename process, ignoring: %m");
4c253ed1
LP
1269 }
1270
1271 if (flags & FORK_DEATHSIG)
1272 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) {
b6e1fff1 1273 log_full_errno(prio, errno, "Failed to set death signal: %m");
4c253ed1
LP
1274 _exit(EXIT_FAILURE);
1275 }
1276
1277 if (flags & FORK_RESET_SIGNALS) {
1278 r = reset_all_signal_handlers();
1279 if (r < 0) {
b6e1fff1 1280 log_full_errno(prio, r, "Failed to reset signal handlers: %m");
4c253ed1
LP
1281 _exit(EXIT_FAILURE);
1282 }
1283
1284 /* This implicitly undoes the signal mask stuff we did before the fork()ing above */
1285 r = reset_signal_mask();
1286 if (r < 0) {
b6e1fff1 1287 log_full_errno(prio, r, "Failed to reset signal mask: %m");
4c253ed1
LP
1288 _exit(EXIT_FAILURE);
1289 }
1290 } else if (block_signals) { /* undo what we did above */
1291 if (sigprocmask(SIG_SETMASK, &saved_ss, NULL) < 0) {
b6e1fff1 1292 log_full_errno(prio, errno, "Failed to restore signal mask: %m");
4c253ed1
LP
1293 _exit(EXIT_FAILURE);
1294 }
1295 }
1296
1297 if (flags & FORK_DEATHSIG) {
7ddc2dc5 1298 pid_t ppid;
4c253ed1
LP
1299 /* Let's see if the parent PID is still the one we started from? If not, then the parent
1300 * already died by the time we set PR_SET_PDEATHSIG, hence let's emulate the effect */
1301
7ddc2dc5
SL
1302 ppid = getppid();
1303 if (ppid == 0)
1304 /* Parent is in a differn't PID namespace. */;
1305 else if (ppid != original_pid) {
4c253ed1
LP
1306 log_debug("Parent died early, raising SIGTERM.");
1307 (void) raise(SIGTERM);
1308 _exit(EXIT_FAILURE);
1309 }
1310 }
1311
1312 if (flags & FORK_CLOSE_ALL_FDS) {
1313 /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */
1314 log_close();
1315
1316 r = close_all_fds(except_fds, n_except_fds);
1317 if (r < 0) {
b6e1fff1 1318 log_full_errno(prio, r, "Failed to close all file descriptors: %m");
4c253ed1
LP
1319 _exit(EXIT_FAILURE);
1320 }
1321 }
1322
1323 /* When we were asked to reopen the logs, do so again now */
1324 if (flags & FORK_REOPEN_LOG) {
1325 log_open();
1326 log_set_open_when_needed(false);
1327 }
1328
1329 if (flags & FORK_NULL_STDIO) {
1330 r = make_null_stdio();
1331 if (r < 0) {
b6e1fff1 1332 log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
4c253ed1
LP
1333 _exit(EXIT_FAILURE);
1334 }
1335 }
1336
1337 if (ret_pid)
1338 *ret_pid = getpid_cached();
1339
1340 return 0;
1341}
1342
78752f2e
LP
1343int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *ret_pid, const char *path, ...) {
1344 bool stdout_is_tty, stderr_is_tty;
1345 unsigned n, i;
1346 va_list ap;
1347 char **l;
1348 int r;
1349
1350 assert(path);
1351
1352 /* Spawns a temporary TTY agent, making sure it goes away when we go away */
1353
1354 r = safe_fork_full(name, except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, ret_pid);
1355 if (r < 0)
1356 return r;
1357 if (r > 0)
1358 return 0;
1359
1360 /* In the child: */
1361
1362 stdout_is_tty = isatty(STDOUT_FILENO);
1363 stderr_is_tty = isatty(STDERR_FILENO);
1364
1365 if (!stdout_is_tty || !stderr_is_tty) {
1366 int fd;
1367
1368 /* Detach from stdout/stderr. and reopen
1369 * /dev/tty for them. This is important to
1370 * ensure that when systemctl is started via
1371 * popen() or a similar call that expects to
1372 * read EOF we actually do generate EOF and
1373 * not delay this indefinitely by because we
1374 * keep an unused copy of stdin around. */
1375 fd = open("/dev/tty", O_WRONLY);
1376 if (fd < 0) {
1377 log_error_errno(errno, "Failed to open /dev/tty: %m");
1378 _exit(EXIT_FAILURE);
1379 }
1380
1381 if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
1382 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
1383 _exit(EXIT_FAILURE);
1384 }
1385
1386 if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
1387 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
1388 _exit(EXIT_FAILURE);
1389 }
1390
1391 if (fd > STDERR_FILENO)
1392 close(fd);
1393 }
1394
1395 /* Count arguments */
1396 va_start(ap, path);
1397 for (n = 0; va_arg(ap, char*); n++)
1398 ;
1399 va_end(ap);
1400
1401 /* Allocate strv */
1402 l = alloca(sizeof(char *) * (n + 1));
1403
1404 /* Fill in arguments */
1405 va_start(ap, path);
1406 for (i = 0; i <= n; i++)
1407 l[i] = va_arg(ap, char*);
1408 va_end(ap);
1409
1410 execv(path, l);
1411 _exit(EXIT_FAILURE);
1412}
1413
7b3e062c
LP
1414static const char *const ioprio_class_table[] = {
1415 [IOPRIO_CLASS_NONE] = "none",
1416 [IOPRIO_CLASS_RT] = "realtime",
1417 [IOPRIO_CLASS_BE] = "best-effort",
1418 [IOPRIO_CLASS_IDLE] = "idle"
1419};
1420
1421DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
1422
1423static const char *const sigchld_code_table[] = {
1424 [CLD_EXITED] = "exited",
1425 [CLD_KILLED] = "killed",
1426 [CLD_DUMPED] = "dumped",
1427 [CLD_TRAPPED] = "trapped",
1428 [CLD_STOPPED] = "stopped",
1429 [CLD_CONTINUED] = "continued",
1430};
1431
1432DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
1433
1434static const char* const sched_policy_table[] = {
1435 [SCHED_OTHER] = "other",
1436 [SCHED_BATCH] = "batch",
1437 [SCHED_IDLE] = "idle",
1438 [SCHED_FIFO] = "fifo",
1439 [SCHED_RR] = "rr"
1440};
1441
1442DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);