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