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