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