]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-execute.c
Merge pull request #1659 from vcaputo/journal_verify_envalid
[thirdparty/systemd.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 "capability.h"
35 #include "env-util.h"
36 #include "af-list.h"
37 #include "namespace.h"
38 #include "path-util.h"
39 #include "utf8.h"
40 #include "dbus-execute.h"
41
42 #ifdef HAVE_SECCOMP
43 #include "seccomp-util.h"
44 #endif
45
46 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
47
48 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
49
50 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
51
52 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
53 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
54
55 static int property_get_environment_files(
56 sd_bus *bus,
57 const char *path,
58 const char *interface,
59 const char *property,
60 sd_bus_message *reply,
61 void *userdata,
62 sd_bus_error *error) {
63
64 ExecContext *c = userdata;
65 char **j;
66 int r;
67
68 assert(bus);
69 assert(reply);
70 assert(c);
71
72 r = sd_bus_message_open_container(reply, 'a', "(sb)");
73 if (r < 0)
74 return r;
75
76 STRV_FOREACH(j, c->environment_files) {
77 const char *fn = *j;
78
79 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
80 if (r < 0)
81 return r;
82 }
83
84 return sd_bus_message_close_container(reply);
85 }
86
87 static int property_get_oom_score_adjust(
88 sd_bus *bus,
89 const char *path,
90 const char *interface,
91 const char *property,
92 sd_bus_message *reply,
93 void *userdata,
94 sd_bus_error *error) {
95
96
97 ExecContext *c = userdata;
98 int32_t n;
99
100 assert(bus);
101 assert(reply);
102 assert(c);
103
104 if (c->oom_score_adjust_set)
105 n = c->oom_score_adjust;
106 else {
107 _cleanup_free_ char *t = NULL;
108
109 n = 0;
110 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
111 safe_atoi(t, &n);
112 }
113
114 return sd_bus_message_append(reply, "i", n);
115 }
116
117 static int property_get_nice(
118 sd_bus *bus,
119 const char *path,
120 const char *interface,
121 const char *property,
122 sd_bus_message *reply,
123 void *userdata,
124 sd_bus_error *error) {
125
126
127 ExecContext *c = userdata;
128 int32_t n;
129
130 assert(bus);
131 assert(reply);
132 assert(c);
133
134 if (c->nice_set)
135 n = c->nice;
136 else {
137 errno = 0;
138 n = getpriority(PRIO_PROCESS, 0);
139 if (errno != 0)
140 n = 0;
141 }
142
143 return sd_bus_message_append(reply, "i", n);
144 }
145
146 static int property_get_ioprio(
147 sd_bus *bus,
148 const char *path,
149 const char *interface,
150 const char *property,
151 sd_bus_message *reply,
152 void *userdata,
153 sd_bus_error *error) {
154
155
156 ExecContext *c = userdata;
157 int32_t n;
158
159 assert(bus);
160 assert(reply);
161 assert(c);
162
163 if (c->ioprio_set)
164 n = c->ioprio;
165 else {
166 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
167 if (n < 0)
168 n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
169 }
170
171 return sd_bus_message_append(reply, "i", n);
172 }
173
174 static int property_get_cpu_sched_policy(
175 sd_bus *bus,
176 const char *path,
177 const char *interface,
178 const char *property,
179 sd_bus_message *reply,
180 void *userdata,
181 sd_bus_error *error) {
182
183 ExecContext *c = userdata;
184 int32_t n;
185
186 assert(bus);
187 assert(reply);
188 assert(c);
189
190 if (c->cpu_sched_set)
191 n = c->cpu_sched_policy;
192 else {
193 n = sched_getscheduler(0);
194 if (n < 0)
195 n = SCHED_OTHER;
196 }
197
198 return sd_bus_message_append(reply, "i", n);
199 }
200
201 static int property_get_cpu_sched_priority(
202 sd_bus *bus,
203 const char *path,
204 const char *interface,
205 const char *property,
206 sd_bus_message *reply,
207 void *userdata,
208 sd_bus_error *error) {
209
210 ExecContext *c = userdata;
211 int32_t n;
212
213 assert(bus);
214 assert(reply);
215 assert(c);
216
217 if (c->cpu_sched_set)
218 n = c->cpu_sched_priority;
219 else {
220 struct sched_param p = {};
221
222 if (sched_getparam(0, &p) >= 0)
223 n = p.sched_priority;
224 else
225 n = 0;
226 }
227
228 return sd_bus_message_append(reply, "i", n);
229 }
230
231 static int property_get_cpu_affinity(
232 sd_bus *bus,
233 const char *path,
234 const char *interface,
235 const char *property,
236 sd_bus_message *reply,
237 void *userdata,
238 sd_bus_error *error) {
239
240 ExecContext *c = userdata;
241
242 assert(bus);
243 assert(reply);
244 assert(c);
245
246 if (c->cpuset)
247 return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
248 else
249 return sd_bus_message_append_array(reply, 'y', NULL, 0);
250 }
251
252 static int property_get_timer_slack_nsec(
253 sd_bus *bus,
254 const char *path,
255 const char *interface,
256 const char *property,
257 sd_bus_message *reply,
258 void *userdata,
259 sd_bus_error *error) {
260
261 ExecContext *c = userdata;
262 uint64_t u;
263
264 assert(bus);
265 assert(reply);
266 assert(c);
267
268 if (c->timer_slack_nsec != NSEC_INFINITY)
269 u = (uint64_t) c->timer_slack_nsec;
270 else
271 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
272
273 return sd_bus_message_append(reply, "t", u);
274 }
275
276 static int property_get_capability_bounding_set(
277 sd_bus *bus,
278 const char *path,
279 const char *interface,
280 const char *property,
281 sd_bus_message *reply,
282 void *userdata,
283 sd_bus_error *error) {
284
285 ExecContext *c = userdata;
286
287 assert(bus);
288 assert(reply);
289 assert(c);
290
291 /* We store this negated internally, to match the kernel, but
292 * we expose it normalized. */
293 return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
294 }
295
296 static int property_get_capabilities(
297 sd_bus *bus,
298 const char *path,
299 const char *interface,
300 const char *property,
301 sd_bus_message *reply,
302 void *userdata,
303 sd_bus_error *error) {
304
305 ExecContext *c = userdata;
306 _cleanup_cap_free_charp_ char *t = NULL;
307 const char *s;
308
309 assert(bus);
310 assert(reply);
311 assert(c);
312
313 if (c->capabilities)
314 s = t = cap_to_text(c->capabilities, NULL);
315 else
316 s = "";
317
318 if (!s)
319 return -ENOMEM;
320
321 return sd_bus_message_append(reply, "s", s);
322 }
323
324 static int property_get_syscall_filter(
325 sd_bus *bus,
326 const char *path,
327 const char *interface,
328 const char *property,
329 sd_bus_message *reply,
330 void *userdata,
331 sd_bus_error *error) {
332
333 ExecContext *c = userdata;
334 _cleanup_strv_free_ char **l = NULL;
335 int r;
336
337 #ifdef HAVE_SECCOMP
338 Iterator i;
339 void *id;
340 #endif
341
342 assert(bus);
343 assert(reply);
344 assert(c);
345
346 r = sd_bus_message_open_container(reply, 'r', "bas");
347 if (r < 0)
348 return r;
349
350 r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
351 if (r < 0)
352 return r;
353
354 #ifdef HAVE_SECCOMP
355 SET_FOREACH(id, c->syscall_filter, i) {
356 char *name;
357
358 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
359 if (!name)
360 continue;
361
362 r = strv_consume(&l, name);
363 if (r < 0)
364 return r;
365 }
366 #endif
367
368 strv_sort(l);
369
370 r = sd_bus_message_append_strv(reply, l);
371 if (r < 0)
372 return r;
373
374 return sd_bus_message_close_container(reply);
375 }
376
377 static int property_get_syscall_archs(
378 sd_bus *bus,
379 const char *path,
380 const char *interface,
381 const char *property,
382 sd_bus_message *reply,
383 void *userdata,
384 sd_bus_error *error) {
385
386 ExecContext *c = userdata;
387 _cleanup_strv_free_ char **l = NULL;
388 int r;
389
390 #ifdef HAVE_SECCOMP
391 Iterator i;
392 void *id;
393 #endif
394
395 assert(bus);
396 assert(reply);
397 assert(c);
398
399 #ifdef HAVE_SECCOMP
400 SET_FOREACH(id, c->syscall_archs, i) {
401 const char *name;
402
403 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
404 if (!name)
405 continue;
406
407 r = strv_extend(&l, name);
408 if (r < 0)
409 return -ENOMEM;
410 }
411 #endif
412
413 strv_sort(l);
414
415 r = sd_bus_message_append_strv(reply, l);
416 if (r < 0)
417 return r;
418
419 return 0;
420 }
421
422 static int property_get_syscall_errno(
423 sd_bus *bus,
424 const char *path,
425 const char *interface,
426 const char *property,
427 sd_bus_message *reply,
428 void *userdata,
429 sd_bus_error *error) {
430
431 ExecContext *c = userdata;
432
433 assert(bus);
434 assert(reply);
435 assert(c);
436
437 return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno);
438 }
439
440 static int property_get_selinux_context(
441 sd_bus *bus,
442 const char *path,
443 const char *interface,
444 const char *property,
445 sd_bus_message *reply,
446 void *userdata,
447 sd_bus_error *error) {
448
449 ExecContext *c = userdata;
450
451 assert(bus);
452 assert(reply);
453 assert(c);
454
455 return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
456 }
457
458 static int property_get_apparmor_profile(
459 sd_bus *bus,
460 const char *path,
461 const char *interface,
462 const char *property,
463 sd_bus_message *reply,
464 void *userdata,
465 sd_bus_error *error) {
466
467 ExecContext *c = userdata;
468
469 assert(bus);
470 assert(reply);
471 assert(c);
472
473 return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
474 }
475
476 static int property_get_smack_process_label(
477 sd_bus *bus,
478 const char *path,
479 const char *interface,
480 const char *property,
481 sd_bus_message *reply,
482 void *userdata,
483 sd_bus_error *error) {
484
485 ExecContext *c = userdata;
486
487 assert(bus);
488 assert(reply);
489 assert(c);
490
491 return sd_bus_message_append(reply, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
492 }
493
494 static int property_get_personality(
495 sd_bus *bus,
496 const char *path,
497 const char *interface,
498 const char *property,
499 sd_bus_message *reply,
500 void *userdata,
501 sd_bus_error *error) {
502
503 ExecContext *c = userdata;
504
505 assert(bus);
506 assert(reply);
507 assert(c);
508
509 return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
510 }
511
512 static int property_get_address_families(
513 sd_bus *bus,
514 const char *path,
515 const char *interface,
516 const char *property,
517 sd_bus_message *reply,
518 void *userdata,
519 sd_bus_error *error) {
520
521 ExecContext *c = userdata;
522 _cleanup_strv_free_ char **l = NULL;
523 Iterator i;
524 void *af;
525 int r;
526
527 assert(bus);
528 assert(reply);
529 assert(c);
530
531 r = sd_bus_message_open_container(reply, 'r', "bas");
532 if (r < 0)
533 return r;
534
535 r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
536 if (r < 0)
537 return r;
538
539 SET_FOREACH(af, c->address_families, i) {
540 const char *name;
541
542 name = af_to_name(PTR_TO_INT(af));
543 if (!name)
544 continue;
545
546 r = strv_extend(&l, name);
547 if (r < 0)
548 return -ENOMEM;
549 }
550
551 strv_sort(l);
552
553 r = sd_bus_message_append_strv(reply, l);
554 if (r < 0)
555 return r;
556
557 return sd_bus_message_close_container(reply);
558 }
559
560 static int property_get_working_directory(
561 sd_bus *bus,
562 const char *path,
563 const char *interface,
564 const char *property,
565 sd_bus_message *reply,
566 void *userdata,
567 sd_bus_error *error) {
568
569 ExecContext *c = userdata;
570 const char *wd;
571
572 assert(bus);
573 assert(reply);
574 assert(c);
575
576 if (c->working_directory_home)
577 wd = "~";
578 else
579 wd = c->working_directory;
580
581 if (c->working_directory_missing_ok)
582 wd = strjoina("!", wd);
583
584 return sd_bus_message_append(reply, "s", wd);
585 }
586
587 static int property_get_syslog_level(
588 sd_bus *bus,
589 const char *path,
590 const char *interface,
591 const char *property,
592 sd_bus_message *reply,
593 void *userdata,
594 sd_bus_error *error) {
595
596 ExecContext *c = userdata;
597
598 assert(bus);
599 assert(reply);
600 assert(c);
601
602 return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
603 }
604
605 static int property_get_syslog_facility(
606 sd_bus *bus,
607 const char *path,
608 const char *interface,
609 const char *property,
610 sd_bus_message *reply,
611 void *userdata,
612 sd_bus_error *error) {
613
614 ExecContext *c = userdata;
615
616 assert(bus);
617 assert(reply);
618 assert(c);
619
620 return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
621 }
622
623 const sd_bus_vtable bus_exec_vtable[] = {
624 SD_BUS_VTABLE_START(0),
625 SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
626 SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
627 SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
628 SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
629 SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
630 SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
631 SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
632 SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
633 SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
634 SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
635 SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
636 SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
637 SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
638 SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
639 SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
640 SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
641 SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
642 SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
643 SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
644 SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
645 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
646 SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
647 SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
648 SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
649 SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
650 SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
651 SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
652 SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
653 SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
654 SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
655 SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
656 SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
657 SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
658 SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
659 SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
660 SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
661 SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
662 SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
663 SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
664 SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
665 SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
666 SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
667 SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
668 SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
669 SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
670 SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
671 SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
672 SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
673 SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
674 SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
675 SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
676 SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
677 SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
678 SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
679 SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
680 SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
681 SD_BUS_PROPERTY("ProtectHome", "s", bus_property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
682 SD_BUS_PROPERTY("ProtectSystem", "s", bus_property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
683 SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
684 SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
685 SD_BUS_PROPERTY("UtmpMode", "s", property_get_exec_utmp_mode, offsetof(ExecContext, utmp_mode), SD_BUS_VTABLE_PROPERTY_CONST),
686 SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
687 SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
688 SD_BUS_PROPERTY("SmackProcessLabel", "(bs)", property_get_smack_process_label, 0, SD_BUS_VTABLE_PROPERTY_CONST),
689 SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
690 SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
691 SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
692 SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
693 SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
694 SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
695 SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
696 SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
697 SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
698 SD_BUS_VTABLE_END
699 };
700
701 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
702 int r;
703
704 assert(reply);
705 assert(c);
706
707 if (!c->path)
708 return 0;
709
710 r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
711 if (r < 0)
712 return r;
713
714 r = sd_bus_message_append(reply, "s", c->path);
715 if (r < 0)
716 return r;
717
718 r = sd_bus_message_append_strv(reply, c->argv);
719 if (r < 0)
720 return r;
721
722 r = sd_bus_message_append(reply, "bttttuii",
723 c->ignore,
724 c->exec_status.start_timestamp.realtime,
725 c->exec_status.start_timestamp.monotonic,
726 c->exec_status.exit_timestamp.realtime,
727 c->exec_status.exit_timestamp.monotonic,
728 (uint32_t) c->exec_status.pid,
729 (int32_t) c->exec_status.code,
730 (int32_t) c->exec_status.status);
731 if (r < 0)
732 return r;
733
734 return sd_bus_message_close_container(reply);
735 }
736
737 int bus_property_get_exec_command(
738 sd_bus *bus,
739 const char *path,
740 const char *interface,
741 const char *property,
742 sd_bus_message *reply,
743 void *userdata,
744 sd_bus_error *ret_error) {
745
746 ExecCommand *c = (ExecCommand*) userdata;
747 int r;
748
749 assert(bus);
750 assert(reply);
751
752 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
753 if (r < 0)
754 return r;
755
756 r = append_exec_command(reply, c);
757 if (r < 0)
758 return r;
759
760 return sd_bus_message_close_container(reply);
761 }
762
763 int bus_property_get_exec_command_list(
764 sd_bus *bus,
765 const char *path,
766 const char *interface,
767 const char *property,
768 sd_bus_message *reply,
769 void *userdata,
770 sd_bus_error *ret_error) {
771
772 ExecCommand *c = *(ExecCommand**) userdata;
773 int r;
774
775 assert(bus);
776 assert(reply);
777
778 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
779 if (r < 0)
780 return r;
781
782 LIST_FOREACH(command, c, c) {
783 r = append_exec_command(reply, c);
784 if (r < 0)
785 return r;
786 }
787
788 return sd_bus_message_close_container(reply);
789 }
790
791 int bus_exec_context_set_transient_property(
792 Unit *u,
793 ExecContext *c,
794 const char *name,
795 sd_bus_message *message,
796 UnitSetPropertiesMode mode,
797 sd_bus_error *error) {
798
799 int r;
800
801 assert(u);
802 assert(c);
803 assert(name);
804 assert(message);
805
806 if (streq(name, "User")) {
807 const char *uu;
808
809 r = sd_bus_message_read(message, "s", &uu);
810 if (r < 0)
811 return r;
812
813 if (mode != UNIT_CHECK) {
814
815 if (isempty(uu)) {
816 c->user = mfree(c->user);
817 } else {
818 char *t;
819
820 t = strdup(uu);
821 if (!t)
822 return -ENOMEM;
823
824 free(c->user);
825 c->user = t;
826 }
827
828 unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
829 }
830
831 return 1;
832
833 } else if (streq(name, "Group")) {
834 const char *gg;
835
836 r = sd_bus_message_read(message, "s", &gg);
837 if (r < 0)
838 return r;
839
840 if (mode != UNIT_CHECK) {
841
842 if (isempty(gg)) {
843 c->group = mfree(c->group);
844 } else {
845 char *t;
846
847 t = strdup(gg);
848 if (!t)
849 return -ENOMEM;
850
851 free(c->group);
852 c->group = t;
853 }
854
855 unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
856 }
857
858 return 1;
859 } else if (streq(name, "SyslogIdentifier")) {
860 const char *id;
861
862 r = sd_bus_message_read(message, "s", &id);
863 if (r < 0)
864 return r;
865
866 if (mode != UNIT_CHECK) {
867
868 if (isempty(id)) {
869 c->syslog_identifier = mfree(c->syslog_identifier);
870 } else {
871 char *t;
872
873 t = strdup(id);
874 if (!t)
875 return -ENOMEM;
876
877 free(c->syslog_identifier);
878 c->syslog_identifier = t;
879 }
880
881 unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
882 }
883
884 return 1;
885 } else if (streq(name, "SyslogLevel")) {
886 int level;
887
888 r = sd_bus_message_read(message, "i", &level);
889 if (r < 0)
890 return r;
891
892 if (!log_level_is_valid(level))
893 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
894
895 if (mode != UNIT_CHECK) {
896 c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
897 unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level);
898 }
899
900 return 1;
901 } else if (streq(name, "SyslogFacility")) {
902 int facility;
903
904 r = sd_bus_message_read(message, "i", &facility);
905 if (r < 0)
906 return r;
907
908 if (!log_facility_unshifted_is_valid(facility))
909 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
910
911 if (mode != UNIT_CHECK) {
912 c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
913 unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility);
914 }
915
916 return 1;
917 } else if (streq(name, "Nice")) {
918 int n;
919
920 r = sd_bus_message_read(message, "i", &n);
921 if (r < 0)
922 return r;
923
924 if (n < PRIO_MIN || n >= PRIO_MAX)
925 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
926
927 if (mode != UNIT_CHECK) {
928 c->nice = n;
929 unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
930 }
931
932 return 1;
933
934 } else if (STR_IN_SET(name, "TTYPath", "RootDirectory")) {
935 const char *s;
936
937 r = sd_bus_message_read(message, "s", &s);
938 if (r < 0)
939 return r;
940
941 if (!path_is_absolute(s))
942 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name);
943
944 if (mode != UNIT_CHECK) {
945 if (streq(name, "TTYPath"))
946 r = free_and_strdup(&c->tty_path, s);
947 else {
948 assert(streq(name, "RootDirectory"));
949 r = free_and_strdup(&c->root_directory, s);
950 }
951 if (r < 0)
952 return r;
953
954 unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
955 }
956
957 return 1;
958
959 } else if (streq(name, "WorkingDirectory")) {
960 const char *s;
961 bool missing_ok;
962
963 r = sd_bus_message_read(message, "s", &s);
964 if (r < 0)
965 return r;
966
967 if (s[0] == '-') {
968 missing_ok = true;
969 s++;
970 } else
971 missing_ok = false;
972
973 if (!streq(s, "~") && !path_is_absolute(s))
974 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
975
976 if (mode != UNIT_CHECK) {
977 if (streq(s, "~")) {
978 c->working_directory = mfree(c->working_directory);
979 c->working_directory_home = true;
980 } else {
981 r = free_and_strdup(&c->working_directory, s);
982 if (r < 0)
983 return r;
984
985 c->working_directory_home = false;
986 }
987
988 c->working_directory_missing_ok = missing_ok;
989 unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
990 }
991
992 return 1;
993
994 } else if (streq(name, "StandardInput")) {
995 const char *s;
996 ExecInput p;
997
998 r = sd_bus_message_read(message, "s", &s);
999 if (r < 0)
1000 return r;
1001
1002 p = exec_input_from_string(s);
1003 if (p < 0)
1004 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard input name");
1005
1006 if (mode != UNIT_CHECK) {
1007 c->std_input = p;
1008
1009 unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s\n", exec_input_to_string(p));
1010 }
1011
1012 return 1;
1013
1014
1015 } else if (streq(name, "StandardOutput")) {
1016 const char *s;
1017 ExecOutput p;
1018
1019 r = sd_bus_message_read(message, "s", &s);
1020 if (r < 0)
1021 return r;
1022
1023 p = exec_output_from_string(s);
1024 if (p < 0)
1025 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard output name");
1026
1027 if (mode != UNIT_CHECK) {
1028 c->std_output = p;
1029
1030 unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s\n", exec_output_to_string(p));
1031 }
1032
1033 return 1;
1034
1035 } else if (streq(name, "StandardError")) {
1036 const char *s;
1037 ExecOutput p;
1038
1039 r = sd_bus_message_read(message, "s", &s);
1040 if (r < 0)
1041 return r;
1042
1043 p = exec_output_from_string(s);
1044 if (p < 0)
1045 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard error name");
1046
1047 if (mode != UNIT_CHECK) {
1048 c->std_error = p;
1049
1050 unit_write_drop_in_private_format(u, mode, name, "StandardError=%s\n", exec_output_to_string(p));
1051 }
1052
1053 return 1;
1054
1055 } else if (STR_IN_SET(name,
1056 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
1057 "PrivateTmp", "PrivateDevices", "PrivateNetwork",
1058 "NoNewPrivileges", "SyslogLevelPrefix")) {
1059 int b;
1060
1061 r = sd_bus_message_read(message, "b", &b);
1062 if (r < 0)
1063 return r;
1064
1065 if (mode != UNIT_CHECK) {
1066 if (streq(name, "IgnoreSIGPIPE"))
1067 c->ignore_sigpipe = b;
1068 else if (streq(name, "TTYVHangup"))
1069 c->tty_vhangup = b;
1070 else if (streq(name, "TTYReset"))
1071 c->tty_reset = b;
1072 else if (streq(name, "PrivateTmp"))
1073 c->private_tmp = b;
1074 else if (streq(name, "PrivateDevices"))
1075 c->private_devices = b;
1076 else if (streq(name, "PrivateNetwork"))
1077 c->private_network = b;
1078 else if (streq(name, "NoNewPrivileges"))
1079 c->no_new_privileges = b;
1080 else if (streq(name, "SyslogLevelPrefix"))
1081 c->syslog_level_prefix = b;
1082
1083 unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b));
1084 }
1085
1086 return 1;
1087
1088 } else if (streq(name, "UtmpIdentifier")) {
1089 const char *id;
1090
1091 r = sd_bus_message_read(message, "s", &id);
1092 if (r < 0)
1093 return r;
1094
1095 if (mode != UNIT_CHECK) {
1096 if (isempty(id))
1097 c->utmp_id = mfree(c->utmp_id);
1098 else if (free_and_strdup(&c->utmp_id, id) < 0)
1099 return -ENOMEM;
1100
1101 unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id));
1102 }
1103
1104 return 1;
1105
1106 } else if (streq(name, "UtmpMode")) {
1107 const char *s;
1108 ExecUtmpMode m;
1109
1110 r = sd_bus_message_read(message, "s", &s);
1111 if (r < 0)
1112 return r;
1113
1114 m = exec_utmp_mode_from_string(s);
1115 if (m < 0)
1116 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid utmp mode");
1117
1118 if (mode != UNIT_CHECK) {
1119 c->utmp_mode = m;
1120
1121 unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s\n", exec_utmp_mode_to_string(m));
1122 }
1123
1124 return 1;
1125
1126 } else if (streq(name, "PAMName")) {
1127 const char *n;
1128
1129 r = sd_bus_message_read(message, "s", &n);
1130 if (r < 0)
1131 return r;
1132
1133 if (mode != UNIT_CHECK) {
1134 if (isempty(n))
1135 c->pam_name = mfree(c->pam_name);
1136 else if (free_and_strdup(&c->pam_name, n) < 0)
1137 return -ENOMEM;
1138
1139 unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n));
1140 }
1141
1142 return 1;
1143
1144 } else if (streq(name, "Environment")) {
1145
1146 _cleanup_strv_free_ char **l = NULL;
1147
1148 r = sd_bus_message_read_strv(message, &l);
1149 if (r < 0)
1150 return r;
1151
1152 if (!strv_env_is_valid(l))
1153 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
1154
1155 if (mode != UNIT_CHECK) {
1156 _cleanup_free_ char *joined = NULL;
1157 char **e;
1158
1159 if (strv_length(l) == 0) {
1160 c->environment = strv_free(c->environment);
1161 unit_write_drop_in_private_format(u, mode, name, "Environment=\n");
1162 } else {
1163 e = strv_env_merge(2, c->environment, l);
1164 if (!e)
1165 return -ENOMEM;
1166
1167 strv_free(c->environment);
1168 c->environment = e;
1169
1170 joined = strv_join_quoted(c->environment);
1171 if (!joined)
1172 return -ENOMEM;
1173
1174 unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
1175 }
1176 }
1177
1178 return 1;
1179
1180 } else if (streq(name, "TimerSlackNSec")) {
1181
1182 nsec_t n;
1183
1184 r = sd_bus_message_read(message, "t", &n);
1185 if (r < 0)
1186 return r;
1187
1188 if (mode != UNIT_CHECK) {
1189 c->timer_slack_nsec = n;
1190 unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
1191 }
1192
1193 return 1;
1194
1195 } else if (streq(name, "OOMScoreAdjust")) {
1196 int oa;
1197
1198 r = sd_bus_message_read(message, "i", &oa);
1199 if (r < 0)
1200 return r;
1201
1202 if (!oom_score_adjust_is_valid(oa))
1203 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
1204
1205 if (mode != UNIT_CHECK) {
1206 c->oom_score_adjust = oa;
1207 c->oom_score_adjust_set = true;
1208 unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa);
1209 }
1210
1211 return 1;
1212
1213 } else if (streq(name, "EnvironmentFiles")) {
1214
1215 _cleanup_free_ char *joined = NULL;
1216 _cleanup_fclose_ FILE *f = NULL;
1217 _cleanup_free_ char **l = NULL;
1218 size_t size = 0;
1219 char **i;
1220
1221 r = sd_bus_message_enter_container(message, 'a', "(sb)");
1222 if (r < 0)
1223 return r;
1224
1225 f = open_memstream(&joined, &size);
1226 if (!f)
1227 return -ENOMEM;
1228
1229 STRV_FOREACH(i, c->environment_files)
1230 fprintf(f, "EnvironmentFile=%s\n", *i);
1231
1232 while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
1233 const char *path;
1234 int b;
1235
1236 r = sd_bus_message_read(message, "sb", &path, &b);
1237 if (r < 0)
1238 return r;
1239
1240 r = sd_bus_message_exit_container(message);
1241 if (r < 0)
1242 return r;
1243
1244 if (!isempty(path) && !path_is_absolute(path))
1245 return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
1246
1247 if (mode != UNIT_CHECK) {
1248 char *buf = NULL;
1249
1250 buf = strjoin(b ? "-" : "", path, NULL);
1251 if (!buf)
1252 return -ENOMEM;
1253
1254 fprintf(f, "EnvironmentFile=%s\n", buf);
1255
1256 r = strv_consume(&l, buf);
1257 if (r < 0)
1258 return r;
1259 }
1260 }
1261 if (r < 0)
1262 return r;
1263
1264 r = sd_bus_message_exit_container(message);
1265 if (r < 0)
1266 return r;
1267
1268 r = fflush_and_check(f);
1269 if (r < 0)
1270 return r;
1271
1272 if (mode != UNIT_CHECK) {
1273 if (strv_isempty(l)) {
1274 c->environment_files = strv_free(c->environment_files);
1275 unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n");
1276 } else {
1277 r = strv_extend_strv(&c->environment_files, l, true);
1278 if (r < 0)
1279 return r;
1280
1281 unit_write_drop_in_private(u, mode, name, joined);
1282 }
1283 }
1284
1285 return 1;
1286
1287 } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
1288
1289 _cleanup_strv_free_ char **l = NULL;
1290 char ***dirs;
1291 char **p;
1292
1293 r = sd_bus_message_read_strv(message, &l);
1294 if (r < 0)
1295 return r;
1296
1297 STRV_FOREACH(p, l) {
1298 int offset;
1299 if (!utf8_is_valid(*p))
1300 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
1301
1302 offset = **p == '-';
1303 if (!path_is_absolute(*p + offset))
1304 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
1305 }
1306
1307 if (mode != UNIT_CHECK) {
1308 _cleanup_free_ char *joined = NULL;
1309
1310 if (streq(name, "ReadWriteDirectories"))
1311 dirs = &c->read_write_dirs;
1312 else if (streq(name, "ReadOnlyDirectories"))
1313 dirs = &c->read_only_dirs;
1314 else if (streq(name, "InaccessibleDirectories"))
1315 dirs = &c->inaccessible_dirs;
1316
1317 if (strv_length(l) == 0) {
1318 *dirs = strv_free(*dirs);
1319 unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
1320 } else {
1321 r = strv_extend_strv(dirs, l, true);
1322
1323 if (r < 0)
1324 return -ENOMEM;
1325
1326 joined = strv_join_quoted(*dirs);
1327 if (!joined)
1328 return -ENOMEM;
1329
1330 unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
1331 }
1332
1333 }
1334
1335 return 1;
1336
1337 } else if (rlimit_from_string(name) >= 0) {
1338 uint64_t rl;
1339 rlim_t x;
1340
1341 r = sd_bus_message_read(message, "t", &rl);
1342 if (r < 0)
1343 return r;
1344
1345 if (rl == (uint64_t) -1)
1346 x = RLIM_INFINITY;
1347 else {
1348 x = (rlim_t) rl;
1349
1350 if ((uint64_t) x != rl)
1351 return -ERANGE;
1352 }
1353
1354 if (mode != UNIT_CHECK) {
1355 int z;
1356
1357 z = rlimit_from_string(name);
1358
1359 if (!c->rlimit[z]) {
1360 c->rlimit[z] = new(struct rlimit, 1);
1361 if (!c->rlimit[z])
1362 return -ENOMEM;
1363 }
1364
1365 c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
1366
1367 if (x == RLIM_INFINITY)
1368 unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
1369 else
1370 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
1371 }
1372
1373 return 1;
1374 }
1375
1376 return 0;
1377 }