chiark / gitweb /
Introduce strv_consume which takes ownership
[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_consume(&l, name);
389                 if (r < 0)
390                         return r;
391         }
392 #endif
393
394         strv_sort(l);
395
396         r = sd_bus_message_append_strv(reply, l);
397         if (r < 0)
398                 return r;
399
400         return sd_bus_message_close_container(reply);
401 }
402
403 static int property_get_syscall_archs(
404                 sd_bus *bus,
405                 const char *path,
406                 const char *interface,
407                 const char *property,
408                 sd_bus_message *reply,
409                 void *userdata,
410                 sd_bus_error *error) {
411
412         ExecContext *c = userdata;
413         _cleanup_strv_free_ char **l = NULL;
414         int r;
415
416 #ifdef HAVE_SECCOMP
417         Iterator i;
418         void *id;
419 #endif
420
421         assert(bus);
422         assert(reply);
423         assert(c);
424
425 #ifdef HAVE_SECCOMP
426         SET_FOREACH(id, c->syscall_archs, i) {
427                 const char *name;
428
429                 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
430                 if (!name)
431                         continue;
432
433                 r = strv_extend(&l, name);
434                 if (r < 0)
435                         return -ENOMEM;
436         }
437 #endif
438
439         strv_sort(l);
440
441         r = sd_bus_message_append_strv(reply, l);
442         if (r < 0)
443                 return r;
444
445         return 0;
446 }
447
448 static int property_get_syscall_errno(
449                 sd_bus *bus,
450                 const char *path,
451                 const char *interface,
452                 const char *property,
453                 sd_bus_message *reply,
454                 void *userdata,
455                 sd_bus_error *error) {
456
457         ExecContext *c = userdata;
458
459         assert(bus);
460         assert(reply);
461         assert(c);
462
463         return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno);
464 }
465
466 static int property_get_selinux_context(
467                 sd_bus *bus,
468                 const char *path,
469                 const char *interface,
470                 const char *property,
471                 sd_bus_message *reply,
472                 void *userdata,
473                 sd_bus_error *error) {
474
475         ExecContext *c = userdata;
476
477         assert(bus);
478         assert(reply);
479         assert(c);
480
481         return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
482 }
483
484 static int property_get_apparmor_profile(
485                 sd_bus *bus,
486                 const char *path,
487                 const char *interface,
488                 const char *property,
489                 sd_bus_message *reply,
490                 void *userdata,
491                 sd_bus_error *error) {
492
493         ExecContext *c = userdata;
494
495         assert(bus);
496         assert(reply);
497         assert(c);
498
499         return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
500 }
501
502 static int property_get_personality(
503                 sd_bus *bus,
504                 const char *path,
505                 const char *interface,
506                 const char *property,
507                 sd_bus_message *reply,
508                 void *userdata,
509                 sd_bus_error *error) {
510
511         ExecContext *c = userdata;
512
513         assert(bus);
514         assert(reply);
515         assert(c);
516
517         return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
518 }
519
520 static int property_get_address_families(
521                 sd_bus *bus,
522                 const char *path,
523                 const char *interface,
524                 const char *property,
525                 sd_bus_message *reply,
526                 void *userdata,
527                 sd_bus_error *error) {
528
529         ExecContext *c = userdata;
530         _cleanup_strv_free_ char **l = NULL;
531         Iterator i;
532         void *af;
533         int r;
534
535         assert(bus);
536         assert(reply);
537         assert(c);
538
539         r = sd_bus_message_open_container(reply, 'r', "bas");
540         if (r < 0)
541                 return r;
542
543         r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
544         if (r < 0)
545                 return r;
546
547         SET_FOREACH(af, c->address_families, i) {
548                 const char *name;
549
550                 name = af_to_name(PTR_TO_INT(af));
551                 if (!name)
552                         continue;
553
554                 r = strv_extend(&l, name);
555                 if (r < 0)
556                         return -ENOMEM;
557         }
558
559         strv_sort(l);
560
561         r = sd_bus_message_append_strv(reply, l);
562         if (r < 0)
563                 return r;
564
565         return sd_bus_message_close_container(reply);
566 }
567
568 const sd_bus_vtable bus_exec_vtable[] = {
569         SD_BUS_VTABLE_START(0),
570         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
571         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
572         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
573         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
574         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
575         SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
576         SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
577         SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
578         SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
579         SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
580         SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
581         SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
582         SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
583         SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
584         SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
585         SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
586         SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
587         SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
588         SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
589         SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
590         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
591         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
592         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
593         SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
594         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
595         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
596         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
597         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
598         SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
599         SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
600         SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
601         SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
602         SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
603         SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
604         SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
605         SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
606         SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
607         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
608         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
609         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
610         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
611         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
612         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
613         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
614         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
615         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
616         SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), SD_BUS_VTABLE_PROPERTY_CONST),
617         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
618         SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
619         SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
620         SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
621         SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
622         SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
623         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
624         SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
625         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
626         SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
627         SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
628         SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
629         SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
630         SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
631         SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
632         SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
633         SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
634         SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
635         SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
636         SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
637         SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
638         SD_BUS_VTABLE_END
639 };
640
641 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
642         int r;
643
644         assert(reply);
645         assert(c);
646
647         if (!c->path)
648                 return 0;
649
650         r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
651         if (r < 0)
652                 return r;
653
654         r = sd_bus_message_append(reply, "s", c->path);
655         if (r < 0)
656                 return r;
657
658         r = sd_bus_message_append_strv(reply, c->argv);
659         if (r < 0)
660                 return r;
661
662         r = sd_bus_message_append(reply, "bttttuii",
663                                   c->ignore,
664                                   c->exec_status.start_timestamp.realtime,
665                                   c->exec_status.start_timestamp.monotonic,
666                                   c->exec_status.exit_timestamp.realtime,
667                                   c->exec_status.exit_timestamp.monotonic,
668                                   (uint32_t) c->exec_status.pid,
669                                   (int32_t) c->exec_status.code,
670                                   (int32_t) c->exec_status.status);
671         if (r < 0)
672                 return r;
673
674         return sd_bus_message_close_container(reply);
675 }
676
677 int bus_property_get_exec_command(
678                 sd_bus *bus,
679                 const char *path,
680                 const char *interface,
681                 const char *property,
682                 sd_bus_message *reply,
683                 void *userdata,
684                 sd_bus_error *ret_error) {
685
686         ExecCommand *c = (ExecCommand*) userdata;
687         int r;
688
689         assert(bus);
690         assert(reply);
691
692         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
693         if (r < 0)
694                 return r;
695
696         r = append_exec_command(reply, c);
697         if (r < 0)
698                 return r;
699
700         return sd_bus_message_close_container(reply);
701 }
702
703 int bus_property_get_exec_command_list(
704                 sd_bus *bus,
705                 const char *path,
706                 const char *interface,
707                 const char *property,
708                 sd_bus_message *reply,
709                 void *userdata,
710                 sd_bus_error *ret_error) {
711
712         ExecCommand *c = *(ExecCommand**) userdata;
713         int r;
714
715         assert(bus);
716         assert(reply);
717
718         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
719         if (r < 0)
720                 return r;
721
722         LIST_FOREACH(command, c, c) {
723                 r = append_exec_command(reply, c);
724                 if (r < 0)
725                         return r;
726         }
727
728         return sd_bus_message_close_container(reply);
729 }
730
731 int bus_exec_context_set_transient_property(
732                 Unit *u,
733                 ExecContext *c,
734                 const char *name,
735                 sd_bus_message *message,
736                 UnitSetPropertiesMode mode,
737                 sd_bus_error *error) {
738
739         int r;
740
741         assert(u);
742         assert(c);
743         assert(name);
744         assert(message);
745
746         if (streq(name, "User")) {
747                 const char *uu;
748
749                 r = sd_bus_message_read(message, "s", &uu);
750                 if (r < 0)
751                         return r;
752
753                 if (mode != UNIT_CHECK) {
754
755                         if (isempty(uu)) {
756                                 free(c->user);
757                                 c->user = NULL;
758                         } else {
759                                 char *t;
760
761                                 t = strdup(uu);
762                                 if (!t)
763                                         return -ENOMEM;
764
765                                 free(c->user);
766                                 c->user = t;
767                         }
768
769                         unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
770                 }
771
772                 return 1;
773
774         } else if (streq(name, "Group")) {
775                 const char *gg;
776
777                 r = sd_bus_message_read(message, "s", &gg);
778                 if (r < 0)
779                         return r;
780
781                 if (mode != UNIT_CHECK) {
782
783                         if (isempty(gg)) {
784                                 free(c->group);
785                                 c->group = NULL;
786                         } else {
787                                 char *t;
788
789                                 t = strdup(gg);
790                                 if (!t)
791                                         return -ENOMEM;
792
793                                 free(c->group);
794                                 c->group = t;
795                         }
796
797                         unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
798                 }
799
800                 return 1;
801
802         } else if (streq(name, "Nice")) {
803                 int n;
804
805                 r = sd_bus_message_read(message, "i", &n);
806                 if (r < 0)
807                         return r;
808
809                 if (n < PRIO_MIN || n >= PRIO_MAX)
810                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
811
812                 if (mode != UNIT_CHECK) {
813                         c->nice = n;
814                         unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
815                 }
816
817                 return 1;
818
819         } else if (streq(name, "Environment")) {
820
821                 _cleanup_strv_free_ char **l = NULL;
822
823                 r = sd_bus_message_read_strv(message, &l);
824                 if (r < 0)
825                         return r;
826
827                 if (!strv_env_is_valid(l))
828                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
829
830                 if (mode != UNIT_CHECK) {
831                         _cleanup_free_ char *joined = NULL;
832                         char **e;
833
834                         e = strv_env_merge(2, c->environment, l);
835                         if (!e)
836                                 return -ENOMEM;
837
838                         strv_free(c->environment);
839                         c->environment = e;
840
841                         joined = strv_join(c->environment, " ");
842                         if (!joined)
843                                 return -ENOMEM;
844
845                         unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
846                 }
847
848                 return 1;
849         }
850
851         return 0;
852 }