]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/busname.c
core: add new AcceptFD= setting to .busname units
[thirdparty/systemd.git] / src / core / busname.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 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 "special.h"
23 #include "bus-kernel.h"
24 #include "bus-internal.h"
25 #include "bus-util.h"
26 #include "service.h"
27 #include "dbus-busname.h"
28 #include "busname.h"
29
30 static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
31 [BUSNAME_DEAD] = UNIT_INACTIVE,
32 [BUSNAME_LISTENING] = UNIT_ACTIVE,
33 [BUSNAME_RUNNING] = UNIT_ACTIVE,
34 [BUSNAME_FAILED] = UNIT_FAILED
35 };
36
37 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
38
39 static void busname_init(Unit *u) {
40 BusName *n = BUSNAME(u);
41
42 assert(u);
43 assert(u->load_state == UNIT_STUB);
44
45 n->starter_fd = -1;
46 n->accept_fd = true;
47 }
48
49 static void busname_done(Unit *u) {
50 BusName *n = BUSNAME(u);
51
52 assert(u);
53
54 free(n->name);
55 n->name = NULL;
56
57 unit_ref_unset(&n->service);
58
59 n->event_source = sd_event_source_unref(n->event_source);
60 n->starter_fd = safe_close(n->starter_fd);
61 }
62
63 static int busname_add_default_default_dependencies(BusName *n) {
64 int r;
65
66 assert(n);
67
68 r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true);
69 if (r < 0)
70 return r;
71
72 if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) {
73 r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
74 if (r < 0)
75 return r;
76 }
77
78 return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
79 }
80
81 static int busname_add_extras(BusName *n) {
82 Unit *u = UNIT(n);
83 int r;
84
85 assert(n);
86
87 if (!n->name) {
88 n->name = unit_name_to_prefix(u->id);
89 if (!n->name)
90 return -ENOMEM;
91 }
92
93 if (!u->description) {
94 r = unit_set_description(u, n->name);
95 if (r < 0)
96 return r;
97 }
98
99 if (!UNIT_DEREF(n->service)) {
100 Unit *x;
101
102 r = unit_load_related_unit(u, ".service", &x);
103 if (r < 0)
104 return r;
105
106 unit_ref_set(&n->service, x);
107 }
108
109 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(n->service), true);
110 if (r < 0)
111 return r;
112
113 if (u->default_dependencies) {
114 r = busname_add_default_default_dependencies(n);
115 if (r < 0)
116 return r;
117 }
118
119 return 0;
120 }
121
122 static int busname_verify(BusName *n) {
123 char *e;
124
125 assert(n);
126
127 if (UNIT(n)->load_state != UNIT_LOADED)
128 return 0;
129
130 if (!service_name_is_valid(n->name)) {
131 log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
132 return -EINVAL;
133 }
134
135 e = strappenda(n->name, ".busname");
136 if (!unit_has_name(UNIT(n), e)) {
137 log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
138 return -EINVAL;
139 }
140
141 return 0;
142 }
143
144 static int busname_load(Unit *u) {
145 BusName *n = BUSNAME(u);
146 int r;
147
148 assert(u);
149 assert(u->load_state == UNIT_STUB);
150
151 r = unit_load_fragment_and_dropin(u);
152 if (r < 0)
153 return r;
154
155 if (u->load_state == UNIT_LOADED) {
156 /* This is a new unit? Then let's add in some extras */
157 r = busname_add_extras(n);
158 if (r < 0)
159 return r;
160 }
161
162 return busname_verify(n);
163 }
164
165 static void busname_dump(Unit *u, FILE *f, const char *prefix) {
166 BusName *n = BUSNAME(u);
167
168 assert(n);
169 assert(f);
170
171 fprintf(f,
172 "%sBus Name State: %s\n"
173 "%sResult: %s\n"
174 "%sName: %s\n"
175 "%sAccept FD: %s\n",
176 prefix, busname_state_to_string(n->state),
177 prefix, busname_result_to_string(n->result),
178 prefix, n->name,
179 prefix, yes_no(n->accept_fd));
180 }
181
182 static void busname_unwatch_fd(BusName *n) {
183 int r;
184
185 assert(n);
186
187 if (n->event_source) {
188 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_OFF);
189 if (r < 0)
190 log_debug_unit(UNIT(n)->id, "Failed to disable event source.");
191 }
192 }
193
194 static void busname_close_fd(BusName *n) {
195 assert(n);
196
197 busname_unwatch_fd(n);
198
199 if (n->starter_fd <= 0)
200 return;
201
202 n->starter_fd = safe_close(n->starter_fd);
203 }
204
205 static int busname_watch_fd(BusName *n) {
206 int r;
207
208 assert(n);
209
210 if (n->starter_fd < 0)
211 return 0;
212
213 if (n->event_source)
214 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_ON);
215 else
216 r = sd_event_add_io(UNIT(n)->manager->event, &n->event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
217 if (r < 0) {
218 log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r));
219 busname_unwatch_fd(n);
220 return r;
221 }
222
223 return 0;
224 }
225
226 static int busname_open_fd(BusName *n) {
227 assert(n);
228
229 if (n->starter_fd >= 0)
230 return 0;
231
232 n->starter_fd = bus_kernel_create_starter(
233 UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
234 n->name, n->accept_fd, n->policy);
235
236 if (n->starter_fd < 0) {
237 log_warning_unit(UNIT(n)->id, "Failed to create starter fd: %s", strerror(-n->starter_fd));
238 return n->starter_fd;
239 }
240
241 return 0;
242 }
243
244 static void busname_set_state(BusName *n, BusNameState state) {
245 BusNameState old_state;
246 assert(n);
247
248 old_state = n->state;
249 n->state = state;
250
251 if (state != BUSNAME_LISTENING)
252 busname_unwatch_fd(n);
253
254 if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_RUNNING))
255 busname_close_fd(n);
256
257 if (state != old_state)
258 log_debug_unit(UNIT(n)->id, "%s changed %s -> %s",
259 UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
260
261 unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
262 }
263
264 static int busname_coldplug(Unit *u) {
265 BusName *n = BUSNAME(u);
266 int r;
267
268 assert(n);
269 assert(n->state == BUSNAME_DEAD);
270
271 if (n->deserialized_state == n->state)
272 return 0;
273
274 if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_RUNNING)) {
275 r = busname_open_fd(n);
276 if (r < 0)
277 return r;
278 }
279
280 if (n->deserialized_state == BUSNAME_LISTENING) {
281 r = busname_watch_fd(n);
282 if (r < 0)
283 return r;
284 }
285
286 busname_set_state(n, n->deserialized_state);
287 return 0;
288 }
289
290 static void busname_enter_dead(BusName *n, BusNameResult f) {
291 assert(n);
292
293 if (f != BUSNAME_SUCCESS)
294 n->result = f;
295
296 busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
297 }
298
299 static void busname_enter_listening(BusName *n) {
300 int r;
301
302 assert(n);
303
304 r = busname_open_fd(n);
305 if (r < 0) {
306 log_warning_unit(UNIT(n)->id, "%s failed to listen on bus names: %s", UNIT(n)->id, strerror(-r));
307 goto fail;
308 }
309
310 r = busname_watch_fd(n);
311 if (r < 0) {
312 log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r));
313 goto fail;
314 }
315
316 busname_set_state(n, BUSNAME_LISTENING);
317 return;
318
319 fail:
320 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
321 }
322
323 static void busname_enter_running(BusName *n) {
324 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
325 bool pending = false;
326 Unit *other;
327 Iterator i;
328 int r;
329
330 assert(n);
331
332 /* We don't take conenctions anymore if we are supposed to
333 * shut down anyway */
334
335 if (unit_stop_pending(UNIT(n))) {
336 log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
337
338 /* Flush all queued activation reqeuest by closing and reopening the connection */
339 bus_kernel_drop_one(n->starter_fd);
340
341 busname_enter_listening(n);
342 return;
343 }
344
345 /* If there's already a start pending don't bother to do
346 * anything */
347 SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
348 if (unit_active_or_pending(other)) {
349 pending = true;
350 break;
351 }
352
353 if (!pending) {
354 r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
355 if (r < 0)
356 goto fail;
357 }
358
359 busname_set_state(n, BUSNAME_RUNNING);
360 return;
361
362 fail:
363 log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
364 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
365 }
366
367 static int busname_start(Unit *u) {
368 BusName *n = BUSNAME(u);
369
370 assert(n);
371
372 if (UNIT_ISSET(n->service)) {
373 Service *service;
374
375 service = SERVICE(UNIT_DEREF(n->service));
376
377 if (UNIT(service)->load_state != UNIT_LOADED) {
378 log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
379 return -ENOENT;
380 }
381 }
382
383 assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
384
385 n->result = BUSNAME_SUCCESS;
386 busname_enter_listening(n);
387
388 return 0;
389 }
390
391 static int busname_stop(Unit *u) {
392 BusName *n = BUSNAME(u);
393
394 assert(n);
395 assert(n->state == BUSNAME_LISTENING || n->state == BUSNAME_RUNNING);
396
397 busname_enter_dead(n, BUSNAME_SUCCESS);
398 return 0;
399 }
400
401 static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
402 BusName *n = BUSNAME(u);
403
404 assert(n);
405 assert(f);
406 assert(fds);
407
408 unit_serialize_item(u, f, "state", busname_state_to_string(n->state));
409 unit_serialize_item(u, f, "result", busname_result_to_string(n->result));
410
411 if (n->starter_fd >= 0) {
412 int copy;
413
414 copy = fdset_put_dup(fds, n->starter_fd);
415 if (copy < 0)
416 return copy;
417
418 unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
419 }
420
421 return 0;
422 }
423
424 static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
425 BusName *n = BUSNAME(u);
426
427 assert(n);
428 assert(key);
429 assert(value);
430
431 if (streq(key, "state")) {
432 BusNameState state;
433
434 state = busname_state_from_string(value);
435 if (state < 0)
436 log_debug_unit(u->id, "Failed to parse state value %s", value);
437 else
438 n->deserialized_state = state;
439
440 } else if (streq(key, "result")) {
441 BusNameResult f;
442
443 f = busname_result_from_string(value);
444 if (f < 0)
445 log_debug_unit(u->id, "Failed to parse result value %s", value);
446 else if (f != BUSNAME_SUCCESS)
447 n->result = f;
448
449 } else if (streq(key, "starter-fd")) {
450 int fd;
451
452 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
453 log_debug_unit(u->id, "Failed to parse starter fd value %s", value);
454 else {
455 safe_close(n->starter_fd);
456 n->starter_fd = fdset_remove(fds, fd);
457 }
458 } else
459 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
460
461 return 0;
462 }
463
464 _pure_ static UnitActiveState busname_active_state(Unit *u) {
465 assert(u);
466
467 return state_translation_table[BUSNAME(u)->state];
468 }
469
470 _pure_ static const char *busname_sub_state_to_string(Unit *u) {
471 assert(u);
472
473 return busname_state_to_string(BUSNAME(u)->state);
474 }
475
476 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
477 BusName *n = userdata;
478
479 assert(n);
480 assert(fd >= 0);
481
482 if (n->state != BUSNAME_LISTENING)
483 return 0;
484
485 log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
486
487 if (revents != EPOLLIN) {
488 log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
489 UNIT(n)->id, revents);
490 goto fail;
491 }
492
493 busname_enter_running(n);
494 return 0;
495 fail:
496
497 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
498 return 0;
499 }
500
501 static void busname_reset_failed(Unit *u) {
502 BusName *n = BUSNAME(u);
503
504 assert(n);
505
506 if (n->state == BUSNAME_FAILED)
507 busname_set_state(n, BUSNAME_DEAD);
508
509 n->result = BUSNAME_SUCCESS;
510 }
511
512 static void busname_trigger_notify(Unit *u, Unit *other) {
513 BusName *n = BUSNAME(u);
514 Service *s;
515
516 assert(n);
517 assert(other);
518
519 if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
520 return;
521
522 if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
523 return;
524
525 s = SERVICE(other);
526
527 if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
528 busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
529 else if (IN_SET(s->state,
530 SERVICE_DEAD, SERVICE_FAILED,
531 SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
532 SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
533 SERVICE_AUTO_RESTART))
534 busname_enter_listening(n);
535 }
536
537 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
538 [BUSNAME_DEAD] = "dead",
539 [BUSNAME_LISTENING] = "listening",
540 [BUSNAME_RUNNING] = "running",
541 [BUSNAME_FAILED] = "failed"
542 };
543
544 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
545
546 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
547 [BUSNAME_SUCCESS] = "success",
548 [BUSNAME_FAILURE_RESOURCES] = "resources",
549 [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
550 };
551
552 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
553
554 static const char* const busname_policy_access_table[_BUSNAME_POLICY_ACCESS_MAX] = {
555 [BUSNAME_POLICY_ACCESS_SEE] = "see",
556 [BUSNAME_POLICY_ACCESS_TALK] = "talk",
557 [BUSNAME_POLICY_ACCESS_OWN] = "own",
558 };
559
560 DEFINE_STRING_TABLE_LOOKUP(busname_policy_access, BusNamePolicyAccess);
561
562 const UnitVTable busname_vtable = {
563 .object_size = sizeof(BusName),
564
565 .sections =
566 "Unit\0"
567 "BusName\0"
568 "Install\0",
569 .private_section = "BusName",
570
571 .init = busname_init,
572 .done = busname_done,
573 .load = busname_load,
574
575 .coldplug = busname_coldplug,
576
577 .dump = busname_dump,
578
579 .start = busname_start,
580 .stop = busname_stop,
581
582 .serialize = busname_serialize,
583 .deserialize_item = busname_deserialize_item,
584
585 .active_state = busname_active_state,
586 .sub_state_to_string = busname_sub_state_to_string,
587
588 .trigger_notify = busname_trigger_notify,
589
590 .reset_failed = busname_reset_failed,
591
592 .bus_interface = "org.freedesktop.systemd1.BusName",
593 .bus_vtable = bus_busname_vtable,
594
595 .status_message_formats = {
596 .finished_start_job = {
597 [JOB_DONE] = "Listening on %s.",
598 [JOB_FAILED] = "Failed to listen on %s.",
599 [JOB_DEPENDENCY] = "Dependency failed for %s.",
600 [JOB_TIMEOUT] = "Timed out starting %s.",
601 },
602 .finished_stop_job = {
603 [JOB_DONE] = "Closed %s.",
604 [JOB_FAILED] = "Failed stopping %s.",
605 [JOB_TIMEOUT] = "Timed out stopping %s.",
606 },
607 },
608 };