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