chiark / gitweb /
busname: introduce Activating directive
[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_REGISTERED] = UNIT_ACTIVE,
33         [BUSNAME_LISTENING] = UNIT_ACTIVE,
34         [BUSNAME_RUNNING] = UNIT_ACTIVE,
35         [BUSNAME_FAILED] = UNIT_FAILED
36 };
37
38 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
39
40 static 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;
47         n->accept_fd = true;
48 }
49
50 static 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);
61         n->starter_fd = safe_close(n->starter_fd);
62 }
63
64 static 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
82 static 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
100         if (n->activating) {
101                 if (!UNIT_DEREF(n->service)) {
102                         Unit *x;
103
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);
112                 if (r < 0)
113                         return r;
114         }
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 static 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
147 static 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
168 static 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"
177                 "%sName: %s\n"
178                 "%sActivating: %s\n"
179                 "%sAccept FD: %s\n",
180                 prefix, busname_state_to_string(n->state),
181                 prefix, busname_result_to_string(n->result),
182                 prefix, n->name,
183                 prefix, yes_no(n->activating),
184                 prefix, yes_no(n->accept_fd));
185 }
186
187 static 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
199 static void busname_close_fd(BusName *n) {
200         assert(n);
201
202         busname_unwatch_fd(n);
203
204         if (n->starter_fd <= 0)
205                 return;
206
207         n->starter_fd = safe_close(n->starter_fd);
208 }
209
210 static 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
221                 r = sd_event_add_io(UNIT(n)->manager->event, &n->event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
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
231 static int busname_open_fd(BusName *n) {
232         assert(n);
233
234         if (n->starter_fd >= 0)
235                 return 0;
236
237         n->starter_fd = bus_kernel_create_starter(
238                         UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
239                         n->name, n->activating, n->accept_fd, n->policy);
240
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
249 static 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
259         if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING))
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
269 static 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
279         if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING)) {
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
295 static 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
304 static void busname_enter_listening(BusName *n) {
305         int r;
306
307         assert(n);
308
309         r = busname_open_fd(n);
310         if (r < 0) {
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));
314                 goto fail;
315         }
316
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);
327
328         return;
329
330 fail:
331         busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
332 }
333
334 static 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
343         if (!n->activating)
344                 return;
345
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);
351
352                 /* Flush all queued activation reqeuest by closing and reopening the connection */
353                 bus_kernel_drop_one(n->starter_fd);
354
355                 busname_enter_listening(n);
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
376 fail:
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
381 static int busname_start(Unit *u) {
382         BusName *n = BUSNAME(u);
383
384         assert(n);
385
386         if (n->activating && UNIT_ISSET(n->service)) {
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
405 static int busname_stop(Unit *u) {
406         BusName *n = BUSNAME(u);
407
408         assert(n);
409         assert(IN_SET(n->state, BUSNAME_REGISTERED, BUSNAME_LISTENING, BUSNAME_RUNNING));
410
411         busname_enter_dead(n, BUSNAME_SUCCESS);
412         return 0;
413 }
414
415 static 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
438 static 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 {
469                         safe_close(n->starter_fd);
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
490 static 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;
509 fail:
510
511         busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
512         return 0;
513 }
514
515 static 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
526 static 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
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))
548                 busname_enter_listening(n);
549 }
550
551 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
552         [BUSNAME_DEAD] = "dead",
553         [BUSNAME_REGISTERED] = "registered",
554         [BUSNAME_LISTENING] = "listening",
555         [BUSNAME_RUNNING] = "running",
556         [BUSNAME_FAILED] = "failed"
557 };
558
559 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
560
561 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
562         [BUSNAME_SUCCESS] = "success",
563         [BUSNAME_FAILURE_RESOURCES] = "resources",
564         [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
565 };
566
567 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
568
569 static 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
575 DEFINE_STRING_TABLE_LOOKUP(busname_policy_access, BusNamePolicyAccess);
576
577 const 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,
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 };