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