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