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