chiark / gitweb /
core: make exec_command_free_list return NULL
[elogind.git] / src / core / dbus-service.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 "strv.h"
23 #include "path-util.h"
24 #include "unit.h"
25 #include "service.h"
26 #include "dbus-unit.h"
27 #include "dbus-execute.h"
28 #include "dbus-kill.h"
29 #include "dbus-cgroup.h"
30 #include "dbus-service.h"
31 #include "bus-util.h"
32
33 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
35 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
36 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess);
37 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
38
39 const sd_bus_vtable bus_service_vtable[] = {
40         SD_BUS_VTABLE_START(0),
41         SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
42         SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST),
43         SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST),
44         SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, offsetof(Service, notify_access), SD_BUS_VTABLE_PROPERTY_CONST),
45         SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
46         SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
47         SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
48         SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
49         BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
50         SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
51         SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
52         SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
53         SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
54         SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
55         SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
56         SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
57         SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
58         SD_BUS_PROPERTY("GuessMainPID", "b", bus_property_get_bool, offsetof(Service, guess_main_pid), SD_BUS_VTABLE_PROPERTY_CONST),
59         SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60         SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
61         SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
62         SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
63         SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
64         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
65         BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
67         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
68         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
69         BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
70         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
71         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
72         SD_BUS_VTABLE_END
73 };
74
75 static int bus_service_set_transient_property(
76                 Service *s,
77                 const char *name,
78                 sd_bus_message *message,
79                 UnitSetPropertiesMode mode,
80                 sd_bus_error *error) {
81
82         int r;
83
84         assert(s);
85         assert(name);
86         assert(message);
87
88         if (streq(name, "RemainAfterExit")) {
89                 int b;
90
91                 r = sd_bus_message_read(message, "b", &b);
92                 if (r < 0)
93                         return r;
94
95                 if (mode != UNIT_CHECK) {
96                         s->remain_after_exit = b;
97                         unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
98                 }
99
100                 return 1;
101
102         } else if (streq(name, "Type")) {
103                 const char *t;
104                 ServiceType k;
105
106                 r = sd_bus_message_read(message, "s", &t);
107                 if (r < 0)
108                         return r;
109
110                 k = service_type_from_string(t);
111                 if (k < 0)
112                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t);
113
114                 if (mode != UNIT_CHECK) {
115                         s->type = k;
116                         unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type));
117                 }
118
119                 return 1;
120
121         } else if (streq(name, "ExecStart")) {
122                 unsigned n = 0;
123
124                 r = sd_bus_message_enter_container(message, 'a', "(sasb)");
125                 if (r < 0)
126                         return r;
127
128                 while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
129                         _cleanup_strv_free_ char **argv = NULL;
130                         const char *path;
131                         int b;
132
133                         r = sd_bus_message_read(message, "s", &path);
134                         if (r < 0)
135                                 return r;
136
137                         if (!path_is_absolute(path))
138                                 return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
139
140                         r = sd_bus_message_read_strv(message, &argv);
141                         if (r < 0)
142                                 return r;
143
144                         r = sd_bus_message_read(message, "b", &b);
145                         if (r < 0)
146                                 return r;
147
148                         r = sd_bus_message_exit_container(message);
149                         if (r < 0)
150                                 return r;
151
152                         if (mode != UNIT_CHECK) {
153                                 ExecCommand *c;
154
155                                 c = new0(ExecCommand, 1);
156                                 if (!c)
157                                         return -ENOMEM;
158
159                                 c->path = strdup(path);
160                                 if (!c->path) {
161                                         free(c);
162                                         return -ENOMEM;
163                                 }
164
165                                 c->argv = argv;
166                                 argv = NULL;
167
168                                 c->ignore = b;
169
170                                 path_kill_slashes(c->path);
171                                 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
172                         }
173
174                         n++;
175                 }
176
177                 if (r < 0)
178                         return r;
179
180                 r = sd_bus_message_exit_container(message);
181                 if (r < 0)
182                         return r;
183
184                 if (mode != UNIT_CHECK) {
185                         _cleanup_free_ char *buf = NULL;
186                         _cleanup_fclose_ FILE *f = NULL;
187                         ExecCommand *c;
188                         size_t size = 0;
189
190                         if (n == 0)
191                                 s->exec_command[SERVICE_EXEC_START] = exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
192
193                         f = open_memstream(&buf, &size);
194                         if (!f)
195                                 return -ENOMEM;
196
197                         fputs("ExecStart=\n", f);
198
199                         LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
200                                 _cleanup_free_ char *a;
201
202                                 a = strv_join_quoted(c->argv);
203                                 if (!a)
204                                         return -ENOMEM;
205
206                                 fprintf(f, "ExecStart=%s@%s %s\n",
207                                         c->ignore ? "-" : "",
208                                         c->path,
209                                         a);
210                         }
211
212                         fflush(f);
213                         unit_write_drop_in_private(UNIT(s), mode, name, buf);
214                 }
215
216                 return 1;
217         }
218
219         return 0;
220 }
221
222 int bus_service_set_property(
223                 Unit *u,
224                 const char *name,
225                 sd_bus_message *message,
226                 UnitSetPropertiesMode mode,
227                 sd_bus_error *error) {
228
229         Service *s = SERVICE(u);
230         int r;
231
232         assert(s);
233         assert(name);
234         assert(message);
235
236         r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
237         if (r != 0)
238                 return r;
239
240         if (u->transient && u->load_state == UNIT_STUB) {
241                 /* This is a transient unit, let's load a little more */
242
243                 r = bus_service_set_transient_property(s, name, message, mode, error);
244                 if (r != 0)
245                         return r;
246
247                 r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, mode, error);
248                 if (r != 0)
249                         return r;
250
251                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
252                 if (r != 0)
253                         return r;
254         }
255
256         return 0;
257 }
258
259 int bus_service_commit_properties(Unit *u) {
260         assert(u);
261
262         unit_update_cgroup_members_masks(u);
263         unit_realize_cgroup(u);
264
265         return 0;
266 }