chiark / gitweb /
config_parse_set_status: put signals in the correct set
[elogind.git] / src / core / dbus-execute.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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 Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 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   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/prctl.h>
23
24 #ifdef HAVE_SECCOMP
25 #include <seccomp.h>
26 #endif
27
28 #include "bus-util.h"
29 #include "missing.h"
30 #include "ioprio.h"
31 #include "strv.h"
32 #include "fileio.h"
33 #include "execute.h"
34 #include "capability.h"
35 #include "env-util.h"
36 #include "af-list.h"
37 #include "namespace.h"
38 #include "path-util.h"
39 #include "dbus-execute.h"
40
41 #ifdef HAVE_SECCOMP
42 #include "seccomp-util.h"
43 #endif
44
45 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
46
47 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
48
49 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
50 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
51
52 static int property_get_environment_files(
53                 sd_bus *bus,
54                 const char *path,
55                 const char *interface,
56                 const char *property,
57                 sd_bus_message *reply,
58                 void *userdata,
59                 sd_bus_error *error) {
60
61         ExecContext *c = userdata;
62         char **j;
63         int r;
64
65         assert(bus);
66         assert(reply);
67         assert(c);
68
69         r = sd_bus_message_open_container(reply, 'a', "(sb)");
70         if (r < 0)
71                 return r;
72
73         STRV_FOREACH(j, c->environment_files) {
74                 const char *fn = *j;
75
76                 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
77                 if (r < 0)
78                         return r;
79         }
80
81         return sd_bus_message_close_container(reply);
82 }
83
84 static int property_get_rlimit(
85                 sd_bus *bus,
86                 const char *path,
87                 const char *interface,
88                 const char *property,
89                 sd_bus_message *reply,
90                 void *userdata,
91                 sd_bus_error *error) {
92
93         struct rlimit *rl;
94         uint64_t u;
95         rlim_t x;
96
97         assert(bus);
98         assert(reply);
99         assert(userdata);
100
101         rl = *(struct rlimit**) userdata;
102         if (rl)
103                 x = rl->rlim_max;
104         else {
105                 struct rlimit buf = {};
106                 int z;
107
108                 z = rlimit_from_string(property);
109                 assert(z >= 0);
110
111                 getrlimit(z, &buf);
112                 x = buf.rlim_max;
113         }
114
115         /* rlim_t might have different sizes, let's map
116          * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
117          * all archs */
118         u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
119
120         return sd_bus_message_append(reply, "t", u);
121 }
122
123 static int property_get_oom_score_adjust(
124                 sd_bus *bus,
125                 const char *path,
126                 const char *interface,
127                 const char *property,
128                 sd_bus_message *reply,
129                 void *userdata,
130                 sd_bus_error *error) {
131
132
133         ExecContext *c = userdata;
134         int32_t n;
135
136         assert(bus);
137         assert(reply);
138         assert(c);
139
140         if (c->oom_score_adjust_set)
141                 n = c->oom_score_adjust;
142         else {
143                 _cleanup_free_ char *t = NULL;
144
145                 n = 0;
146                 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
147                         safe_atoi(t, &n);
148         }
149
150         return sd_bus_message_append(reply, "i", n);
151 }
152
153 static int property_get_nice(
154                 sd_bus *bus,
155                 const char *path,
156                 const char *interface,
157                 const char *property,
158                 sd_bus_message *reply,
159                 void *userdata,
160                 sd_bus_error *error) {
161
162
163         ExecContext *c = userdata;
164         int32_t n;
165
166         assert(bus);
167         assert(reply);
168         assert(c);
169
170         if (c->nice_set)
171                 n = c->nice;
172         else {
173                 errno = 0;
174                 n = getpriority(PRIO_PROCESS, 0);
175                 if (errno != 0)
176                         n = 0;
177         }
178
179         return sd_bus_message_append(reply, "i", n);
180 }
181
182 static int property_get_ioprio(
183                 sd_bus *bus,
184                 const char *path,
185                 const char *interface,
186                 const char *property,
187                 sd_bus_message *reply,
188                 void *userdata,
189                 sd_bus_error *error) {
190
191
192         ExecContext *c = userdata;
193         int32_t n;
194
195         assert(bus);
196         assert(reply);
197         assert(c);
198
199         if (c->ioprio_set)
200                 n = c->ioprio;
201         else {
202                 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
203                 if (n < 0)
204                         n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
205         }
206
207         return sd_bus_message_append(reply, "i", n);
208 }
209
210 static int property_get_cpu_sched_policy(
211                 sd_bus *bus,
212                 const char *path,
213                 const char *interface,
214                 const char *property,
215                 sd_bus_message *reply,
216                 void *userdata,
217                 sd_bus_error *error) {
218
219         ExecContext *c = userdata;
220         int32_t n;
221
222         assert(bus);
223         assert(reply);
224         assert(c);
225
226         if (c->cpu_sched_set)
227                 n = c->cpu_sched_policy;
228         else {
229                 n = sched_getscheduler(0);
230                 if (n < 0)
231                         n = SCHED_OTHER;
232         }
233
234         return sd_bus_message_append(reply, "i", n);
235 }
236
237 static int property_get_cpu_sched_priority(
238                 sd_bus *bus,
239                 const char *path,
240                 const char *interface,
241                 const char *property,
242                 sd_bus_message *reply,
243                 void *userdata,
244                 sd_bus_error *error) {
245
246         ExecContext *c = userdata;
247         int32_t n;
248
249         assert(bus);
250         assert(reply);
251         assert(c);
252
253         if (c->cpu_sched_set)
254                 n = c->cpu_sched_priority;
255         else {
256                 struct sched_param p = {};
257
258                 if (sched_getparam(0, &p) >= 0)
259                         n = p.sched_priority;
260                 else
261                         n = 0;
262         }
263
264         return sd_bus_message_append(reply, "i", n);
265 }
266
267 static int property_get_cpu_affinity(
268                 sd_bus *bus,
269                 const char *path,
270                 const char *interface,
271                 const char *property,
272                 sd_bus_message *reply,
273                 void *userdata,
274                 sd_bus_error *error) {
275
276         ExecContext *c = userdata;
277
278         assert(bus);
279         assert(reply);
280         assert(c);
281
282         if (c->cpuset)
283                 return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
284         else
285                 return sd_bus_message_append_array(reply, 'y', NULL, 0);
286 }
287
288 static int property_get_timer_slack_nsec(
289                 sd_bus *bus,
290                 const char *path,
291                 const char *interface,
292                 const char *property,
293                 sd_bus_message *reply,
294                 void *userdata,
295                 sd_bus_error *error) {
296
297         ExecContext *c = userdata;
298         uint64_t u;
299
300         assert(bus);
301         assert(reply);
302         assert(c);
303
304         if (c->timer_slack_nsec != NSEC_INFINITY)
305                 u = (uint64_t) c->timer_slack_nsec;
306         else
307                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
308
309         return sd_bus_message_append(reply, "t", u);
310 }
311
312 static int property_get_capability_bounding_set(
313                 sd_bus *bus,
314                 const char *path,
315                 const char *interface,
316                 const char *property,
317                 sd_bus_message *reply,
318                 void *userdata,
319                 sd_bus_error *error) {
320
321         ExecContext *c = userdata;
322
323         assert(bus);
324         assert(reply);
325         assert(c);
326
327         /* We store this negated internally, to match the kernel, but
328          * we expose it normalized. */
329         return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
330 }
331
332 static int property_get_capabilities(
333                 sd_bus *bus,
334                 const char *path,
335                 const char *interface,
336                 const char *property,
337                 sd_bus_message *reply,
338                 void *userdata,
339                 sd_bus_error *error) {
340
341         ExecContext *c = userdata;
342         _cleanup_cap_free_charp_ char *t = NULL;
343         const char *s;
344
345         assert(bus);
346         assert(reply);
347         assert(c);
348
349         if (c->capabilities)
350                 s = t = cap_to_text(c->capabilities, NULL);
351         else
352                 s = "";
353
354         if (!s)
355                 return -ENOMEM;
356
357         return sd_bus_message_append(reply, "s", s);
358 }
359
360 static int property_get_syscall_filter(
361                 sd_bus *bus,
362                 const char *path,
363                 const char *interface,
364                 const char *property,
365                 sd_bus_message *reply,
366                 void *userdata,
367                 sd_bus_error *error) {
368
369         ExecContext *c = userdata;
370         _cleanup_strv_free_ char **l = NULL;
371         int r;
372
373 #ifdef HAVE_SECCOMP
374         Iterator i;
375         void *id;
376 #endif
377
378         assert(bus);
379         assert(reply);
380         assert(c);
381
382         r = sd_bus_message_open_container(reply, 'r', "bas");
383         if (r < 0)
384                 return r;
385
386         r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
387         if (r < 0)
388                 return r;
389
390 #ifdef HAVE_SECCOMP
391         SET_FOREACH(id, c->syscall_filter, i) {
392                 char *name;
393
394                 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
395                 if (!name)
396                         continue;
397
398                 r = strv_consume(&l, name);
399                 if (r < 0)
400                         return r;
401         }
402 #endif
403
404         strv_sort(l);
405
406         r = sd_bus_message_append_strv(reply, l);
407         if (r < 0)
408                 return r;
409
410         return sd_bus_message_close_container(reply);
411 }
412
413 static int property_get_syscall_archs(
414                 sd_bus *bus,
415                 const char *path,
416                 const char *interface,
417                 const char *property,
418                 sd_bus_message *reply,
419                 void *userdata,
420                 sd_bus_error *error) {
421
422         ExecContext *c = userdata;
423         _cleanup_strv_free_ char **l = NULL;
424         int r;
425
426 #ifdef HAVE_SECCOMP
427         Iterator i;
428         void *id;
429 #endif
430
431         assert(bus);
432         assert(reply);
433         assert(c);
434
435 #ifdef HAVE_SECCOMP
436         SET_FOREACH(id, c->syscall_archs, i) {
437                 const char *name;
438
439                 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
440                 if (!name)
441                         continue;
442
443                 r = strv_extend(&l, name);
444                 if (r < 0)
445                         return -ENOMEM;
446         }
447 #endif
448
449         strv_sort(l);
450
451         r = sd_bus_message_append_strv(reply, l);
452         if (r < 0)
453                 return r;
454
455         return 0;
456 }
457
458 static int property_get_syscall_errno(
459                 sd_bus *bus,
460                 const char *path,
461                 const char *interface,
462                 const char *property,
463                 sd_bus_message *reply,
464                 void *userdata,
465                 sd_bus_error *error) {
466
467         ExecContext *c = userdata;
468
469         assert(bus);
470         assert(reply);
471         assert(c);
472
473         return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno);
474 }
475
476 static int property_get_selinux_context(
477                 sd_bus *bus,
478                 const char *path,
479                 const char *interface,
480                 const char *property,
481                 sd_bus_message *reply,
482                 void *userdata,
483                 sd_bus_error *error) {
484
485         ExecContext *c = userdata;
486
487         assert(bus);
488         assert(reply);
489         assert(c);
490
491         return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
492 }
493
494 static int property_get_apparmor_profile(
495                 sd_bus *bus,
496                 const char *path,
497                 const char *interface,
498                 const char *property,
499                 sd_bus_message *reply,
500                 void *userdata,
501                 sd_bus_error *error) {
502
503         ExecContext *c = userdata;
504
505         assert(bus);
506         assert(reply);
507         assert(c);
508
509         return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
510 }
511
512 static int property_get_smack_process_label(
513                 sd_bus *bus,
514                 const char *path,
515                 const char *interface,
516                 const char *property,
517                 sd_bus_message *reply,
518                 void *userdata,
519                 sd_bus_error *error) {
520
521         ExecContext *c = userdata;
522
523         assert(bus);
524         assert(reply);
525         assert(c);
526
527         return sd_bus_message_append(reply, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
528 }
529
530 static int property_get_personality(
531                 sd_bus *bus,
532                 const char *path,
533                 const char *interface,
534                 const char *property,
535                 sd_bus_message *reply,
536                 void *userdata,
537                 sd_bus_error *error) {
538
539         ExecContext *c = userdata;
540
541         assert(bus);
542         assert(reply);
543         assert(c);
544
545         return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
546 }
547
548 static int property_get_address_families(
549                 sd_bus *bus,
550                 const char *path,
551                 const char *interface,
552                 const char *property,
553                 sd_bus_message *reply,
554                 void *userdata,
555                 sd_bus_error *error) {
556
557         ExecContext *c = userdata;
558         _cleanup_strv_free_ char **l = NULL;
559         Iterator i;
560         void *af;
561         int r;
562
563         assert(bus);
564         assert(reply);
565         assert(c);
566
567         r = sd_bus_message_open_container(reply, 'r', "bas");
568         if (r < 0)
569                 return r;
570
571         r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
572         if (r < 0)
573                 return r;
574
575         SET_FOREACH(af, c->address_families, i) {
576                 const char *name;
577
578                 name = af_to_name(PTR_TO_INT(af));
579                 if (!name)
580                         continue;
581
582                 r = strv_extend(&l, name);
583                 if (r < 0)
584                         return -ENOMEM;
585         }
586
587         strv_sort(l);
588
589         r = sd_bus_message_append_strv(reply, l);
590         if (r < 0)
591                 return r;
592
593         return sd_bus_message_close_container(reply);
594 }
595
596 const sd_bus_vtable bus_exec_vtable[] = {
597         SD_BUS_VTABLE_START(0),
598         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
599         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
600         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
601         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
602         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
603         SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
604         SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
605         SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
606         SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
607         SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
608         SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
609         SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
610         SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
611         SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
612         SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
613         SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
614         SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
615         SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
616         SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
617         SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
618         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
619         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
620         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
621         SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
622         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
623         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
624         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
625         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
626         SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
627         SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
628         SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
629         SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
630         SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
631         SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
632         SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
633         SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
634         SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
635         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
636         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
637         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
638         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
639         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
640         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
641         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
642         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
643         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
644         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
645         SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
646         SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
647         SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
648         SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
649         SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
650         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
651         SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
652         SD_BUS_PROPERTY("ProtectHome", "s", bus_property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
653         SD_BUS_PROPERTY("ProtectSystem", "s", bus_property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
654         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
655         SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
656         SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
657         SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
658         SD_BUS_PROPERTY("SmackProcessLabel", "(bs)", property_get_smack_process_label, 0, SD_BUS_VTABLE_PROPERTY_CONST),
659         SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
660         SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
661         SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
662         SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
663         SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
664         SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
665         SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
666         SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
667         SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
668         SD_BUS_VTABLE_END
669 };
670
671 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
672         int r;
673
674         assert(reply);
675         assert(c);
676
677         if (!c->path)
678                 return 0;
679
680         r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
681         if (r < 0)
682                 return r;
683
684         r = sd_bus_message_append(reply, "s", c->path);
685         if (r < 0)
686                 return r;
687
688         r = sd_bus_message_append_strv(reply, c->argv);
689         if (r < 0)
690                 return r;
691
692         r = sd_bus_message_append(reply, "bttttuii",
693                                   c->ignore,
694                                   c->exec_status.start_timestamp.realtime,
695                                   c->exec_status.start_timestamp.monotonic,
696                                   c->exec_status.exit_timestamp.realtime,
697                                   c->exec_status.exit_timestamp.monotonic,
698                                   (uint32_t) c->exec_status.pid,
699                                   (int32_t) c->exec_status.code,
700                                   (int32_t) c->exec_status.status);
701         if (r < 0)
702                 return r;
703
704         return sd_bus_message_close_container(reply);
705 }
706
707 int bus_property_get_exec_command(
708                 sd_bus *bus,
709                 const char *path,
710                 const char *interface,
711                 const char *property,
712                 sd_bus_message *reply,
713                 void *userdata,
714                 sd_bus_error *ret_error) {
715
716         ExecCommand *c = (ExecCommand*) userdata;
717         int r;
718
719         assert(bus);
720         assert(reply);
721
722         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
723         if (r < 0)
724                 return r;
725
726         r = append_exec_command(reply, c);
727         if (r < 0)
728                 return r;
729
730         return sd_bus_message_close_container(reply);
731 }
732
733 int bus_property_get_exec_command_list(
734                 sd_bus *bus,
735                 const char *path,
736                 const char *interface,
737                 const char *property,
738                 sd_bus_message *reply,
739                 void *userdata,
740                 sd_bus_error *ret_error) {
741
742         ExecCommand *c = *(ExecCommand**) userdata;
743         int r;
744
745         assert(bus);
746         assert(reply);
747
748         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
749         if (r < 0)
750                 return r;
751
752         LIST_FOREACH(command, c, c) {
753                 r = append_exec_command(reply, c);
754                 if (r < 0)
755                         return r;
756         }
757
758         return sd_bus_message_close_container(reply);
759 }
760
761 int bus_exec_context_set_transient_property(
762                 Unit *u,
763                 ExecContext *c,
764                 const char *name,
765                 sd_bus_message *message,
766                 UnitSetPropertiesMode mode,
767                 sd_bus_error *error) {
768
769         int r;
770
771         assert(u);
772         assert(c);
773         assert(name);
774         assert(message);
775
776         if (streq(name, "User")) {
777                 const char *uu;
778
779                 r = sd_bus_message_read(message, "s", &uu);
780                 if (r < 0)
781                         return r;
782
783                 if (mode != UNIT_CHECK) {
784
785                         if (isempty(uu)) {
786                                 free(c->user);
787                                 c->user = NULL;
788                         } else {
789                                 char *t;
790
791                                 t = strdup(uu);
792                                 if (!t)
793                                         return -ENOMEM;
794
795                                 free(c->user);
796                                 c->user = t;
797                         }
798
799                         unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
800                 }
801
802                 return 1;
803
804         } else if (streq(name, "Group")) {
805                 const char *gg;
806
807                 r = sd_bus_message_read(message, "s", &gg);
808                 if (r < 0)
809                         return r;
810
811                 if (mode != UNIT_CHECK) {
812
813                         if (isempty(gg)) {
814                                 free(c->group);
815                                 c->group = NULL;
816                         } else {
817                                 char *t;
818
819                                 t = strdup(gg);
820                                 if (!t)
821                                         return -ENOMEM;
822
823                                 free(c->group);
824                                 c->group = t;
825                         }
826
827                         unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
828                 }
829
830                 return 1;
831
832         } else if (streq(name, "Nice")) {
833                 int n;
834
835                 r = sd_bus_message_read(message, "i", &n);
836                 if (r < 0)
837                         return r;
838
839                 if (n < PRIO_MIN || n >= PRIO_MAX)
840                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
841
842                 if (mode != UNIT_CHECK) {
843                         c->nice = n;
844                         unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
845                 }
846
847                 return 1;
848
849         } else if (streq(name, "TTYPath")) {
850                 const char *tty;
851
852                 r = sd_bus_message_read(message, "s", &tty);
853                 if (r < 0)
854                         return r;
855
856                 if (!path_is_absolute(tty))
857                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY device not absolute path");
858
859                 if (mode != UNIT_CHECK) {
860                         char *t;
861
862                         t = strdup(tty);
863                         if (!t)
864                                 return -ENOMEM;
865
866                         free(c->tty_path);
867                         c->tty_path = t;
868
869                         unit_write_drop_in_private_format(u, mode, name, "TTYPath=%s\n", tty);
870                 }
871
872                 return 1;
873
874         } else if (streq(name, "StandardInput")) {
875                 const char *s;
876                 ExecInput p;
877
878                 r = sd_bus_message_read(message, "s", &s);
879                 if (r < 0)
880                         return r;
881
882                 p = exec_input_from_string(s);
883                 if (p < 0)
884                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard input name");
885
886                 if (mode != UNIT_CHECK) {
887                         c->std_input = p;
888
889                         unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s\n", exec_input_to_string(p));
890                 }
891
892                 return 1;
893
894
895         } else if (streq(name, "StandardOutput")) {
896                 const char *s;
897                 ExecOutput p;
898
899                 r = sd_bus_message_read(message, "s", &s);
900                 if (r < 0)
901                         return r;
902
903                 p = exec_output_from_string(s);
904                 if (p < 0)
905                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard output name");
906
907                 if (mode != UNIT_CHECK) {
908                         c->std_output = p;
909
910                         unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s\n", exec_output_to_string(p));
911                 }
912
913                 return 1;
914
915         } else if (streq(name, "StandardError")) {
916                 const char *s;
917                 ExecOutput p;
918
919                 r = sd_bus_message_read(message, "s", &s);
920                 if (r < 0)
921                         return r;
922
923                 p = exec_output_from_string(s);
924                 if (p < 0)
925                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard error name");
926
927                 if (mode != UNIT_CHECK) {
928                         c->std_error = p;
929
930                         unit_write_drop_in_private_format(u, mode, name, "StandardError=%s\n", exec_output_to_string(p));
931                 }
932
933                 return 1;
934
935         } else if (streq(name, "Environment")) {
936
937                 _cleanup_strv_free_ char **l = NULL;
938
939                 r = sd_bus_message_read_strv(message, &l);
940                 if (r < 0)
941                         return r;
942
943                 if (!strv_env_is_valid(l))
944                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
945
946                 if (mode != UNIT_CHECK) {
947                         _cleanup_free_ char *joined = NULL;
948                         char **e;
949
950                         e = strv_env_merge(2, c->environment, l);
951                         if (!e)
952                                 return -ENOMEM;
953
954                         strv_free(c->environment);
955                         c->environment = e;
956
957                         joined = strv_join_quoted(c->environment);
958                         if (!joined)
959                                 return -ENOMEM;
960
961                         unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
962                 }
963
964                 return 1;
965
966         } else if (rlimit_from_string(name) >= 0) {
967                 uint64_t rl;
968                 rlim_t x;
969
970                 r = sd_bus_message_read(message, "t", &rl);
971                 if (r < 0)
972                         return r;
973
974                 if (rl == (uint64_t) -1)
975                         x = RLIM_INFINITY;
976                 else {
977                         x = (rlim_t) rl;
978
979                         if ((uint64_t) x != rl)
980                                 return -ERANGE;
981                 }
982
983                 if (mode != UNIT_CHECK) {
984                         int z;
985
986                         z = rlimit_from_string(name);
987
988                         if (!c->rlimit[z]) {
989                                 c->rlimit[z] = new(struct rlimit, 1);
990                                 if (!c->rlimit[z])
991                                         return -ENOMEM;
992                         }
993
994                         c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
995
996                         if (x == RLIM_INFINITY)
997                                 unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
998                         else
999                                 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
1000                 }
1001
1002                 return 1;
1003         }
1004
1005         return 0;
1006 }