chiark / gitweb /
45bfecf80d32c43aff95f56cc726c147153683a0
[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_start_limit_action, start_limit_action, StartLimitAction);
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_start_limit_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("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
55         SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
56         SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
57         SD_BUS_PROPERTY("GuessMainPID", "b", bus_property_get_bool, offsetof(Service, guess_main_pid), SD_BUS_VTABLE_PROPERTY_CONST),
58         SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
59         SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60         SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
61         SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
62         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
63         BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
64         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
65         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
66         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
67         BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
68         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
69         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
70         SD_BUS_VTABLE_END
71 };
72
73 static int bus_service_set_transient_property(
74                 Service *s,
75                 const char *name,
76                 sd_bus_message *message,
77                 UnitSetPropertiesMode mode,
78                 sd_bus_error *error) {
79
80         int r;
81
82         assert(s);
83         assert(name);
84         assert(message);
85
86         if (streq(name, "RemainAfterExit")) {
87                 int b;
88
89                 r = sd_bus_message_read(message, "b", &b);
90                 if (r < 0)
91                         return r;
92
93                 if (mode != UNIT_CHECK) {
94                         s->remain_after_exit = b;
95                         unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
96                 }
97
98                 return 1;
99
100         } else if (streq(name, "Type")) {
101                 const char *t;
102                 ServiceType k;
103
104                 r = sd_bus_message_read(message, "s", &t);
105                 if (r < 0)
106                         return r;
107
108                 k = service_type_from_string(t);
109                 if (k < 0)
110                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t);
111
112                 if (mode != UNIT_CHECK) {
113                         s->type = k;
114                         unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type));
115                 }
116
117                 return 1;
118
119         } else if (streq(name, "ExecStart")) {
120                 unsigned n = 0;
121
122                 r = sd_bus_message_enter_container(message, 'a', "(sasb)");
123                 if (r < 0)
124                         return r;
125
126                 while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
127                         _cleanup_strv_free_ char **argv = NULL;
128                         const char *path;
129                         int b;
130
131                         r = sd_bus_message_read(message, "s", &path);
132                         if (r < 0)
133                                 return r;
134
135                         if (!path_is_absolute(path))
136                                 return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
137
138                         r = sd_bus_message_read_strv(message, &argv);
139                         if (r < 0)
140                                 return r;
141
142                         r = sd_bus_message_read(message, "b", &b);
143                         if (r < 0)
144                                 return r;
145
146                         r = sd_bus_message_exit_container(message);
147                         if (r < 0)
148                                 return r;
149
150                         if (mode != UNIT_CHECK) {
151                                 ExecCommand *c;
152
153                                 c = new0(ExecCommand, 1);
154                                 if (!c)
155                                         return -ENOMEM;
156
157                                 c->path = strdup(path);
158                                 if (!c->path) {
159                                         free(c);
160                                         return -ENOMEM;
161                                 }
162
163                                 c->argv = argv;
164                                 argv = NULL;
165
166                                 c->ignore = b;
167
168                                 path_kill_slashes(c->path);
169                                 exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
170                         }
171
172                         n++;
173                 }
174
175                 if (r < 0)
176                         return r;
177
178                 r = sd_bus_message_exit_container(message);
179                 if (r < 0)
180                         return r;
181
182                 if (mode != UNIT_CHECK) {
183                         _cleanup_free_ char *buf = NULL;
184                         _cleanup_fclose_ FILE *f = NULL;
185                         ExecCommand *c;
186                         size_t size = 0;
187
188                         if (n == 0) {
189                                 exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
190                                 s->exec_command[SERVICE_EXEC_START] = NULL;
191                         }
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 }