chiark / gitweb /
bus-driverd: actually add --version
[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
53 #define DBUS_PATH       "/org/freedesktop/DBus"
54 #define DBUS_INTERFACE  "org.freedesktop.DBus"
55
56 /*
57  * TODO:
58  *
59  * AddMatch / RemoveMatch
60  * ListActivatableNames
61  * StartServiceByName
62  */
63
64 static sd_bus *driver_bus;
65
66 static int help(void) {
67
68         printf("%s [OPTIONS...] <bus-path>\n\n"
69                "Driver to provide a org.freedesktop.DBus interface on the given kdbus node.\n\n"
70                "  -h --help              Show this help\n"
71                "     --version           Show package version\n",
72                program_invocation_short_name);
73
74         return 0;
75 }
76
77 static int parse_argv(int argc, char *argv[]) {
78
79         enum {
80                 ARG_VERSION = 0x100,
81         };
82
83         static const struct option options[] = {
84                 { "help",            no_argument,       NULL, 'h'         },
85                 { "version",         no_argument,       NULL, ARG_VERSION },
86                 {}
87         };
88
89         int c;
90
91         assert(argc >= 0);
92         assert(argv);
93
94         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
95                 switch (c) {
96
97                 case 'h':
98                         help();
99                         return 0;
100
101                 case ARG_VERSION:
102                         puts(PACKAGE_STRING);
103                         puts(SYSTEMD_FEATURES);
104                         return 0;
105
106                 case '?':
107                         return -EINVAL;
108
109                 default:
110                         assert_not_reached("Unknown option");
111                 }
112
113         return 1;
114 }
115
116 static int driver_name_info_error(sd_bus *bus, sd_bus_message *m, const char *name, int error_code) {
117
118         if (error_code == -ENXIO || error_code == -ENOENT)
119                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER,
120                                                   "Could not get owner of name '%s': no such name",
121                                                   name);
122
123         return sd_bus_reply_method_errno(m, error_code, NULL);
124 }
125
126 static int driver_add_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
127
128         char *arg0, *match;
129         int r;
130
131         r = sd_bus_message_read(m, "s", &arg0);
132         if (r < 0)
133                 return r;
134
135         match = strdup(arg0);
136         if (!match)
137                 return -ENOMEM;
138
139         /* FIXME */
140
141         return sd_bus_reply_method_return(m, NULL);
142 }
143
144 static int driver_remove_match(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
145
146         char *arg0;
147         int r;
148
149         r = sd_bus_message_read(m, "s", &arg0);
150         if (r < 0)
151                 return r;
152
153         /* FIXME */
154
155         return sd_bus_reply_method_return(m, NULL);
156 }
157
158 static int driver_get_security_ctx(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
159
160         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
161         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
162         char *arg0;
163         int r;
164
165         r = sd_bus_message_read(m, "s", &arg0);
166         if (r < 0)
167                 return r;
168
169         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_SELINUX_CONTEXT, &creds);
170         if (r < 0) {
171                 if (r == -ENOENT)
172                         return driver_name_info_error(bus, m, arg0, r);
173                 else
174                         return r;
175         }
176
177         r = sd_bus_message_new_method_return(m, &reply);
178         if (r < 0)
179                 return r;
180
181         r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
182         if (r < 0)
183                 return r;
184
185         return sd_bus_send(bus, reply, NULL);
186 }
187
188 static int driver_get_pid(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
189
190         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
191         char *arg0;
192         int r;
193
194         r = sd_bus_message_read(m, "s", &arg0);
195         if (r < 0)
196                 return r;
197
198         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_PID, &creds);
199         if (r < 0)
200                 return r;
201
202         return sd_bus_reply_method_return(m, "u", creds->pid);
203 }
204
205 static int driver_get_user(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
206
207         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
208         char *arg0;
209         int r;
210
211         r = sd_bus_message_read(m, "s", &arg0);
212         if (r < 0)
213                 return r;
214
215         r = sd_bus_get_owner(bus, arg0, SD_BUS_CREDS_UID, &creds);
216         if (r < 0) {
217                 if (r == -ENOENT)
218                         return driver_name_info_error(bus, m, arg0, r);
219                 else
220                         return r;
221         }
222
223         return sd_bus_reply_method_return(m, "u", creds->uid);
224 }
225
226 static int driver_get_id(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
227
228         sd_id128_t server_id;
229         char buf[SD_ID128_STRING_MAX];
230         int r;
231
232         r = sd_bus_get_server_id(bus, &server_id);
233         if (r < 0)
234                 return r;
235
236         return sd_bus_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
237 }
238
239 static int driver_get_name_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
240
241         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
242         _cleanup_free_ char *owner = NULL;
243         char *arg0;
244         int r;
245
246         r = sd_bus_message_read(m, "s", &arg0);
247         if (r < 0)
248                 return r;
249
250         r = sd_bus_get_owner(bus, arg0, 0, &creds);
251         if (r < 0) {
252                 if (r == -ENOENT)
253                         return driver_name_info_error(bus, m, arg0, r);
254                 else
255                         return r;
256         }
257
258         return sd_bus_reply_method_return(m, "s", creds->unique_name);
259 }
260
261 static int driver_hello(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
262
263         return sd_bus_reply_method_return(m, "s", m->sender);
264 }
265
266 static int driver_list_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
267
268         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
269         _cleanup_strv_free_ char **names = NULL;
270         int r;
271
272         r = sd_bus_list_names(bus, &names, NULL);
273         if (r < 0)
274                 return r;
275
276         r = sd_bus_message_new_method_return(m, &reply);
277         if (r < 0)
278                 return r;
279
280         r = sd_bus_message_append_strv(reply, names);
281         if (r < 0)
282                 return r;
283
284         return sd_bus_send(bus, reply, NULL);
285 }
286
287 static int driver_list_activatable_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
288
289         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
290         _cleanup_strv_free_ char **names = NULL;
291         int r;
292
293         r = sd_bus_list_names(bus, NULL, &names);
294         if (r < 0)
295                 return r;
296
297         r = sd_bus_message_new_method_return(m, &reply);
298         if (r < 0)
299                 return r;
300
301         r = sd_bus_message_append_strv(reply, names);
302         if (r < 0)
303                 return r;
304
305         return sd_bus_send(bus, reply, NULL);
306 }
307
308 static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
309
310         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
311         struct kdbus_cmd_name_list cmd = {};
312         struct kdbus_name_list *name_list;
313         struct kdbus_cmd_name *name;
314         _cleanup_strv_free_ char **owners = NULL;
315         char *arg0;
316         int r;
317
318         r = sd_bus_message_read(m, "s", &arg0);
319         if (r < 0)
320                 return r;
321
322         cmd.flags = KDBUS_NAME_LIST_QUEUED;
323
324         r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
325         if (r < 0)
326                 return -errno;
327
328         name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
329
330         KDBUS_ITEM_FOREACH(name, name_list, names) {
331                 if (name->size > sizeof(*name) && !streq(name->name, arg0)) {
332                         char *n;
333
334                         if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0)
335                                 return -ENOMEM;
336
337                         r = strv_push(&owners, n);
338                         if (r < 0) {
339                                 free(n);
340                                 return -ENOMEM;
341                         }
342                 }
343         }
344
345         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_FREE, &cmd.offset);
346         if (r < 0)
347                 return -errno;
348
349         r = sd_bus_message_new_method_return(m, &reply);
350         if (r < 0)
351                 return r;
352
353         r = sd_bus_message_append_strv(reply, owners);
354         if (r < 0)
355                 return r;
356
357         return sd_bus_send(bus, reply, NULL);
358 }
359
360 static int driver_name_has_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
361
362         char *arg0;
363         int r;
364
365         r = sd_bus_message_read(m, "s", &arg0);
366         if (r < 0)
367                 return r;
368
369         r = sd_bus_get_owner(bus, arg0, 0, NULL);
370         if (r < 0 && r != -ENOENT)
371                 return r;
372
373         return sd_bus_reply_method_return(m, "b", r == 0);
374 }
375
376 static int driver_request_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
377
378         struct kdbus_cmd_name *cmd_name;
379         uint32_t flags;
380         size_t size;
381         uint64_t id;
382         char *name;
383         int r;
384
385         r = sd_bus_message_read(m, "su", &name, &flags);
386         if (r < 0)
387                 return r;
388
389         size = sizeof(*cmd_name) + strlen(name) + 1;
390
391         cmd_name = alloca(size);
392         memset(cmd_name, 0, size);
393         strcpy(cmd_name->name, name);
394         cmd_name->size = size;
395         kdbus_translate_request_name_flags(flags, (uint64_t *) &cmd_name->conn_flags);
396
397         /* This function is open-coded because we request the name 'on behalf'
398          * of the requesting connection */
399         r = bus_kernel_parse_unique_name(m->sender, &id);
400         if (r < 0)
401                 return r;
402
403         cmd_name->id = id;
404
405         r = ioctl(sd_bus_get_fd(bus), KDBUS_CMD_NAME_ACQUIRE, cmd_name);
406         if (r < 0)
407                 return r;
408
409         return sd_bus_reply_method_return(m, "u", 0);
410 }
411
412 static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
413
414         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
415         char *s;
416         int r;
417
418         return sd_bus_reply_method_return(m, "u", 2);
419
420         r = sd_bus_message_read(m, "s", &s);
421         if (r < 0)
422                 return r;
423
424         /* FIXME */
425
426         return sd_bus_send(bus, reply, NULL);
427 }
428
429 static int driver_update_env(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
430
431         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_NOT_SUPPORTED,
432                                           "UpdateActivationEnvironment is unsupported");
433 }
434
435 static int driver_reload_config(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
436
437         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_NOT_SUPPORTED,
438                                           "ReloadConfig is unsupported");
439 }
440
441 const sd_bus_vtable dbus_vtable[] = {
442         SD_BUS_VTABLE_START(0),
443         SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, 0),
444         SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_ctx, 0),
445         SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, 0),
446         SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, 0),
447         SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, 0),
448         SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, 0),
449         SD_BUS_METHOD("Hello", NULL, "s", driver_hello, 0),
450         SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, 0),
451         SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, 0),
452         SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, 0),
453         SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, 0),
454         SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_reload_config, 0),
455         SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, 0),
456         SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, 0),
457         SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, 0),
458         SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_update_env, 0),
459         SD_BUS_SIGNAL("NameAcquired", "s", 0),
460         SD_BUS_SIGNAL("NameLost", "s", 0),
461         SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
462         SD_BUS_VTABLE_END
463 };
464
465 static int driver_main(const char *bus_name) {
466
467         _cleanup_event_source_unref_ sd_event_source *w_accept = NULL;
468         _cleanup_event_source_unref_ sd_event_source *w_root_service = NULL;
469         _cleanup_event_unref_ sd_event *e = NULL;
470         int r;
471
472         r = sd_event_new(&e);
473         if (r < 0) {
474                 log_error("Failed to allocate event loop: %s", strerror(-r));
475                 return r;
476         }
477
478         /* set up kernel bus connection */
479         r = sd_bus_new(&driver_bus);
480         if (r < 0) {
481                 log_error("Failed to create bus: %s", strerror(-r));
482                 return r;
483         }
484
485         r = sd_bus_set_address(driver_bus, bus_name);
486         if (r < 0) {
487                 log_error("Failed to create bus: %s", strerror(-r));
488                 return r;
489         }
490
491         r = sd_bus_start(driver_bus);
492         if (r < 0) {
493                 log_error("Failed to start kernel bus: %s", strerror(-r));
494                 return r;
495         }
496
497         r = sd_bus_request_name(driver_bus, DBUS_INTERFACE, 0);
498         if (r < 0) {
499                 log_error("Unable to request name '%s': %s\n", DBUS_INTERFACE, strerror(-r));
500                 return r;
501         }
502
503         r = sd_bus_add_object_vtable(driver_bus, DBUS_PATH, DBUS_INTERFACE, dbus_vtable, NULL);
504         if (r < 0) {
505                 log_error("Failed to add manager object vtable: %s", strerror(-r));
506                 return r;
507         }
508
509         r = sd_bus_attach_event(driver_bus, e, 0);
510         if (r < 0) {
511                 log_error("Error %d while adding bus to even: %s", r, strerror(-r));
512                 return r;
513         }
514
515         log_debug("Entering main loop.");
516
517         return sd_event_loop(e);
518 }
519
520 int main(int argc, char *argv[]) {
521         char *bus_name;
522         int r;
523
524         setlocale(LC_ALL, "");
525         log_parse_environment();
526         log_open();
527
528         r = parse_argv(argc, argv);
529         if (r <= 0)
530                 return r;
531
532         if (argc <= optind) {
533                 help();
534                 return -EINVAL;
535         }
536
537         r = asprintf(&bus_name, "kernel:path=%s", argv[optind]);
538         if (r < 0)
539                 return r;
540
541         return driver_main(bus_name);
542 }