chiark / gitweb /
timesyncd: only run when the system has a carrier on a network interface
[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 "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 }