chiark / gitweb /
core: expose architecture as a bus property, so that we can easily query it remotely
[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_apparmor_profile(
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, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
501 }
502
503 static int property_get_personality(
504                 sd_bus *bus,
505                 const char *path,
506                 const char *interface,
507                 const char *property,
508                 sd_bus_message *reply,
509                 void *userdata,
510                 sd_bus_error *error) {
511
512         ExecContext *c = userdata;
513
514         assert(bus);
515         assert(reply);
516         assert(c);
517
518         return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
519 }
520
521 const sd_bus_vtable bus_exec_vtable[] = {
522         SD_BUS_VTABLE_START(0),
523         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
524         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
525         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
526         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
527         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
528         SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
529         SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
530         SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
531         SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
532         SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
533         SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
534         SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
535         SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
536         SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
537         SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
538         SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
539         SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
540         SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
541         SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
542         SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
543         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
544         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
545         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
546         SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
547         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
548         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
549         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
550         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
551         SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
552         SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
553         SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
554         SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
555         SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
556         SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
557         SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
558         SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
559         SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
560         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
561         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
562         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
563         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
564         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
565         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
566         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
567         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
568         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
569         SD_BUS_PROPERTY("TCPWrapName", "s", NULL, offsetof(ExecContext, tcpwrap_name), SD_BUS_VTABLE_PROPERTY_CONST),
570         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
571         SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
572         SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
573         SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
574         SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
575         SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
576         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
577         SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
578         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
579         SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
580         SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
581         SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
582         SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
583         SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
584         SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
585         SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
586         SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
587         SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
588         SD_BUS_VTABLE_END
589 };
590
591 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
592         int r;
593
594         assert(reply);
595         assert(c);
596
597         if (!c->path)
598                 return 0;
599
600         r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
601         if (r < 0)
602                 return r;
603
604         r = sd_bus_message_append(reply, "s", c->path);
605         if (r < 0)
606                 return r;
607
608         r = sd_bus_message_append_strv(reply, c->argv);
609         if (r < 0)
610                 return r;
611
612         r = sd_bus_message_append(reply, "bttttuii",
613                                   c->ignore,
614                                   c->exec_status.start_timestamp.realtime,
615                                   c->exec_status.start_timestamp.monotonic,
616                                   c->exec_status.exit_timestamp.realtime,
617                                   c->exec_status.exit_timestamp.monotonic,
618                                   (uint32_t) c->exec_status.pid,
619                                   (int32_t) c->exec_status.code,
620                                   (int32_t) c->exec_status.status);
621         if (r < 0)
622                 return r;
623
624         return sd_bus_message_close_container(reply);
625 }
626
627 int bus_property_get_exec_command(
628                 sd_bus *bus,
629                 const char *path,
630                 const char *interface,
631                 const char *property,
632                 sd_bus_message *reply,
633                 void *userdata,
634                 sd_bus_error *ret_error) {
635
636         ExecCommand *c = (ExecCommand*) userdata;
637         int r;
638
639         assert(bus);
640         assert(reply);
641
642         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
643         if (r < 0)
644                 return r;
645
646         r = append_exec_command(reply, c);
647         if (r < 0)
648                 return r;
649
650         return sd_bus_message_close_container(reply);
651 }
652
653 int bus_property_get_exec_command_list(
654                 sd_bus *bus,
655                 const char *path,
656                 const char *interface,
657                 const char *property,
658                 sd_bus_message *reply,
659                 void *userdata,
660                 sd_bus_error *ret_error) {
661
662         ExecCommand *c = *(ExecCommand**) userdata;
663         int r;
664
665         assert(bus);
666         assert(reply);
667
668         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
669         if (r < 0)
670                 return r;
671
672         LIST_FOREACH(command, c, c) {
673                 r = append_exec_command(reply, c);
674                 if (r < 0)
675                         return r;
676         }
677
678         return sd_bus_message_close_container(reply);
679 }
680
681 int bus_exec_context_set_transient_property(
682                 Unit *u,
683                 ExecContext *c,
684                 const char *name,
685                 sd_bus_message *message,
686                 UnitSetPropertiesMode mode,
687                 sd_bus_error *error) {
688
689         int r;
690
691         assert(u);
692         assert(c);
693         assert(name);
694         assert(message);
695
696         if (streq(name, "User")) {
697                 const char *uu;
698
699                 r = sd_bus_message_read(message, "s", &uu);
700                 if (r < 0)
701                         return r;
702
703                 if (mode != UNIT_CHECK) {
704
705                         if (isempty(uu)) {
706                                 free(c->user);
707                                 c->user = NULL;
708                         } else {
709                                 char *t;
710
711                                 t = strdup(uu);
712                                 if (!t)
713                                         return -ENOMEM;
714
715                                 free(c->user);
716                                 c->user = t;
717                         }
718
719                         unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
720                 }
721
722                 return 1;
723
724         } else if (streq(name, "Group")) {
725                 const char *gg;
726
727                 r = sd_bus_message_read(message, "s", &gg);
728                 if (r < 0)
729                         return r;
730
731                 if (mode != UNIT_CHECK) {
732
733                         if (isempty(gg)) {
734                                 free(c->group);
735                                 c->group = NULL;
736                         } else {
737                                 char *t;
738
739                                 t = strdup(gg);
740                                 if (!t)
741                                         return -ENOMEM;
742
743                                 free(c->group);
744                                 c->group = t;
745                         }
746
747                         unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
748                 }
749
750                 return 1;
751
752         } else if (streq(name, "Nice")) {
753                 int n;
754
755                 r = sd_bus_message_read(message, "i", &n);
756                 if (r < 0)
757                         return r;
758
759                 if (n < PRIO_MIN || n >= PRIO_MAX)
760                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
761
762                 if (mode != UNIT_CHECK) {
763                         c->nice = n;
764                         unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
765                 }
766
767                 return 1;
768
769         } else if (streq(name, "Environment")) {
770
771                 _cleanup_strv_free_ char **l = NULL;
772
773                 r = sd_bus_message_read_strv(message, &l);
774                 if (r < 0)
775                         return r;
776
777                 if (!strv_env_is_valid(l))
778                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
779
780                 if (mode != UNIT_CHECK) {
781                         _cleanup_free_ char *joined = NULL;
782                         char **e;
783
784                         e = strv_env_merge(2, c->environment, l);
785                         if (!e)
786                                 return -ENOMEM;
787
788                         strv_free(c->environment);
789                         c->environment = e;
790
791                         joined = strv_join(c->environment, " ");
792                         if (!joined)
793                                 return -ENOMEM;
794
795                         unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
796                 }
797
798                 return 1;
799         }
800
801         return 0;
802 }