chiark / gitweb /
machined: optionally, allow registration of pre-existing units (scopes
[elogind.git] / src / machine / machine-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 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 <errno.h>
23 #include <string.h>
24 #include <sys/capability.h>
25
26 #include "bus-util.h"
27 #include "strv.h"
28 #include "machine.h"
29
30 static int property_get_id(
31                 sd_bus *bus,
32                 const char *path,
33                 const char *interface,
34                 const char *property,
35                 sd_bus_message *reply,
36                 void *userdata,
37                 sd_bus_error *error) {
38
39         Machine *m = userdata;
40         int r;
41
42         assert(bus);
43         assert(reply);
44         assert(m);
45
46         r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
47         if (r < 0)
48                 return r;
49
50         return 1;
51 }
52
53 static int property_get_state(
54                 sd_bus *bus,
55                 const char *path,
56                 const char *interface,
57                 const char *property,
58                 sd_bus_message *reply,
59                 void *userdata,
60                 sd_bus_error *error) {
61
62         Machine *m = userdata;
63         const char *state;
64         int r;
65
66         assert(bus);
67         assert(reply);
68         assert(m);
69
70         state = machine_state_to_string(machine_get_state(m));
71
72         r = sd_bus_message_append_basic(reply, 's', state);
73         if (r < 0)
74                 return r;
75
76         return 1;
77 }
78
79 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
80
81 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
82         Machine *m = userdata;
83         int r;
84
85         assert(bus);
86         assert(message);
87         assert(m);
88
89         r = machine_stop(m);
90         if (r < 0)
91                 return r;
92
93         return sd_bus_reply_method_return(message, NULL);
94 }
95
96 static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
97         Machine *m = userdata;
98         const char *swho;
99         int32_t signo;
100         KillWho who;
101         int r;
102
103         assert(bus);
104         assert(message);
105         assert(m);
106
107         r = sd_bus_message_read(message, "si", &swho, &signo);
108         if (r < 0)
109                 return r;
110
111         if (isempty(swho))
112                 who = KILL_ALL;
113         else {
114                 who = kill_who_from_string(swho);
115                 if (who < 0)
116                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
117         }
118
119         if (signo <= 0 || signo >= _NSIG)
120                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
121
122         r = machine_kill(m, who, signo);
123         if (r < 0)
124                 return r;
125
126         return sd_bus_reply_method_return(message, NULL);
127 }
128
129 const sd_bus_vtable machine_vtable[] = {
130         SD_BUS_VTABLE_START(0),
131         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
132         SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
133         BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
134         SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
135         SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
136         SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
137         SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
138         SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
139         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
140         SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
141         SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
142         SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
143         SD_BUS_VTABLE_END
144 };
145
146 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
147         Manager *m = userdata;
148         Machine *machine;
149         int r;
150
151         assert(bus);
152         assert(path);
153         assert(interface);
154         assert(found);
155         assert(m);
156
157         if (streq(path, "/org/freedesktop/machine1/machine/self")) {
158                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
159                 sd_bus_message *message;
160                 pid_t pid;
161
162                 message = sd_bus_get_current(bus);
163                 if (!message)
164                         return 0;
165
166                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
167                 if (r < 0)
168                         return r;
169
170                 r = sd_bus_creds_get_pid(creds, &pid);
171                 if (r < 0)
172                         return r;
173
174                 r = manager_get_machine_by_pid(m, pid, &machine);
175                 if (r <= 0)
176                         return 0;
177         } else {
178                 _cleanup_free_ char *e = NULL;
179                 const char *p;
180
181                 p = startswith(path, "/org/freedesktop/machine1/machine/");
182                 if (!p)
183                         return 0;
184
185                 e = sd_bus_label_unescape(p);
186                 if (!e)
187                         return -ENOMEM;
188
189                 machine = hashmap_get(m->machines, e);
190                 if (!machine)
191                         return 0;
192         }
193
194         *found = machine;
195         return 1;
196 }
197
198 char *machine_bus_path(Machine *m) {
199         _cleanup_free_ char *e = NULL;
200
201         assert(m);
202
203         e = sd_bus_label_escape(m->name);
204         if (!e)
205                 return NULL;
206
207         return strappend("/org/freedesktop/machine1/machine/", e);
208 }
209
210 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
211         _cleanup_strv_free_ char **l = NULL;
212         Machine *machine = NULL;
213         Manager *m = userdata;
214         Iterator i;
215         int r;
216
217         assert(bus);
218         assert(path);
219         assert(nodes);
220
221         HASHMAP_FOREACH(machine, m->machines, i) {
222                 char *p;
223
224                 p = machine_bus_path(machine);
225                 if (!p)
226                         return -ENOMEM;
227
228                 r = strv_push(&l, p);
229                 if (r < 0) {
230                         free(p);
231                         return r;
232                 }
233         }
234
235         *nodes = l;
236         l = NULL;
237
238         return 1;
239 }
240
241 int machine_send_signal(Machine *m, bool new_machine) {
242         _cleanup_free_ char *p = NULL;
243
244         assert(m);
245
246         p = machine_bus_path(m);
247         if (!p)
248                 return -ENOMEM;
249
250         return sd_bus_emit_signal(
251                         m->manager->bus,
252                         "/org/freedesktop/machine1",
253                         "org.freedesktop.machine1.Manager",
254                         new_machine ? "MachineNew" : "MachineRemoved",
255                         "so", m->name, p);
256 }
257
258 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
259         _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
260         _cleanup_free_ char *p = NULL;
261
262         assert(m);
263
264         if (!m->create_message)
265                 return 0;
266
267         c = m->create_message;
268         m->create_message = NULL;
269
270         if (error)
271                 return sd_bus_reply_method_error(c, error);
272
273         /* Update the machine state file before we notify the client
274          * about the result. */
275         machine_save(m);
276
277         p = machine_bus_path(m);
278         if (!p)
279                 return -ENOMEM;
280
281         return sd_bus_reply_method_return(c, "o", p);
282 }