chiark / gitweb /
bus: make driverd code more similar to other daemons, and make it exit on idle among...
[elogind.git] / src / bus-driverd / bus-driverd.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Daniel Mack
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <locale.h>
25 #include <string.h>
26 #include <poll.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/timex.h>
31 #include <sys/utsname.h>
32 #include <unistd.h>
33
34 #include "kdbus.h"
35 #include "sd-bus.h"
36 #include "bus-internal.h"
37
38 #include "sd-daemon.h"
39 #include "sd-event.h"
40 #include "event-util.h"
41 #include "bus-util.h"
42 #include "bus-error.h"
43 #include "bus-message.h"
44 #include "bus-kernel.h"
45 #include "socket-util.h"
46 #include "util.h"
47 #include "build.h"
48 #include "strv.h"
49 #include "sd-id128.h"
50 #include "async.h"
51 #include "hashmap.h"
52 #include "def.h"
53
54 /*
55  * TODO:
56  *
57  * AddMatch / RemoveMatch
58  * ListActivatableNames
59  * StartServiceByName
60  */
61
62 static int driver_name_info_error(sd_bus *bus, sd_bus_message *m, const char *name, int error_code) {
63
64         if (error_code == -ENXIO || error_code == -ENOENT)
65                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER,
66                                                   "Could not get owner of name '%s': no such name",
67                                                   name);
68
69         return sd_bus_reply_method_errno(m, error_code, NULL);
70 }
71
72 static int driver_add_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
73
74         char *arg0, *match;
75         int r;
76
77         r = sd_bus_message_read(m, "s", &arg0);
78         if (r < 0)
79                 return r;
80
81         match = strdup(arg0);
82         if (!match)
83                 return -ENOMEM;
84
85         /* FIXME */
86
87         return sd_bus_reply_method_return(m, NULL);
88 }
89
90 static int driver_remove_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
91
92         char *arg0;
93         int r;
94
95         r = sd_bus_message_read(m, "s", &arg0);
96         if (r < 0)
97                 return r;
98
99         /* FIXME */
100
101         return sd_bus_reply_method_return(m, NULL);
102 }
103
104 static int driver_get_security_ctx(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
105
106         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
107         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
108         char *arg0;
109         int r;
110
111         r = sd_bus_message_read(m, "s", &arg0);
112         if (r < 0)
113                 return r;
114
115         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_SELINUX_CONTEXT, &creds);
116         if (r < 0) {
117                 if (r == -ENOENT)
118                         return driver_name_info_error(bus, m, arg0, r);
119                 else
120                         return r;
121         }
122
123         r = sd_bus_message_new_method_return(m, &reply);
124         if (r < 0)
125                 return r;
126
127         r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
128         if (r < 0)
129                 return r;
130
131         return sd_bus_send(bus, reply, NULL);
132 }
133
134 static int driver_get_pid(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
135
136         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
137         char *arg0;
138         int r;
139
140         r = sd_bus_message_read(m, "s", &arg0);
141         if (r < 0)
142                 return r;
143
144         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_PID, &creds);
145         if (r < 0)
146                 return r;
147
148         return sd_bus_reply_method_return(m, "u", creds->pid);
149 }
150
151 static int driver_get_user(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
152
153         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
154         char *arg0;
155         int r;
156
157         r = sd_bus_message_read(m, "s", &arg0);
158         if (r < 0)
159                 return r;
160
161         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UID, &creds);
162         if (r < 0) {
163                 if (r == -ENOENT)
164                         return driver_name_info_error(bus, m, arg0, r);
165                 else
166                         return r;
167         }
168
169         return sd_bus_reply_method_return(m, "u", creds->uid);
170 }
171
172 static int driver_get_id(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
173
174         sd_id128_t server_id;
175         char buf[SD_ID128_STRING_MAX];
176         int r;
177
178         r = sd_bus_get_server_id(bus, &server_id);
179         if (r < 0)
180                 return r;
181
182         return sd_bus_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
183 }
184
185 static int driver_get_name_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
186
187         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
188         _cleanup_free_ char *owner = NULL;
189         char *arg0;
190         int r;
191
192         r = sd_bus_message_read(m, "s", &arg0);
193         if (r < 0)
194                 return r;
195
196         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UNIQUE_NAME, &creds);
197         if (r < 0) {
198                 if (r == -ENOENT)
199                         return driver_name_info_error(bus, m, arg0, r);
200                 else
201                         return r;
202         }
203
204         return sd_bus_reply_method_return(m, "s", creds->unique_name);
205 }
206
207 static int driver_hello(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
208
209         return sd_bus_reply_method_return(m, "s", m->sender);
210 }
211
212 static int driver_list_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
213
214         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
215         _cleanup_strv_free_ char **names = NULL;
216         int r;
217
218         r = sd_bus_list_names(bus, &names, NULL);
219         if (r < 0)
220                 return r;
221
222         r = sd_bus_message_new_method_return(m, &reply);
223         if (r < 0)
224                 return r;
225
226         r = sd_bus_message_append_strv(reply, names);
227         if (r < 0)
228                 return r;
229
230         return sd_bus_send(bus, reply, NULL);
231 }
232
233 static int driver_list_activatable_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
234
235         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
236         _cleanup_strv_free_ char **names = NULL;
237         int r;
238
239         r = sd_bus_list_names(bus, NULL, &names);
240         if (r < 0)
241                 return r;
242
243         r = sd_bus_message_new_method_return(m, &reply);
244         if (r < 0)
245                 return r;
246
247         r = sd_bus_message_append_strv(reply, names);
248         if (r < 0)
249                 return r;
250
251         return sd_bus_send(bus, reply, NULL);
252 }
253
254 static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
255
256         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
257         struct kdbus_cmd_name_list cmd = {};
258         struct kdbus_name_list *name_list;
259         struct kdbus_cmd_name *name;
260         _cleanup_strv_free_ char **owners = NULL;
261         char *arg0;
262         int r;
263
264         r = sd_bus_message_read(m, "s", &arg0);
265         if (r < 0)
266                 return r;
267
268         cmd.flags = KDBUS_NAME_LIST_QUEUED;
269
270         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
271         if (r < 0)
272                 return -errno;
273
274         name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
275
276         KDBUS_ITEM_FOREACH(name, name_list, names) {
277                 if (name->size > sizeof(*name) && !streq(name->name, arg0)) {
278                         char *n;
279
280                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0)
281                                 return -ENOMEM;
282
283                         r = strv_push(&owners, n);
284                         if (r < 0) {
285                                 free(n);
286                                 return -ENOMEM;
287                         }
288                 }
289         }
290
291         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd.offset);
292         if (r < 0)
293                 return -errno;
294
295         r = sd_bus_message_new_method_return(m, &reply);
296         if (r < 0)
297                 return r;
298
299         r = sd_bus_message_append_strv(reply, owners);
300         if (r < 0)
301                 return r;
302
303         return sd_bus_send(bus, reply, NULL);
304 }
305
306 static int driver_name_has_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
307
308         char *arg0;
309         int r;
310
311         r = sd_bus_message_read(m, "s", &arg0);
312         if (r < 0)
313                 return r;
314
315         r = sd_bus_get_owner(bus, arg0, 0, NULL);
316         if (r < 0 && r != -ENOENT)
317                 return r;
318
319         return sd_bus_reply_method_return(m, "b", r == 0);
320 }
321
322 static int driver_request_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
323
324         struct kdbus_cmd_name *cmd_name;
325         uint32_t flags;
326         size_t size;
327         uint64_t id;
328         char *name;
329         int r;
330
331         r = sd_bus_message_read(m, "su", &name, &flags);
332         if (r < 0)
333                 return r;
334
335         size = sizeof(*cmd_name) + strlen(name) + 1;
336
337         cmd_name = alloca(size);
338         memset(cmd_name, 0, size);
339         strcpy(cmd_name->name, name);
340         cmd_name->size = size;
341         kdbus_translate_request_name_flags(flags, (uint64_t *) &cmd_name->conn_flags);
342
343         /* This function is open-coded because we request the name 'on behalf'
344          * of the requesting connection */
345         r = bus_kernel_parse_unique_name(m->sender, &id);
346         if (r < 0)
347                 return r;
348
349         cmd_name->id = id;
350
351         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_ACQUIRE, cmd_name);
352         if (r < 0)
353                 return r;
354
355         return sd_bus_reply_method_return(m, "u", 0);
356 }
357
358 static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
359
360         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
361         char *s;
362         int r;
363
364         return sd_bus_reply_method_return(m, "u", 2);
365
366         r = sd_bus_message_read(m, "s", &s);
367         if (r < 0)
368                 return r;
369
370         /* FIXME */
371
372         return sd_bus_send(bus, reply, NULL);
373 }
374
375 static int driver_unsupported(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
376         return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
377 }
378
379 static const sd_bus_vtable driver_vtable[] = {
380         SD_BUS_VTABLE_START(0),
381         SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, 0),
382         SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_ctx, 0),
383         SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, 0),
384         SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, 0),
385         SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, 0),
386         SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, 0),
387         SD_BUS_METHOD("Hello", NULL, "s", driver_hello, 0),
388         SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, 0),
389         SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, 0),
390         SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, 0),
391         SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, 0),
392         SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_unsupported, 0),
393         SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, 0),
394         SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, 0),
395         SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, 0),
396         SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_unsupported, 0),
397         SD_BUS_SIGNAL("NameAcquired", "s", 0),
398         SD_BUS_SIGNAL("NameLost", "s", 0),
399         SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
400         SD_BUS_VTABLE_END
401 };
402
403 static int connect_bus(sd_event *event, sd_bus **_bus) {
404         _cleanup_bus_unref_ sd_bus *bus = NULL;
405         int r;
406
407         assert(event);
408         assert(_bus);
409
410         r = sd_bus_default_system(&bus);
411         if (r < 0) {
412                 log_error("Failed to create bus: %s", strerror(-r));
413                 return r;
414         }
415
416         r = sd_bus_add_object_vtable(bus, "/org/freedesktop/DBus", "org.freedesktop.DBus", driver_vtable, NULL);
417         if (r < 0) {
418                 log_error("Failed to add manager object vtable: %s", strerror(-r));
419                 return r;
420         }
421
422         r = sd_bus_request_name(bus, "org.freedesktop.DBus", 0);
423         if (r < 0) {
424                 log_error("Unable to request name: %s\n", strerror(-r));
425                 return r;
426         }
427
428         r = sd_bus_attach_event(bus, event, 0);
429         if (r < 0) {
430                 log_error("Error %d while adding bus to even: %s", r, strerror(-r));
431                 return r;
432         }
433
434         *_bus = bus;
435         bus = NULL;
436
437         return 0;
438 }
439
440 int main(int argc, char *argv[]) {
441         _cleanup_event_unref_ sd_event *event = NULL;
442         _cleanup_bus_unref_ sd_bus *bus = NULL;
443         int r;
444
445         log_set_target(LOG_TARGET_AUTO);
446         log_parse_environment();
447         log_open();
448
449         if (argc != 1) {
450                 log_error("This program takes no arguments.");
451                 r = -EINVAL;
452                 goto finish;
453         }
454
455         r = sd_event_default(&event);
456         if (r < 0) {
457                 log_error("Failed to allocate event loop: %s", strerror(-r));
458                 goto finish;
459         }
460
461         sd_event_set_watchdog(event, true);
462
463         r = connect_bus(event, &bus);
464         if (r < 0)
465                 goto finish;
466
467         r = bus_event_loop_with_idle(event, bus, "org.freedesktop.DBus", DEFAULT_EXIT_USEC);
468         if (r < 0) {
469                 log_error("Failed to run event loop: %s", strerror(-r));
470                 goto finish;
471         }
472
473 finish:
474         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
475
476 }