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