chiark / gitweb /
c6a794b5e838f483b1ca5cade04ef48d1ebaa814
[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
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 *userdata, void **found, sd_bus_error *error) {
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, void *userdata, char ***nodes, sd_bus_error *error) {
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 }