]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/path.c
core: pull in dbus.socket from Type=dbus services
[thirdparty/systemd.git] / src / core / path.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 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 <errno.h>
23 #include <sys/epoll.h>
24 #include <sys/inotify.h>
25 #include <unistd.h>
26
27 #include "bus-error.h"
28 #include "bus-util.h"
29 #include "dbus-path.h"
30 #include "fd-util.h"
31 #include "fs-util.h"
32 #include "glob-util.h"
33 #include "macro.h"
34 #include "mkdir.h"
35 #include "path.h"
36 #include "special.h"
37 #include "stat-util.h"
38 #include "string-table.h"
39 #include "string-util.h"
40 #include "unit-name.h"
41 #include "unit.h"
42
43 static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
44 [PATH_DEAD] = UNIT_INACTIVE,
45 [PATH_WAITING] = UNIT_ACTIVE,
46 [PATH_RUNNING] = UNIT_ACTIVE,
47 [PATH_FAILED] = UNIT_FAILED
48 };
49
50 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
51
52 int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
53
54 static const int flags_table[_PATH_TYPE_MAX] = {
55 [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
56 [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
57 [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
58 [PATH_MODIFIED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO|IN_MODIFY,
59 [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
60 };
61
62 bool exists = false;
63 char *slash, *oldslash = NULL;
64 int r;
65
66 assert(s);
67 assert(s->unit);
68 assert(handler);
69
70 path_spec_unwatch(s);
71
72 s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
73 if (s->inotify_fd < 0) {
74 r = -errno;
75 goto fail;
76 }
77
78 r = sd_event_add_io(s->unit->manager->event, &s->event_source, s->inotify_fd, EPOLLIN, handler, s);
79 if (r < 0)
80 goto fail;
81
82 (void) sd_event_source_set_description(s->event_source, "path");
83
84 /* This assumes the path was passed through path_kill_slashes()! */
85
86 for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
87 char *cut = NULL;
88 int flags;
89 char tmp;
90
91 if (slash) {
92 cut = slash + (slash == s->path);
93 tmp = *cut;
94 *cut = '\0';
95
96 flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
97 } else
98 flags = flags_table[s->type];
99
100 r = inotify_add_watch(s->inotify_fd, s->path, flags);
101 if (r < 0) {
102 if (errno == EACCES || errno == ENOENT) {
103 if (cut)
104 *cut = tmp;
105 break;
106 }
107
108 r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror(-r));
109 if (cut)
110 *cut = tmp;
111 goto fail;
112 } else {
113 exists = true;
114
115 /* Path exists, we don't need to watch parent
116 too closely. */
117 if (oldslash) {
118 char *cut2 = oldslash + (oldslash == s->path);
119 char tmp2 = *cut2;
120 *cut2 = '\0';
121
122 inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
123 /* Error is ignored, the worst can happen is
124 we get spurious events. */
125
126 *cut2 = tmp2;
127 }
128 }
129
130 if (cut)
131 *cut = tmp;
132
133 if (slash)
134 oldslash = slash;
135 else {
136 /* whole path has been iterated over */
137 s->primary_wd = r;
138 break;
139 }
140 }
141
142 if (!exists) {
143 r = log_error_errno(errno, "Failed to add watch on any of the components of %s: %m", s->path);
144 /* either EACCESS or ENOENT */
145 goto fail;
146 }
147
148 return 0;
149
150 fail:
151 path_spec_unwatch(s);
152 return r;
153 }
154
155 void path_spec_unwatch(PathSpec *s) {
156 assert(s);
157
158 s->event_source = sd_event_source_unref(s->event_source);
159 s->inotify_fd = safe_close(s->inotify_fd);
160 }
161
162 int path_spec_fd_event(PathSpec *s, uint32_t revents) {
163 union inotify_event_buffer buffer;
164 struct inotify_event *e;
165 ssize_t l;
166 int r = 0;
167
168 if (revents != EPOLLIN) {
169 log_error("Got invalid poll event on inotify.");
170 return -EINVAL;
171 }
172
173 l = read(s->inotify_fd, &buffer, sizeof(buffer));
174 if (l < 0) {
175 if (errno == EAGAIN || errno == EINTR)
176 return 0;
177
178 return log_error_errno(errno, "Failed to read inotify event: %m");
179 }
180
181 FOREACH_INOTIFY_EVENT(e, buffer, l) {
182 if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
183 s->primary_wd == e->wd)
184 r = 1;
185 }
186
187 return r;
188 }
189
190 static bool path_spec_check_good(PathSpec *s, bool initial) {
191 bool good = false;
192
193 switch (s->type) {
194
195 case PATH_EXISTS:
196 good = access(s->path, F_OK) >= 0;
197 break;
198
199 case PATH_EXISTS_GLOB:
200 good = glob_exists(s->path) > 0;
201 break;
202
203 case PATH_DIRECTORY_NOT_EMPTY: {
204 int k;
205
206 k = dir_is_empty(s->path);
207 good = !(k == -ENOENT || k > 0);
208 break;
209 }
210
211 case PATH_CHANGED:
212 case PATH_MODIFIED: {
213 bool b;
214
215 b = access(s->path, F_OK) >= 0;
216 good = !initial && b != s->previous_exists;
217 s->previous_exists = b;
218 break;
219 }
220
221 default:
222 ;
223 }
224
225 return good;
226 }
227
228 static void path_spec_mkdir(PathSpec *s, mode_t mode) {
229 int r;
230
231 if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
232 return;
233
234 r = mkdir_p_label(s->path, mode);
235 if (r < 0)
236 log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
237 }
238
239 static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
240 fprintf(f,
241 "%s%s: %s\n",
242 prefix,
243 path_type_to_string(s->type),
244 s->path);
245 }
246
247 void path_spec_done(PathSpec *s) {
248 assert(s);
249 assert(s->inotify_fd == -1);
250
251 free(s->path);
252 }
253
254 static void path_init(Unit *u) {
255 Path *p = PATH(u);
256
257 assert(u);
258 assert(u->load_state == UNIT_STUB);
259
260 p->directory_mode = 0755;
261 }
262
263 void path_free_specs(Path *p) {
264 PathSpec *s;
265
266 assert(p);
267
268 while ((s = p->specs)) {
269 path_spec_unwatch(s);
270 LIST_REMOVE(spec, p->specs, s);
271 path_spec_done(s);
272 free(s);
273 }
274 }
275
276 static void path_done(Unit *u) {
277 Path *p = PATH(u);
278
279 assert(p);
280
281 path_free_specs(p);
282 }
283
284 static int path_add_mount_links(Path *p) {
285 PathSpec *s;
286 int r;
287
288 assert(p);
289
290 LIST_FOREACH(spec, s, p->specs) {
291 r = unit_require_mounts_for(UNIT(p), s->path);
292 if (r < 0)
293 return r;
294 }
295
296 return 0;
297 }
298
299 static int path_verify(Path *p) {
300 assert(p);
301
302 if (UNIT(p)->load_state != UNIT_LOADED)
303 return 0;
304
305 if (!p->specs) {
306 log_unit_error(UNIT(p), "Path unit lacks path setting. Refusing.");
307 return -EINVAL;
308 }
309
310 return 0;
311 }
312
313 static int path_add_default_dependencies(Path *p) {
314 int r;
315
316 assert(p);
317
318 r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
319 SPECIAL_PATHS_TARGET, NULL, true);
320 if (r < 0)
321 return r;
322
323 if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
324 r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
325 SPECIAL_SYSINIT_TARGET, NULL, true);
326 if (r < 0)
327 return r;
328 }
329
330 return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
331 SPECIAL_SHUTDOWN_TARGET, NULL, true);
332 }
333
334 static int path_load(Unit *u) {
335 Path *p = PATH(u);
336 int r;
337
338 assert(u);
339 assert(u->load_state == UNIT_STUB);
340
341 r = unit_load_fragment_and_dropin(u);
342 if (r < 0)
343 return r;
344
345 if (u->load_state == UNIT_LOADED) {
346
347 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
348 Unit *x;
349
350 r = unit_load_related_unit(u, ".service", &x);
351 if (r < 0)
352 return r;
353
354 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
355 if (r < 0)
356 return r;
357 }
358
359 r = path_add_mount_links(p);
360 if (r < 0)
361 return r;
362
363 if (UNIT(p)->default_dependencies) {
364 r = path_add_default_dependencies(p);
365 if (r < 0)
366 return r;
367 }
368 }
369
370 return path_verify(p);
371 }
372
373 static void path_dump(Unit *u, FILE *f, const char *prefix) {
374 Path *p = PATH(u);
375 Unit *trigger;
376 PathSpec *s;
377
378 assert(p);
379 assert(f);
380
381 trigger = UNIT_TRIGGER(u);
382
383 fprintf(f,
384 "%sPath State: %s\n"
385 "%sResult: %s\n"
386 "%sUnit: %s\n"
387 "%sMakeDirectory: %s\n"
388 "%sDirectoryMode: %04o\n",
389 prefix, path_state_to_string(p->state),
390 prefix, path_result_to_string(p->result),
391 prefix, trigger ? trigger->id : "n/a",
392 prefix, yes_no(p->make_directory),
393 prefix, p->directory_mode);
394
395 LIST_FOREACH(spec, s, p->specs)
396 path_spec_dump(s, f, prefix);
397 }
398
399 static void path_unwatch(Path *p) {
400 PathSpec *s;
401
402 assert(p);
403
404 LIST_FOREACH(spec, s, p->specs)
405 path_spec_unwatch(s);
406 }
407
408 static int path_watch(Path *p) {
409 int r;
410 PathSpec *s;
411
412 assert(p);
413
414 LIST_FOREACH(spec, s, p->specs) {
415 r = path_spec_watch(s, path_dispatch_io);
416 if (r < 0)
417 return r;
418 }
419
420 return 0;
421 }
422
423 static void path_set_state(Path *p, PathState state) {
424 PathState old_state;
425 assert(p);
426
427 old_state = p->state;
428 p->state = state;
429
430 if (state != PATH_WAITING &&
431 (state != PATH_RUNNING || p->inotify_triggered))
432 path_unwatch(p);
433
434 if (state != old_state)
435 log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
436
437 unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
438 }
439
440 static void path_enter_waiting(Path *p, bool initial, bool recheck);
441
442 static int path_coldplug(Unit *u) {
443 Path *p = PATH(u);
444
445 assert(p);
446 assert(p->state == PATH_DEAD);
447
448 if (p->deserialized_state != p->state) {
449
450 if (p->deserialized_state == PATH_WAITING ||
451 p->deserialized_state == PATH_RUNNING)
452 path_enter_waiting(p, true, true);
453 else
454 path_set_state(p, p->deserialized_state);
455 }
456
457 return 0;
458 }
459
460 static void path_enter_dead(Path *p, PathResult f) {
461 assert(p);
462
463 if (f != PATH_SUCCESS)
464 p->result = f;
465
466 path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
467 }
468
469 static void path_enter_running(Path *p) {
470 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
471 int r;
472
473 assert(p);
474
475 /* Don't start job if we are supposed to go down */
476 if (unit_stop_pending(UNIT(p)))
477 return;
478
479 r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
480 JOB_REPLACE, true, &error, NULL);
481 if (r < 0)
482 goto fail;
483
484 p->inotify_triggered = false;
485
486 r = path_watch(p);
487 if (r < 0)
488 goto fail;
489
490 path_set_state(p, PATH_RUNNING);
491 return;
492
493 fail:
494 log_unit_warning(UNIT(p), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
495 path_enter_dead(p, PATH_FAILURE_RESOURCES);
496 }
497
498 static bool path_check_good(Path *p, bool initial) {
499 PathSpec *s;
500 bool good = false;
501
502 assert(p);
503
504 LIST_FOREACH(spec, s, p->specs) {
505 good = path_spec_check_good(s, initial);
506
507 if (good)
508 break;
509 }
510
511 return good;
512 }
513
514 static void path_enter_waiting(Path *p, bool initial, bool recheck) {
515 int r;
516
517 if (recheck)
518 if (path_check_good(p, initial)) {
519 log_unit_debug(UNIT(p), "Got triggered.");
520 path_enter_running(p);
521 return;
522 }
523
524 r = path_watch(p);
525 if (r < 0)
526 goto fail;
527
528 /* Hmm, so now we have created inotify watches, but the file
529 * might have appeared/been removed by now, so we must
530 * recheck */
531
532 if (recheck)
533 if (path_check_good(p, false)) {
534 log_unit_debug(UNIT(p), "Got triggered.");
535 path_enter_running(p);
536 return;
537 }
538
539 path_set_state(p, PATH_WAITING);
540 return;
541
542 fail:
543 log_unit_warning_errno(UNIT(p), r, "Failed to enter waiting state: %m");
544 path_enter_dead(p, PATH_FAILURE_RESOURCES);
545 }
546
547 static void path_mkdir(Path *p) {
548 PathSpec *s;
549
550 assert(p);
551
552 if (!p->make_directory)
553 return;
554
555 LIST_FOREACH(spec, s, p->specs)
556 path_spec_mkdir(s, p->directory_mode);
557 }
558
559 static int path_start(Unit *u) {
560 Path *p = PATH(u);
561
562 assert(p);
563 assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
564
565 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
566 return -ENOENT;
567
568 path_mkdir(p);
569
570 p->result = PATH_SUCCESS;
571 path_enter_waiting(p, true, true);
572
573 return 1;
574 }
575
576 static int path_stop(Unit *u) {
577 Path *p = PATH(u);
578
579 assert(p);
580 assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
581
582 path_enter_dead(p, PATH_SUCCESS);
583 return 1;
584 }
585
586 static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
587 Path *p = PATH(u);
588
589 assert(u);
590 assert(f);
591 assert(fds);
592
593 unit_serialize_item(u, f, "state", path_state_to_string(p->state));
594 unit_serialize_item(u, f, "result", path_result_to_string(p->result));
595
596 return 0;
597 }
598
599 static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
600 Path *p = PATH(u);
601
602 assert(u);
603 assert(key);
604 assert(value);
605 assert(fds);
606
607 if (streq(key, "state")) {
608 PathState state;
609
610 state = path_state_from_string(value);
611 if (state < 0)
612 log_unit_debug(u, "Failed to parse state value: %s", value);
613 else
614 p->deserialized_state = state;
615
616 } else if (streq(key, "result")) {
617 PathResult f;
618
619 f = path_result_from_string(value);
620 if (f < 0)
621 log_unit_debug(u, "Failed to parse result value: %s", value);
622 else if (f != PATH_SUCCESS)
623 p->result = f;
624
625 } else
626 log_unit_debug(u, "Unknown serialization key: %s", key);
627
628 return 0;
629 }
630
631 _pure_ static UnitActiveState path_active_state(Unit *u) {
632 assert(u);
633
634 return state_translation_table[PATH(u)->state];
635 }
636
637 _pure_ static const char *path_sub_state_to_string(Unit *u) {
638 assert(u);
639
640 return path_state_to_string(PATH(u)->state);
641 }
642
643 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
644 PathSpec *s = userdata;
645 Path *p;
646 int changed;
647
648 assert(s);
649 assert(s->unit);
650 assert(fd >= 0);
651
652 p = PATH(s->unit);
653
654 if (p->state != PATH_WAITING &&
655 p->state != PATH_RUNNING)
656 return 0;
657
658 /* log_debug("inotify wakeup on %s.", u->id); */
659
660 LIST_FOREACH(spec, s, p->specs)
661 if (path_spec_owns_inotify_fd(s, fd))
662 break;
663
664 if (!s) {
665 log_error("Got event on unknown fd.");
666 goto fail;
667 }
668
669 changed = path_spec_fd_event(s, revents);
670 if (changed < 0)
671 goto fail;
672
673 /* If we are already running, then remember that one event was
674 * dispatched so that we restart the service only if something
675 * actually changed on disk */
676 p->inotify_triggered = true;
677
678 if (changed)
679 path_enter_running(p);
680 else
681 path_enter_waiting(p, false, true);
682
683 return 0;
684
685 fail:
686 path_enter_dead(p, PATH_FAILURE_RESOURCES);
687 return 0;
688 }
689
690 static void path_trigger_notify(Unit *u, Unit *other) {
691 Path *p = PATH(u);
692
693 assert(u);
694 assert(other);
695
696 /* Invoked whenever the unit we trigger changes state or gains
697 * or loses a job */
698
699 if (other->load_state != UNIT_LOADED)
700 return;
701
702 if (p->state == PATH_RUNNING &&
703 UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
704 log_unit_debug(UNIT(p), "Got notified about unit deactivation.");
705
706 /* Hmm, so inotify was triggered since the
707 * last activation, so I guess we need to
708 * recheck what is going on. */
709 path_enter_waiting(p, false, p->inotify_triggered);
710 }
711 }
712
713 static void path_reset_failed(Unit *u) {
714 Path *p = PATH(u);
715
716 assert(p);
717
718 if (p->state == PATH_FAILED)
719 path_set_state(p, PATH_DEAD);
720
721 p->result = PATH_SUCCESS;
722 }
723
724 static const char* const path_type_table[_PATH_TYPE_MAX] = {
725 [PATH_EXISTS] = "PathExists",
726 [PATH_EXISTS_GLOB] = "PathExistsGlob",
727 [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
728 [PATH_CHANGED] = "PathChanged",
729 [PATH_MODIFIED] = "PathModified",
730 };
731
732 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
733
734 static const char* const path_result_table[_PATH_RESULT_MAX] = {
735 [PATH_SUCCESS] = "success",
736 [PATH_FAILURE_RESOURCES] = "resources",
737 };
738
739 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
740
741 const UnitVTable path_vtable = {
742 .object_size = sizeof(Path),
743
744 .sections =
745 "Unit\0"
746 "Path\0"
747 "Install\0",
748
749 .init = path_init,
750 .done = path_done,
751 .load = path_load,
752
753 .coldplug = path_coldplug,
754
755 .dump = path_dump,
756
757 .start = path_start,
758 .stop = path_stop,
759
760 .serialize = path_serialize,
761 .deserialize_item = path_deserialize_item,
762
763 .active_state = path_active_state,
764 .sub_state_to_string = path_sub_state_to_string,
765
766 .trigger_notify = path_trigger_notify,
767
768 .reset_failed = path_reset_failed,
769
770 .bus_vtable = bus_path_vtable
771 };