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