chiark / gitweb /
c9e3bb7c758d0793dafe7338cb4f7afbeba55c3a
[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_consume(&l, p);
229                 if (r < 0)
230                         return r;
231         }
232
233         *nodes = l;
234         l = NULL;
235
236         return 1;
237 }
238
239 int machine_send_signal(Machine *m, bool new_machine) {
240         _cleanup_free_ char *p = NULL;
241
242         assert(m);
243
244         p = machine_bus_path(m);
245         if (!p)
246                 return -ENOMEM;
247
248         return sd_bus_emit_signal(
249                         m->manager->bus,
250                         "/org/freedesktop/machine1",
251                         "org.freedesktop.machine1.Manager",
252                         new_machine ? "MachineNew" : "MachineRemoved",
253                         "so", m->name, p);
254 }
255
256 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
257         _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
258         _cleanup_free_ char *p = NULL;
259
260         assert(m);
261
262         if (!m->create_message)
263                 return 0;
264
265         c = m->create_message;
266         m->create_message = NULL;
267
268         if (error)
269                 return sd_bus_reply_method_error(c, error);
270
271         /* Update the machine state file before we notify the client
272          * about the result. */
273         machine_save(m);
274
275         p = machine_bus_path(m);
276         if (!p)
277                 return -ENOMEM;
278
279         return sd_bus_reply_method_return(c, "o", p);
280 }