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