chiark / gitweb /
Make sure that keys are properly removed from hashmap
[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("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
64         BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
65         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
66         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
67         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
68         BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
69         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
70         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
71         SD_BUS_VTABLE_END
72 };
73
74 static int bus_service_set_transient_property(
75                 Service *s,
76                 const char *name,
77                 sd_bus_message *message,
78                 UnitSetPropertiesMode mode,
79                 sd_bus_error *error) {
80
81         int r;
82
83         assert(s);
84         assert(name);
85         assert(message);
86
87         if (streq(name, "RemainAfterExit")) {
88                 int b;
89
90                 r = sd_bus_message_read(message, "b", &b);
91                 if (r < 0)
92                         return r;
93
94                 if (mode != UNIT_CHECK) {
95                         s->remain_after_exit = b;
96                         unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
97                 }
98
99                 return 1;
100
101         } else if (streq(name, "Type")) {
102                 const char *t;
103                 ServiceType k;
104
105                 r = sd_bus_message_read(message, "s", &t);
106                 if (r < 0)
107                         return r;
108
109                 k = service_type_from_string(t);
110                 if (k < 0)
111                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t);
112
113                 if (mode != UNIT_CHECK) {
114                         s->type = k;
115                         unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type));
116                 }
117
118                 return 1;
119
120         } else if (streq(name, "ExecStart")) {
121                 unsigned n = 0;
122
123                 r = sd_bus_message_enter_container(message, 'a', "(sasb)");
124                 if (r < 0)
125                         return r;
126
127                 while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
128                         _cleanup_strv_free_ char **argv = NULL;
129                         const char *path;
130                         int b;
131
132                         r = sd_bus_message_read(message, "s", &path);
133                         if (r < 0)
134                                 return r;
135
136                         if (!path_is_absolute(path))
137                                 return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
138
139                         r = sd_bus_message_read_strv(message, &argv);
140                         if (r < 0)
141                                 return r;
142
143                         r = sd_bus_message_read(message, "b", &b);
144                         if (r < 0)
145                                 return r;
146
147                         r = sd_bus_message_exit_container(message);
148                         if (r < 0)
149                                 return r;
150
151                         if (mode != UNIT_CHECK) {
152                                 ExecCommand *c;
153
154                                 c = new0(ExecCommand, 1);
155                                 if (!c)
156                                         return -ENOMEM;
157
158                                 c->path = strdup(path);
159                                 if (!c->path) {
160                                         free(c);
161                                         return -ENOMEM;
162                                 }
163
164                                 c->argv = argv;
165                                 argv = NULL;
166
167                                 c->ignore = b;
168
169                                 path_kill_slashes(c->path);
170                                 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
171                         }
172
173                         n++;
174                 }
175
176                 if (r < 0)
177                         return r;
178
179                 r = sd_bus_message_exit_container(message);
180                 if (r < 0)
181                         return r;
182
183                 if (mode != UNIT_CHECK) {
184                         _cleanup_free_ char *buf = NULL;
185                         _cleanup_fclose_ FILE *f = NULL;
186                         ExecCommand *c;
187                         size_t size = 0;
188
189                         if (n == 0) {
190                                 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
191                                 s->exec_command[SERVICE_EXEC_START] = NULL;
192                         }
193
194                         f = open_memstream(&buf, &size);
195                         if (!f)
196                                 return -ENOMEM;
197
198                         fputs("ExecStart=\n", f);
199
200                         LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
201                                 _cleanup_free_ char *a;
202
203                                 a = strv_join_quoted(c->argv);
204                                 if (!a)
205                                         return -ENOMEM;
206
207                                 fprintf(f, "ExecStart=%s@%s %s\n",
208                                         c->ignore ? "-" : "",
209                                         c->path,
210                                         a);
211                         }
212
213                         fflush(f);
214                         unit_write_drop_in_private(UNIT(s), mode, name, buf);
215                 }
216
217                 return 1;
218         }
219
220         return 0;
221 }
222
223 int bus_service_set_property(
224                 Unit *u,
225                 const char *name,
226                 sd_bus_message *message,
227                 UnitSetPropertiesMode mode,
228                 sd_bus_error *error) {
229
230         Service *s = SERVICE(u);
231         int r;
232
233         assert(s);
234         assert(name);
235         assert(message);
236
237         r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
238         if (r != 0)
239                 return r;
240
241         if (u->transient && u->load_state == UNIT_STUB) {
242                 /* This is a transient unit, let's load a little more */
243
244                 r = bus_service_set_transient_property(s, name, message, mode, error);
245                 if (r != 0)
246                         return r;
247
248                 r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, mode, error);
249                 if (r != 0)
250                         return r;
251
252                 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
253                 if (r != 0)
254                         return r;
255         }
256
257         return 0;
258 }
259
260 int bus_service_commit_properties(Unit *u) {
261         assert(u);
262
263         unit_update_cgroup_members_masks(u);
264         unit_realize_cgroup(u);
265
266         return 0;
267 }