chiark / gitweb /
core: allow User=, Group=, Nice=, Environment=, Type= to be passed when creating...
[elogind.git] / src / core / dbus-execute.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/prctl.h>
23
24 #include "bus-util.h"
25 #include "missing.h"
26 #include "ioprio.h"
27 #include "strv.h"
28 #include "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 }