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