chiark / gitweb /
core/manager: remove infinite loop
[elogind.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 }
47
48 static 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
66 static 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
84 static 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
127 static 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
149 static 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
170 static 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
185 static 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
197 static void busname_close_fd(BusName *n) {
198         assert(n);
199
200         if (n->starter_fd <= 0)
201                 return;
202
203         close_nointr_nofail(n->starter_fd);
204         n->starter_fd = -1;
205 }
206
207 static int busname_watch_fd(BusName *n) {
208         int r;
209
210         assert(n);
211
212         if (n->starter_fd < 0)
213                 return 0;
214
215         if (n->event_source)
216                 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_ON);
217         else
218                 r = sd_event_add_io(UNIT(n)->manager->event, n->starter_fd, EPOLLIN, busname_dispatch_io, n, &n->event_source);
219         if (r < 0) {
220                 log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r));
221                 busname_unwatch_fd(n);
222                 return r;
223         }
224
225         return 0;
226 }
227
228 static int busname_open_fd(BusName *n) {
229         assert(n);
230
231         if (n->starter_fd >= 0)
232                 return 0;
233
234         n->starter_fd = bus_kernel_create_starter(UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user", n->name);
235         if (n->starter_fd < 0) {
236                 log_warning_unit(UNIT(n)->id, "Failed to create starter fd: %s", strerror(-n->starter_fd));
237                 return n->starter_fd;
238         }
239
240         return 0;
241 }
242
243 static void busname_set_state(BusName *n, BusNameState state) {
244         BusNameState old_state;
245         assert(n);
246
247         old_state = n->state;
248         n->state = state;
249
250         if (state != BUSNAME_LISTENING)
251                 busname_unwatch_fd(n);
252
253         if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_RUNNING))
254                 busname_close_fd(n);
255
256         if (state != old_state)
257                 log_debug_unit(UNIT(n)->id, "%s changed %s -> %s",
258                                UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
259
260         unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
261 }
262
263 static int busname_coldplug(Unit *u) {
264         BusName *n = BUSNAME(u);
265         int r;
266
267         assert(n);
268         assert(n->state == BUSNAME_DEAD);
269
270         if (n->deserialized_state == n->state)
271                 return 0;
272
273         if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_RUNNING)) {
274                 r = busname_open_fd(n);
275                 if (r < 0)
276                         return r;
277         }
278
279         if (n->deserialized_state == BUSNAME_LISTENING) {
280                 r = busname_watch_fd(n);
281                 if (r < 0)
282                         return r;
283         }
284
285         busname_set_state(n, n->deserialized_state);
286         return 0;
287 }
288
289 static void busname_enter_dead(BusName *n, BusNameResult f) {
290         assert(n);
291
292         if (f != BUSNAME_SUCCESS)
293                 n->result = f;
294
295         busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
296 }
297
298 static void busname_enter_listening(BusName *n) {
299         int r;
300
301         assert(n);
302
303         r = busname_open_fd(n);
304         if (r < 0) {
305                 log_warning_unit(UNIT(n)->id, "%s failed to listen on bus names: %s", UNIT(n)->id, strerror(-r));
306                 goto fail;
307         }
308
309         r = busname_watch_fd(n);
310         if (r < 0) {
311                 log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r));
312                 goto fail;
313         }
314
315         busname_set_state(n, BUSNAME_LISTENING);
316         return;
317
318 fail:
319         busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
320 }
321
322 static void busname_enter_running(BusName *n) {
323         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
324         bool pending = false;
325         Unit *other;
326         Iterator i;
327         int r;
328
329         assert(n);
330
331         /* We don't take conenctions anymore if we are supposed to
332          * shut down anyway */
333
334         if (unit_stop_pending(UNIT(n))) {
335                 log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
336                 return;
337         }
338
339         /* If there's already a start pending don't bother to do
340          * anything */
341         SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
342                 if (unit_active_or_pending(other)) {
343                         pending = true;
344                         break;
345                 }
346
347         if (!pending) {
348                 r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
349                 if (r < 0)
350                         goto fail;
351         }
352
353         busname_set_state(n, BUSNAME_RUNNING);
354         return;
355
356 fail:
357         log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
358         busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
359 }
360
361 static int busname_start(Unit *u) {
362         BusName *n = BUSNAME(u);
363
364         assert(n);
365
366         if (UNIT_ISSET(n->service)) {
367                 Service *service;
368
369                 service = SERVICE(UNIT_DEREF(n->service));
370
371                 if (UNIT(service)->load_state != UNIT_LOADED) {
372                         log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
373                         return -ENOENT;
374                 }
375         }
376
377         assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
378
379         n->result = BUSNAME_SUCCESS;
380         busname_enter_listening(n);
381
382         return 0;
383 }
384
385 static int busname_stop(Unit *u) {
386         BusName *n = BUSNAME(u);
387
388         assert(n);
389         assert(n->state == BUSNAME_LISTENING || n->state == BUSNAME_RUNNING);
390
391         busname_enter_dead(n, BUSNAME_SUCCESS);
392         return 0;
393 }
394
395 static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
396         BusName *n = BUSNAME(u);
397
398         assert(n);
399         assert(f);
400         assert(fds);
401
402         unit_serialize_item(u, f, "state", busname_state_to_string(n->state));
403         unit_serialize_item(u, f, "result", busname_result_to_string(n->result));
404
405         if (n->starter_fd >= 0) {
406                 int copy;
407
408                 copy = fdset_put_dup(fds, n->starter_fd);
409                 if (copy < 0)
410                         return copy;
411
412                 unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
413         }
414
415         return 0;
416 }
417
418 static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
419         BusName *n = BUSNAME(u);
420
421         assert(n);
422         assert(key);
423         assert(value);
424
425         if (streq(key, "state")) {
426                 BusNameState state;
427
428                 state = busname_state_from_string(value);
429                 if (state < 0)
430                         log_debug_unit(u->id, "Failed to parse state value %s", value);
431                 else
432                         n->deserialized_state = state;
433
434         } else if (streq(key, "result")) {
435                 BusNameResult f;
436
437                 f = busname_result_from_string(value);
438                 if (f < 0)
439                         log_debug_unit(u->id, "Failed to parse result value %s", value);
440                 else if (f != BUSNAME_SUCCESS)
441                         n->result = f;
442
443         } else if (streq(key, "starter-fd")) {
444                 int fd;
445
446                 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
447                         log_debug_unit(u->id, "Failed to parse starter fd value %s", value);
448                 else {
449                         if (n->starter_fd >= 0)
450                                 close_nointr_nofail(n->starter_fd);
451                         n->starter_fd = fdset_remove(fds, fd);
452                 }
453         } else
454                 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
455
456         return 0;
457 }
458
459 _pure_ static UnitActiveState busname_active_state(Unit *u) {
460         assert(u);
461
462         return state_translation_table[BUSNAME(u)->state];
463 }
464
465 _pure_ static const char *busname_sub_state_to_string(Unit *u) {
466         assert(u);
467
468         return busname_state_to_string(BUSNAME(u)->state);
469 }
470
471 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
472         BusName *n = userdata;
473
474         assert(n);
475         assert(fd >= 0);
476
477         if (n->state != BUSNAME_LISTENING)
478                 return 0;
479
480         log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
481
482         if (revents != EPOLLIN) {
483                 log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
484                                UNIT(n)->id, revents);
485                 goto fail;
486         }
487
488         busname_enter_running(n);
489         return 0;
490 fail:
491
492         busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
493         return 0;
494 }
495
496 static void busname_reset_failed(Unit *u) {
497         BusName *n = BUSNAME(u);
498
499         assert(n);
500
501         if (n->state == BUSNAME_FAILED)
502                 busname_set_state(n, BUSNAME_DEAD);
503
504         n->result = BUSNAME_SUCCESS;
505 }
506
507 static void busname_trigger_notify(Unit *u, Unit *other) {
508         BusName *n = BUSNAME(u);
509         Service *s;
510
511         assert(n);
512         assert(other);
513
514         if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
515                 return;
516
517         if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
518                 return;
519
520         s = SERVICE(other);
521
522         if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
523                 busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
524         else if (IN_SET(s->state,
525                         SERVICE_DEAD, SERVICE_FAILED,
526                         SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
527                         SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
528                         SERVICE_AUTO_RESTART))
529                 busname_enter_listening(n);
530 }
531
532 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
533         [BUSNAME_DEAD] = "dead",
534         [BUSNAME_LISTENING] = "listening",
535         [BUSNAME_RUNNING] = "running",
536         [BUSNAME_FAILED] = "failed"
537 };
538
539 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
540
541 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
542         [BUSNAME_SUCCESS] = "success",
543         [BUSNAME_FAILURE_RESOURCES] = "resources",
544 };
545
546 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
547
548 const UnitVTable busname_vtable = {
549         .object_size = sizeof(BusName),
550
551         .sections =
552                 "Unit\0"
553                 "BusName\0"
554                 "Install\0",
555         .private_section = "BusName",
556
557         .init = busname_init,
558         .done = busname_done,
559         .load = busname_load,
560
561         .coldplug = busname_coldplug,
562
563         .dump = busname_dump,
564
565         .start = busname_start,
566         .stop = busname_stop,
567
568         .serialize = busname_serialize,
569         .deserialize_item = busname_deserialize_item,
570
571         .active_state = busname_active_state,
572         .sub_state_to_string = busname_sub_state_to_string,
573
574         .trigger_notify = busname_trigger_notify,
575
576         .reset_failed = busname_reset_failed,
577
578         .bus_interface = "org.freedesktop.systemd1.BusName",
579         .bus_vtable = bus_busname_vtable,
580         .bus_changing_properties = bus_busname_changing_properties,
581
582         .status_message_formats = {
583                 .finished_start_job = {
584                         [JOB_DONE]       = "Listening on %s.",
585                         [JOB_FAILED]     = "Failed to listen on %s.",
586                         [JOB_DEPENDENCY] = "Dependency failed for %s.",
587                         [JOB_TIMEOUT]    = "Timed out starting %s.",
588                 },
589                 .finished_stop_job = {
590                         [JOB_DONE]       = "Closed %s.",
591                         [JOB_FAILED]     = "Failed stopping %s.",
592                         [JOB_TIMEOUT]    = "Timed out stopping %s.",
593                 },
594         },
595 };