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