chiark / gitweb /
execute: try to suppress PR_SET_SECUREBITS if unnecessary
[elogind.git] / execute.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/prctl.h>
32 #include <linux/sched.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <grp.h>
36 #include <pwd.h>
37
38 #include "execute.h"
39 #include "strv.h"
40 #include "macro.h"
41 #include "util.h"
42 #include "log.h"
43 #include "ioprio.h"
44 #include "securebits.h"
45
46 static int close_fds(int except[], unsigned n_except) {
47         DIR *d;
48         struct dirent *de;
49         int r = 0;
50
51         /* Modifies the fds array! (sorts it) */
52
53         if (!(d = opendir("/proc/self/fd")))
54                 return -errno;
55
56         while ((de = readdir(d))) {
57                 int fd;
58
59                 if (de->d_name[0] == '.')
60                         continue;
61
62                 if ((r = safe_atoi(de->d_name, &fd)) < 0)
63                         goto finish;
64
65                 if (fd < 3)
66                         continue;
67
68                 if (fd == dirfd(d))
69                         continue;
70
71                 if (except) {
72                         bool found;
73                         unsigned i;
74
75                         found = false;
76                         for (i = 0; i < n_except; i++)
77                                 if (except[i] == fd) {
78                                         found = true;
79                                         break;
80                                 }
81
82                         if (found)
83                                 continue;
84                 }
85
86                 if ((r = close_nointr(fd)) < 0)
87                         goto finish;
88         }
89
90 finish:
91         closedir(d);
92         return r;
93 }
94
95 static int shift_fds(int fds[], unsigned n_fds) {
96         int start, restart_from;
97
98         if (n_fds <= 0)
99                 return 0;
100
101         assert(fds);
102
103         start = 0;
104         for (;;) {
105                 int i;
106
107                 restart_from = -1;
108
109                 for (i = start; i < (int) n_fds; i++) {
110                         int nfd;
111
112                         /* Already at right index? */
113                         if (fds[i] == i+3)
114                                 continue;
115
116                         if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
117                                 return -errno;
118
119                         assert_se(close_nointr(fds[i]) == 0);
120                         fds[i] = nfd;
121
122                         /* Hmm, the fd we wanted isn't free? Then
123                          * let's remember that and try again from here*/
124                         if (nfd != i+3 && restart_from < 0)
125                                 restart_from = i;
126                 }
127
128                 if (restart_from < 0)
129                         break;
130
131                 start = restart_from;
132         }
133
134         return 0;
135 }
136
137 static int flags_fds(int fds[], unsigned n_fds, bool nonblock) {
138         unsigned i;
139
140         if (n_fds <= 0)
141                 return 0;
142
143         assert(fds);
144
145         /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
146
147         for (i = 0; i < n_fds; i++) {
148                 int flags;
149
150                 if ((flags = fcntl(fds[i], F_GETFL, 0)) < 0)
151                         return -errno;
152
153                 if (nonblock)
154                         flags |= O_NONBLOCK;
155                 else
156                         flags &= ~O_NONBLOCK;
157
158                 if (fcntl(fds[i], F_SETFL, flags) < 0)
159                         return -errno;
160
161                 /* We unconditionally drop FD_CLOEXEC from the fds,
162                  * since after all we want to pass these fds to our
163                  * children */
164                 if ((flags = fcntl(fds[i], F_GETFD, 0)) < 0)
165                         return -errno;
166
167                 if (fcntl(fds[i], F_SETFD, flags &~FD_CLOEXEC) < 0)
168                         return -errno;
169         }
170
171         return 0;
172 }
173
174 static int replace_null_fd(int fd, int flags) {
175         int nfd;
176         assert(fd >= 0);
177
178         close_nointr(fd);
179
180         if ((nfd = open("/dev/null", flags|O_NOCTTY)) < 0)
181                 return -errno;
182
183         if (nfd != fd) {
184                 close_nointr_nofail(nfd);
185                 return -EIO;
186         }
187
188         return 0;
189 }
190
191 static int setup_output(const ExecContext *context, const char *ident) {
192         int r;
193
194         assert(context);
195
196         switch (context->output) {
197
198         case EXEC_OUTPUT_CONSOLE:
199                 return 0;
200
201         case EXEC_OUTPUT_NULL:
202
203                 if ((r = replace_null_fd(STDOUT_FILENO, O_WRONLY)) < 0 ||
204                     (r = replace_null_fd(STDERR_FILENO, O_WRONLY)) < 0)
205                         return r;
206
207                 return 0;
208
209         case EXEC_OUTPUT_KERNEL:
210         case EXEC_OUTPUT_SYSLOG: {
211
212                 int fd;
213                 union {
214                         struct sockaddr sa;
215                         struct sockaddr_un un;
216                 } sa;
217
218                 close_nointr(STDOUT_FILENO);
219                 close_nointr(STDERR_FILENO);
220
221                 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
222                         return -errno;
223
224                 if (fd != STDOUT_FILENO) {
225                         close_nointr_nofail(fd);
226                         return -EIO;
227                 }
228
229                 zero(sa);
230                 sa.sa.sa_family = AF_UNIX;
231                 strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
232
233                 if (connect(fd, &sa.sa, sizeof(sa)) < 0) {
234                         close_nointr_nofail(fd);
235                         return -errno;
236                 }
237
238                 if (shutdown(fd, SHUT_RD) < 0) {
239                         close_nointr_nofail(fd);
240                         return -errno;
241                 }
242
243                 if ((fd = dup(fd)) < 0) {
244                         close_nointr_nofail(fd);
245                         return -errno;
246                 }
247
248                 if (fd != STDERR_FILENO) {
249                         close_nointr_nofail(fd);
250                         return -EIO;
251                 }
252
253                 /* We speak a very simple protocol between log server
254                  * and client: one line for the log destination (kmsg
255                  * or syslog), followed by the priority field,
256                  * followed by the process name. Since we replaced
257                  * stdin/stderr we simple use stdio to write to
258                  * it. Note that we use stderr, to minimize buffer
259                  * flushing issues. */
260
261                 fprintf(stderr,
262                         "%s\n"
263                         "%i\n"
264                         "%s\n",
265                         context->output == EXEC_OUTPUT_KERNEL ? "kmsg" : "syslog",
266                         context->syslog_priority,
267                         context->syslog_identifier ? context->syslog_identifier : ident);
268
269                 return 0;
270         }
271
272         default:
273                 assert_not_reached("Unknown output type");
274         }
275 }
276
277 static int setup_input(const ExecContext *context) {
278         int r;
279
280         assert(context);
281
282         switch (context->input) {
283
284         case EXEC_INPUT_CONSOLE:
285                 return 0;
286
287         case EXEC_INPUT_NULL:
288                 if ((r = replace_null_fd(STDIN_FILENO, O_RDONLY)) < 0)
289                         return r;
290
291                 return 0;
292
293         default:
294                 assert_not_reached("Unknown input type");
295         }
296 }
297
298 static int get_group_creds(const char *groupname, gid_t *gid) {
299         struct group *g;
300         unsigned long lu;
301
302         assert(groupname);
303         assert(gid);
304
305         /* We enforce some special rules for gid=0: in order to avoid
306          * NSS lookups for root we hardcode its data. */
307
308         if (streq(groupname, "root") || streq(groupname, "0")) {
309                 *gid = 0;
310                 return 0;
311         }
312
313         if (safe_atolu(groupname, &lu) >= 0) {
314                 errno = 0;
315                 g = getgrgid((gid_t) lu);
316         } else {
317                 errno = 0;
318                 g = getgrnam(groupname);
319         }
320
321         if (!g)
322                 return errno != 0 ? -errno : -ESRCH;
323
324         *gid = g->gr_gid;
325         return 0;
326 }
327
328 static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
329         struct passwd *p;
330         unsigned long lu;
331
332         assert(username);
333         assert(*username);
334         assert(uid);
335         assert(gid);
336         assert(home);
337
338         /* We enforce some special rules for uid=0: in order to avoid
339          * NSS lookups for root we hardcode its data. */
340
341         if (streq(*username, "root") || streq(*username, "0")) {
342                 *username = "root";
343                 *uid = 0;
344                 *gid = 0;
345                 *home = "/root";
346                 return 0;
347         }
348
349         if (safe_atolu(*username, &lu) >= 0) {
350                 errno = 0;
351                 p = getpwuid((uid_t) lu);
352
353                 /* If there are multiple users with the same id, make
354                  * sure to leave $USER to the configured value instead
355                  * of the first occurence in the database. However if
356                  * the uid was configured by a numeric uid, then let's
357                  * pick the real username from /etc/passwd. */
358                 if (*username && p)
359                         *username = p->pw_name;
360         } else {
361                 errno = 0;
362                 p = getpwnam(*username);
363         }
364
365         if (!p)
366                 return errno != 0 ? -errno : -ESRCH;
367
368         *uid = p->pw_uid;
369         *gid = p->pw_gid;
370         *home = p->pw_dir;
371         return 0;
372 }
373
374 static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
375         bool keep_groups = false;
376         int r;
377
378         assert(context);
379
380         /* Lookup and ser GID and supplementary group list. Here too
381          * we avoid NSS lookups for gid=0. */
382
383         if (context->group || username) {
384
385                 if (context->group)
386                         if ((r = get_group_creds(context->group, &gid)) < 0)
387                                 return r;
388
389                 /* First step, initialize groups from /etc/groups */
390                 if (username && gid != 0) {
391                         if (initgroups(username, gid) < 0)
392                                 return -errno;
393
394                         keep_groups = true;
395                 }
396
397                 /* Second step, set our gids */
398                 if (setresgid(gid, gid, gid) < 0)
399                         return -errno;
400         }
401
402         if (context->supplementary_groups) {
403                 int ngroups_max, k;
404                 gid_t *gids;
405                 char **i;
406
407                 /* Final step, initialize any manually set supplementary groups */
408                 ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);
409
410                 if (!(gids = new(gid_t, ngroups_max)))
411                         return -ENOMEM;
412
413                 if (keep_groups) {
414                         if ((k = getgroups(ngroups_max, gids)) < 0) {
415                                 free(gids);
416                                 return -errno;
417                         }
418                 } else
419                         k = 0;
420
421                 STRV_FOREACH(i, context->supplementary_groups) {
422
423                         if (k >= ngroups_max) {
424                                 free(gids);
425                                 return -E2BIG;
426                         }
427
428                         if ((r = get_group_creds(*i, gids+k)) < 0) {
429                                 free(gids);
430                                 return r;
431                         }
432
433                         k++;
434                 }
435
436                 if (setgroups(k, gids) < 0) {
437                         free(gids);
438                         return -errno;
439                 }
440
441                 free(gids);
442         }
443
444         return 0;
445 }
446
447 static int enforce_user(const ExecContext *context, uid_t uid) {
448         int r;
449         assert(context);
450
451         /* Sets (but doesn't lookup) the uid and make sure we keep the
452          * capabilities while doing so. */
453
454         if (context->capabilities) {
455                 cap_t d;
456                 static const cap_value_t bits[] = {
457                         CAP_SETUID,   /* Necessary so that we can run setresuid() below */
458                         CAP_SETPCAP   /* Necessary so that we can set PR_SET_SECUREBITS later on */
459                 };
460
461                 /* First step: If we need to keep capabilities but
462                  * drop privileges we need to make sure we keep our
463                  * caps, whiel we drop priviliges. */
464                 if (uid != 0) {
465                         int sb = context->secure_bits|SECURE_KEEP_CAPS;
466
467                         if (prctl(PR_GET_SECUREBITS) != sb)
468                                 if (prctl(PR_SET_SECUREBITS, sb) < 0)
469                                         return -errno;
470                 }
471
472                 /* Second step: set the capabilites. This will reduce
473                  * the capabilities to the minimum we need. */
474
475                 if (!(d = cap_dup(context->capabilities)))
476                         return -errno;
477
478                 if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
479                     cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) {
480                         r = -errno;
481                         cap_free(d);
482                         return r;
483                 }
484
485                 if (cap_set_proc(d) < 0) {
486                         r = -errno;
487                         cap_free(d);
488                         return r;
489                 }
490
491                 cap_free(d);
492         }
493
494         /* Third step: actually set the uids */
495         if (setresuid(uid, uid, uid) < 0)
496                 return -errno;
497
498         /* At this point we should have all necessary capabilities but
499            are otherwise a normal user. However, the caps might got
500            corrupted due to the setresuid() so we need clean them up
501            later. This is done outside of this call. */
502
503         return 0;
504 }
505
506 int exec_spawn(const ExecCommand *command,
507                const ExecContext *context,
508                int *fds, unsigned n_fds,
509                bool apply_permissions,
510                bool apply_chroot,
511                pid_t *ret) {
512
513         pid_t pid;
514
515         assert(command);
516         assert(context);
517         assert(ret);
518         assert(fds || n_fds <= 0);
519
520         log_debug("About to execute %s", command->path);
521
522         if ((pid = fork()) < 0)
523                 return -errno;
524
525         if (pid == 0) {
526                 int i, r;
527                 sigset_t ss;
528                 const char *username = NULL, *home = NULL;
529                 uid_t uid = (uid_t) -1;
530                 gid_t gid = (gid_t) -1;
531                 char **our_env = NULL, **final_env = NULL;
532                 unsigned n_env = 0;
533
534                 /* child */
535
536                 if (sigemptyset(&ss) < 0 ||
537                     sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
538                         r = EXIT_SIGNAL_MASK;
539                         goto fail;
540                 }
541
542                 if (setpgid(0, 0) < 0) {
543                         r = EXIT_PGID;
544                         goto fail;
545                 }
546
547                 umask(context->umask);
548
549                 if (setup_input(context) < 0) {
550                         r = EXIT_INPUT;
551                         goto fail;
552                 }
553
554                 if (setup_output(context, file_name_from_path(command->path)) < 0) {
555                         r = EXIT_OUTPUT;
556                         goto fail;
557                 }
558
559                 if (context->oom_adjust_set) {
560                         char t[16];
561
562                         snprintf(t, sizeof(t), "%i", context->oom_adjust);
563                         char_array_0(t);
564
565                         if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
566                                 r = EXIT_OOM_ADJUST;
567                                 goto fail;
568                         }
569                 }
570
571                 if (context->nice_set)
572                         if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
573                                 r = EXIT_NICE;
574                                 goto fail;
575                         }
576
577                 if (context->cpu_sched_set) {
578                         struct sched_param param;
579
580                         zero(param);
581                         param.sched_priority = context->cpu_sched_priority;
582
583                         if (sched_setscheduler(0, context->cpu_sched_policy |
584                                                (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), &param) < 0) {
585                                 r = EXIT_SETSCHEDULER;
586                                 goto fail;
587                         }
588                 }
589
590                 if (context->cpu_affinity_set)
591                         if (sched_setaffinity(0, sizeof(context->cpu_affinity), &context->cpu_affinity) < 0) {
592                                 r = EXIT_CPUAFFINITY;
593                                 goto fail;
594                         }
595
596                 if (context->ioprio_set)
597                         if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
598                                 r = EXIT_IOPRIO;
599                                 goto fail;
600                         }
601
602                 if (context->timer_slack_ns_set)
603                         if (prctl(PR_SET_TIMERSLACK, context->timer_slack_ns_set) < 0) {
604                                 r = EXIT_TIMERSLACK;
605                                 goto fail;
606                         }
607
608                 if (context->user) {
609                         username = context->user;
610                         if (get_user_creds(&username, &uid, &gid, &home) < 0) {
611                                 r = EXIT_USER;
612                                 goto fail;
613                         }
614                 }
615
616                 if (apply_permissions)
617                         if (enforce_groups(context, username, uid) < 0) {
618                                 r = EXIT_GROUP;
619                                 goto fail;
620                         }
621
622                 if (apply_chroot) {
623                         if (context->root_directory)
624                                 if (chroot(context->root_directory) < 0) {
625                                         r = EXIT_CHROOT;
626                                         goto fail;
627                                 }
628
629                         if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
630                                 r = EXIT_CHDIR;
631                                 goto fail;
632                         }
633                 } else {
634
635                         char *d;
636
637                         if (asprintf(&d, "%s/%s",
638                                      context->root_directory ? context->root_directory : "",
639                                      context->working_directory ? context->working_directory : "") < 0) {
640                                 r = EXIT_MEMORY;
641                                 goto fail;
642                         }
643
644                         if (chdir(d) < 0) {
645                                 free(d);
646                                 r = EXIT_CHDIR;
647                                 goto fail;
648                         }
649
650                         free(d);
651                 }
652
653                 if (close_fds(fds, n_fds) < 0 ||
654                     shift_fds(fds, n_fds) < 0 ||
655                     flags_fds(fds, n_fds, context->non_blocking) < 0) {
656                         r = EXIT_FDS;
657                         goto fail;
658                 }
659
660                 if (apply_permissions) {
661
662                         for (i = 0; i < RLIMIT_NLIMITS; i++) {
663                                 if (!context->rlimit[i])
664                                         continue;
665
666                                 if (setrlimit(i, context->rlimit[i]) < 0) {
667                                         r = EXIT_LIMITS;
668                                         goto fail;
669                                 }
670                         }
671
672                         if (context->user)
673                                 if (enforce_user(context, uid) < 0) {
674                                         r = EXIT_USER;
675                                         goto fail;
676                                 }
677
678                         /* PR_GET_SECUREBITS is not priviliged, while
679                          * PR_SET_SECUREBITS is. So to suppress
680                          * potential EPERMs we'll try not to call
681                          * PR_SET_SECUREBITS unless necessary. */
682                         if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
683                                 if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
684                                         r = EXIT_SECUREBITS;
685                                         goto fail;
686                                 }
687
688                         if (context->capabilities)
689                                 if (cap_set_proc(context->capabilities) < 0) {
690                                         r = EXIT_CAPABILITIES;
691                                         goto fail;
692                                 }
693                 }
694
695                 if (!(our_env = new0(char*, 6))) {
696                         r = EXIT_MEMORY;
697                         goto fail;
698                 }
699
700                 if (n_fds > 0)
701                         if (asprintf(our_env + n_env++, "LISTEN_PID=%llu", (unsigned long long) getpid()) < 0 ||
702                             asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
703                                 r = EXIT_MEMORY;
704                                 goto fail;
705                         }
706
707                 if (home)
708                         if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
709                                 r = EXIT_MEMORY;
710                                 goto fail;
711                         }
712
713                 if (username)
714                         if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
715                             asprintf(our_env + n_env++, "USER=%s", username) < 0) {
716                                 r = EXIT_MEMORY;
717                                 goto fail;
718                         }
719
720                 if (!(final_env = strv_env_merge(environ, our_env, context->environment, NULL))) {
721                         r = EXIT_MEMORY;
722                         goto fail;
723                 }
724
725                 execve(command->path, command->argv, final_env);
726                 r = EXIT_EXEC;
727
728         fail:
729                 strv_free(our_env);
730                 strv_free(final_env);
731
732                 _exit(r);
733         }
734
735
736         log_debug("Forked %s as %llu", command->path, (unsigned long long) pid);
737
738         *ret = pid;
739         return 0;
740 }
741
742 void exec_context_init(ExecContext *c) {
743         assert(c);
744
745         c->umask = 0002;
746         c->oom_adjust = 0;
747         c->oom_adjust_set = false;
748         c->nice = 0;
749         c->nice_set = false;
750         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
751         c->ioprio_set = false;
752         c->cpu_sched_policy = SCHED_OTHER;
753         c->cpu_sched_priority = 0;
754         c->cpu_sched_set = false;
755         CPU_ZERO(&c->cpu_affinity);
756         c->cpu_affinity_set = false;
757
758         c->input = 0;
759         c->output = 0;
760         c->syslog_priority = LOG_DAEMON|LOG_INFO;
761
762         c->secure_bits = 0;
763         c->capability_bounding_set_drop = 0;
764 }
765
766 void exec_context_done(ExecContext *c) {
767         unsigned l;
768
769         assert(c);
770
771         strv_free(c->environment);
772         c->environment = NULL;
773
774         for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
775                 free(c->rlimit[l]);
776                 c->rlimit[l] = NULL;
777         }
778
779         free(c->working_directory);
780         c->working_directory = NULL;
781         free(c->root_directory);
782         c->root_directory = NULL;
783
784         free(c->syslog_identifier);
785         c->syslog_identifier = NULL;
786
787         free(c->user);
788         c->user = NULL;
789
790         free(c->group);
791         c->group = NULL;
792
793         strv_free(c->supplementary_groups);
794         c->supplementary_groups = NULL;
795
796         if (c->capabilities) {
797                 cap_free(c->capabilities);
798                 c->capabilities = NULL;
799         }
800 }
801
802 void exec_command_free_list(ExecCommand *c) {
803         ExecCommand *i;
804
805         while ((i = c)) {
806                 LIST_REMOVE(ExecCommand, command, c, i);
807
808                 free(i->path);
809                 strv_free(i->argv);
810                 free(i);
811         }
812 }
813
814 void exec_command_free_array(ExecCommand **c, unsigned n) {
815         unsigned i;
816
817         for (i = 0; i < n; i++) {
818                 exec_command_free_list(c[i]);
819                 c[i] = NULL;
820         }
821 }
822
823 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
824         char ** e;
825         unsigned i;
826
827         assert(c);
828         assert(f);
829
830         if (!prefix)
831                 prefix = "";
832
833         fprintf(f,
834                 "%sUMask: %04o\n"
835                 "%sWorkingDirectory: %s\n"
836                 "%sRootDirectory: %s\n"
837                 "%sNonBlocking: %s\n",
838                 prefix, c->umask,
839                 prefix, c->working_directory ? c->working_directory : "/",
840                 prefix, c->root_directory ? c->root_directory : "/",
841                 prefix, yes_no(c->non_blocking));
842
843         if (c->environment)
844                 for (e = c->environment; *e; e++)
845                         fprintf(f, "%sEnvironment: %s\n", prefix, *e);
846
847         if (c->nice_set)
848                 fprintf(f,
849                         "%sNice: %i\n",
850                         prefix, c->nice);
851
852         if (c->oom_adjust_set)
853                 fprintf(f,
854                         "%sOOMAdjust: %i\n",
855                         prefix, c->oom_adjust);
856
857         for (i = 0; i < RLIM_NLIMITS; i++)
858                 if (c->rlimit[i])
859                         fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
860
861         if (c->ioprio_set)
862                 fprintf(f,
863                         "%sIOSchedulingClass: %s\n"
864                         "%sIOPriority: %i\n",
865                         prefix, ioprio_class_to_string(IOPRIO_PRIO_CLASS(c->ioprio)),
866                         prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
867
868         if (c->cpu_sched_set)
869                 fprintf(f,
870                         "%sCPUSchedulingPolicy: %s\n"
871                         "%sCPUSchedulingPriority: %i\n"
872                         "%sCPUSchedulingResetOnFork: %s\n",
873                         prefix, sched_policy_to_string(c->cpu_sched_policy),
874                         prefix, c->cpu_sched_priority,
875                         prefix, yes_no(c->cpu_sched_reset_on_fork));
876
877         if (c->cpu_affinity_set) {
878                 fprintf(f, "%sCPUAffinity:", prefix);
879                 for (i = 0; i < CPU_SETSIZE; i++)
880                         if (CPU_ISSET(i, &c->cpu_affinity))
881                                 fprintf(f, " %i", i);
882                 fputs("\n", f);
883         }
884
885         if (c->timer_slack_ns_set)
886                 fprintf(f, "%sTimerSlackNS: %lu\n", prefix, c->timer_slack_ns);
887
888         fprintf(f,
889                 "%sInput: %s\n"
890                 "%sOutput: %s\n",
891                 prefix, exec_input_to_string(c->input),
892                 prefix, exec_output_to_string(c->output));
893
894         if (c->output == EXEC_OUTPUT_SYSLOG || c->output == EXEC_OUTPUT_KERNEL)
895                 fprintf(f,
896                         "%sSyslogFacility: %s\n"
897                         "%sSyslogLevel: %s\n",
898                         prefix, log_facility_to_string(LOG_FAC(c->syslog_priority)),
899                         prefix, log_level_to_string(LOG_PRI(c->syslog_priority)));
900
901         if (c->capabilities) {
902                 char *t;
903                 if ((t = cap_to_text(c->capabilities, NULL))) {
904                         fprintf(f, "%sCapabilities: %s\n",
905                                 prefix, t);
906                         cap_free(t);
907                 }
908         }
909
910         if (c->secure_bits)
911                 fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
912                         prefix,
913                         (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "",
914                         (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
915                         (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
916                         (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
917                         (c->secure_bits & SECURE_NOROOT) ? " noroot" : "",
918                         (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
919
920         if (c->capability_bounding_set_drop) {
921                 fprintf(f, "%sCapabilityBoundingSetDrop:", prefix);
922
923                 for (i = 0; i <= CAP_LAST_CAP; i++)
924                         if (c->capability_bounding_set_drop & (1 << i)) {
925                                 char *t;
926
927                                 if ((t = cap_to_name(i))) {
928                                         fprintf(f, " %s", t);
929                                         free(t);
930                                 }
931                         }
932
933                 fputs("\n", f);
934         }
935
936         if (c->user)
937                 fprintf(f, "%sUser: %s", prefix, c->user);
938         if (c->group)
939                 fprintf(f, "%sGroup: %s", prefix, c->group);
940
941         if (c->supplementary_groups) {
942                 char **g;
943
944                 fprintf(f, "%sSupplementaryGroups:", prefix);
945
946                 STRV_FOREACH(g, c->supplementary_groups)
947                         fprintf(f, " %s", *g);
948
949                 fputs("\n", f);
950         }
951 }
952
953 void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
954         assert(s);
955
956         s->pid = pid;
957         s->code = code;
958         s->status = status;
959         s->timestamp = now(CLOCK_REALTIME);
960 }
961
962 char *exec_command_line(ExecCommand *c) {
963         size_t k;
964         char *n, *p, **a;
965         bool first = true;
966
967         assert(c);
968         assert(c->argv);
969
970         k = 1;
971         STRV_FOREACH(a, c->argv)
972                 k += strlen(*a)+3;
973
974         if (!(n = new(char, k)))
975                 return NULL;
976
977         p = n;
978         STRV_FOREACH(a, c->argv) {
979
980                 if (!first)
981                         *(p++) = ' ';
982                 else
983                         first = false;
984
985                 if (strpbrk(*a, WHITESPACE)) {
986                         *(p++) = '\'';
987                         p = stpcpy(p, *a);
988                         *(p++) = '\'';
989                 } else
990                         p = stpcpy(p, *a);
991
992         }
993
994         *p = 0;
995
996         /* FIXME: this doesn't really handle arguments that have
997          * spaces and ticks in them */
998
999         return n;
1000 }
1001
1002 void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
1003         char *cmd;
1004
1005         assert(c);
1006         assert(f);
1007
1008         if (!prefix)
1009                 prefix = "";
1010
1011         cmd = exec_command_line(c);
1012
1013         fprintf(f,
1014                 "%sCommand Line: %s\n",
1015                 prefix, cmd ? cmd : strerror(ENOMEM));
1016
1017         free(cmd);
1018 }
1019
1020 void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
1021         assert(f);
1022
1023         if (!prefix)
1024                 prefix = "";
1025
1026         LIST_FOREACH(command, c, c)
1027                 exec_command_dump(c, f, prefix);
1028 }
1029
1030 void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
1031         ExecCommand *end;
1032
1033         assert(l);
1034         assert(e);
1035
1036         if (*l) {
1037                 /* It's kinda important that we keep the order here */
1038                 LIST_FIND_TAIL(ExecCommand, command, *l, end);
1039                 LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
1040         } else
1041               *l = e;
1042 }
1043
1044 static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
1045         [EXEC_OUTPUT_CONSOLE] = "console",
1046         [EXEC_OUTPUT_NULL] = "null",
1047         [EXEC_OUTPUT_SYSLOG] = "syslog",
1048         [EXEC_OUTPUT_KERNEL] = "kernel"
1049 };
1050
1051 DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
1052
1053 static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
1054         [EXEC_INPUT_NULL] = "null",
1055         [EXEC_INPUT_CONSOLE] = "console"
1056 };
1057
1058 DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);