chiark / gitweb /
core: Added support for ERRNO NOTIFY_SOCKET message parsing, and added StatusErrno...
[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                                 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
192                                 s->exec_command[SERVICE_EXEC_START] = NULL;
193                         }
194
195                         f = open_memstream(&buf, &size);
196                         if (!f)
197                                 return -ENOMEM;
198
199                         fputs("ExecStart=\n", f);
200
201                         LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
202                                 _cleanup_free_ char *a;
203
204                                 a = strv_join_quoted(c->argv);
205                                 if (!a)
206                                         return -ENOMEM;
207
208                                 fprintf(f, "ExecStart=%s@%s %s\n",
209                                         c->ignore ? "-" : "",
210                                         c->path,
211                                         a);
212                         }
213
214                         fflush(f);
215                         unit_write_drop_in_private(UNIT(s), mode, name, buf);
216                 }
217
218                 return 1;
219         }
220
221         return 0;
222 }
223
224 int bus_service_set_property(
225                 Unit *u,
226                 const char *name,
227                 sd_bus_message *message,
228                 UnitSetPropertiesMode mode,
229                 sd_bus_error *error) {
230
231         Service *s = SERVICE(u);
232         int r;
233
234         assert(s);
235         assert(name);
236         assert(message);
237
238         r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
239         if (r != 0)
240                 return r;
241
242         if (u->transient && u->load_state == UNIT_STUB) {
243                 /* This is a transient unit, let's load a little more */
244
245                 r = bus_service_set_transient_property(s, name, message, mode, error);
246                 if (r != 0)
247                         return r;
248
249                 r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, mode, error);
250                 if (r != 0)
251                         return r;
252
253                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
254                 if (r != 0)
255                         return r;
256         }
257
258         return 0;
259 }
260
261 int bus_service_commit_properties(Unit *u) {
262         assert(u);
263
264         unit_update_cgroup_members_masks(u);
265         unit_realize_cgroup(u);
266
267         return 0;
268 }