1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <sys/epoll.h>
5 #include <sys/inotify.h>
6 #include <unistd.h>
7
8 #include "bus-error.h"
9 #include "bus-util.h"
10 #include "dbus-path.h"
11 #include "dbus-unit.h"
12 #include "escape.h"
13 #include "fd-util.h"
14 #include "glob-util.h"
15 #include "inotify-util.h"
16 #include "macro.h"
17 #include "mkdir-label.h"
18 #include "path.h"
19 #include "path-util.h"
20 #include "serialize.h"
21 #include "special.h"
22 #include "stat-util.h"
23 #include "string-table.h"
24 #include "string-util.h"
25 #include "unit-name.h"
26 #include "unit.h"
27
28 static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
29 [PATH_DEAD] = UNIT_INACTIVE,
30 [PATH_WAITING] = UNIT_ACTIVE,
31 [PATH_RUNNING] = UNIT_ACTIVE,
32 [PATH_FAILED] = UNIT_FAILED,
33 };
34
35 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
36
path_spec_watch(PathSpec * s,sd_event_io_handler_t handler)37 int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
38 static const int flags_table[_PATH_TYPE_MAX] = {
39 [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
40 [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
41 [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
42 [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,
43 [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO,
44 };
45
46 bool exists = false;
47 char *slash, *oldslash = NULL;
48 int r;
49
50 assert(s);
51 assert(s->unit);
52 assert(handler);
53
54 path_spec_unwatch(s);
55
56 s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
57 if (s->inotify_fd < 0) {
58 r = log_error_errno(errno, "Failed to allocate inotify fd: %m");
59 goto fail;
60 }
61
62 r = sd_event_add_io(s->unit->manager->event, &s->event_source, s->inotify_fd, EPOLLIN, handler, s);
63 if (r < 0) {
64 log_error_errno(r, "Failed to add inotify fd to event loop: %m");
65 goto fail;
66 }
67
68 (void) sd_event_source_set_description(s->event_source, "path");
69
70 /* This function assumes the path was passed through path_simplify()! */
71 assert(!strstr(s->path, "//"));
72
73 for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
74 bool incomplete = false;
75 int flags, wd = -1;
76 char tmp, *cut;
77
78 if (slash) {
79 cut = slash + (slash == s->path);
80 tmp = *cut;
81 *cut = '\0';
82
83 flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
84 } else {
85 cut = NULL;
86 flags = flags_table[s->type];
87 }
88
89 /* If this is a symlink watch both the symlink inode and where it points to. If the inode is
90 * not a symlink both calls will install the same watch, which is redundant and doesn't
91 * hurt. */
92 for (int follow_symlink = 0; follow_symlink < 2; follow_symlink ++) {
93 uint32_t f = flags;
94
95 SET_FLAG(f, IN_DONT_FOLLOW, !follow_symlink);
96
97 wd = inotify_add_watch(s->inotify_fd, s->path, f);
98 if (wd < 0) {
99 if (IN_SET(errno, EACCES, ENOENT)) {
100 incomplete = true; /* This is an expected error, let's accept this
101 * quietly: we have an incomplete watch for
102 * now. */
103 break;
104 }
105
106 /* This second call to inotify_add_watch() should fail like the previous one
107 * and is done for logging the error in a comprehensive way. */
108 wd = inotify_add_watch_and_warn(s->inotify_fd, s->path, f);
109 if (wd < 0) {
110 if (cut)
111 *cut = tmp;
112
113 r = wd;
114 goto fail;
115 }
116
117 /* Hmm, we succeeded in adding the watch this time... let's continue. */
118 }
119 }
120
121 if (incomplete) {
122 if (cut)
123 *cut = tmp;
124
125 break;
126 }
127
128 exists = true;
129
130 /* Path exists, we don't need to watch parent too closely. */
131 if (oldslash) {
132 char *cut2 = oldslash + (oldslash == s->path);
133 char tmp2 = *cut2;
134 *cut2 = '\0';
135
136 (void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
137 /* Error is ignored, the worst can happen is we get spurious events. */
138
139 *cut2 = tmp2;
140 }
141
142 if (cut)
143 *cut = tmp;
144
145 if (slash)
146 oldslash = slash;
147 else {
148 /* whole path has been iterated over */
149 s->primary_wd = wd;
150 break;
151 }
152 }
153
154 if (!exists) {
155 r = log_error_errno(errno, "Failed to add watch on any of the components of %s: %m", s->path);
156 /* either EACCESS or ENOENT */
157 goto fail;
158 }
159
160 return 0;
161
162 fail:
163 path_spec_unwatch(s);
164 return r;
165 }
166
path_spec_unwatch(PathSpec * s)167 void path_spec_unwatch(PathSpec *s) {
168 assert(s);
169
170 s->event_source = sd_event_source_disable_unref(s->event_source);
171 s->inotify_fd = safe_close(s->inotify_fd);
172 }
173
path_spec_fd_event(PathSpec * s,uint32_t revents)174 int path_spec_fd_event(PathSpec *s, uint32_t revents) {
175 union inotify_event_buffer buffer;
176 ssize_t l;
177
178 assert(s);
179
180 if (revents != EPOLLIN)
181 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
182 "Got invalid poll event on inotify.");
183
184 l = read(s->inotify_fd, &buffer, sizeof(buffer));
185 if (l < 0) {
186 if (ERRNO_IS_TRANSIENT(errno))
187 return 0;
188
189 return log_error_errno(errno, "Failed to read inotify event: %m");
190 }
191
192 if (IN_SET(s->type, PATH_CHANGED, PATH_MODIFIED))
193 FOREACH_INOTIFY_EVENT_WARN(e, buffer, l)
194 if (s->primary_wd == e->wd)
195 return 1;
196
197 return 0;
198 }
199
path_spec_check_good(PathSpec * s,bool initial,bool from_trigger_notify)200 static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_notify) {
201 bool b, good = false;
202
203 switch (s->type) {
204
205 case PATH_EXISTS:
206 good = access(s->path, F_OK) >= 0;
207 break;
208
209 case PATH_EXISTS_GLOB:
210 good = glob_exists(s->path) > 0;
211 break;
212
213 case PATH_DIRECTORY_NOT_EMPTY: {
214 int k;
215
216 k = dir_is_empty(s->path, /* ignore_hidden_or_backup= */ true);
217 good = !(IN_SET(k, -ENOENT, -ENOTDIR) || k > 0);
218 break;
219 }
220
221 case PATH_CHANGED:
222 case PATH_MODIFIED:
223 b = access(s->path, F_OK) >= 0;
224 good = !initial && !from_trigger_notify && b != s->previous_exists;
225 s->previous_exists = b;
226 break;
227
228 default:
229 ;
230 }
231
232 return good;
233 }
234
path_spec_mkdir(PathSpec * s,mode_t mode)235 static void path_spec_mkdir(PathSpec *s, mode_t mode) {
236 int r;
237
238 if (IN_SET(s->type, PATH_EXISTS, PATH_EXISTS_GLOB))
239 return;
240
241 r = mkdir_p_label(s->path, mode);
242 if (r < 0)
243 log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
244 }
245
path_spec_dump(PathSpec * s,FILE * f,const char * prefix)246 static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
247 const char *type;
248
249 assert_se(type = path_type_to_string(s->type));
250 fprintf(f, "%s%s: %s\n", prefix, type, s->path);
251 }
252
path_spec_done(PathSpec * s)253 void path_spec_done(PathSpec *s) {
254 assert(s);
255 assert(s->inotify_fd == -1);
256
257 free(s->path);
258 }
259
path_init(Unit * u)260 static void path_init(Unit *u) {
261 Path *p = PATH(u);
262
263 assert(u);
264 assert(u->load_state == UNIT_STUB);
265
266 p->directory_mode = 0755;
267
268 p->trigger_limit.interval = USEC_INFINITY;
269 p->trigger_limit.burst = UINT_MAX;
270 }
271
path_free_specs(Path * p)272 void path_free_specs(Path *p) {
273 PathSpec *s;
274
275 assert(p);
276
277 while ((s = p->specs)) {
278 path_spec_unwatch(s);
279 LIST_REMOVE(spec, p->specs, s);
280 path_spec_done(s);
281 free(s);
282 }
283 }
284
path_done(Unit * u)285 static void path_done(Unit *u) {
286 Path *p = PATH(u);
287
288 assert(p);
289
290 path_free_specs(p);
291 }
292
path_add_mount_dependencies(Path * p)293 static int path_add_mount_dependencies(Path *p) {
294 int r;
295
296 assert(p);
297
298 LIST_FOREACH(spec, s, p->specs) {
299 r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE);
300 if (r < 0)
301 return r;
302 }
303
304 return 0;
305 }
306
path_verify(Path * p)307 static int path_verify(Path *p) {
308 assert(p);
309 assert(UNIT(p)->load_state == UNIT_LOADED);
310
311 if (!p->specs)
312 return log_unit_error_errno(UNIT(p), SYNTHETIC_ERRNO(ENOEXEC), "Path unit lacks path setting. Refusing.");
313
314 return 0;
315 }
316
path_add_default_dependencies(Path * p)317 static int path_add_default_dependencies(Path *p) {
318 int r;
319
320 assert(p);
321
322 if (!UNIT(p)->default_dependencies)
323 return 0;
324
325 r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
326 if (r < 0)
327 return r;
328
329 if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
330 r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
331 if (r < 0)
332 return r;
333 }
334
335 return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
336 }
337
path_add_trigger_dependencies(Path * p)338 static int path_add_trigger_dependencies(Path *p) {
339 Unit *x;
340 int r;
341
342 assert(p);
343
344 if (UNIT_TRIGGER(UNIT(p)))
345 return 0;
346
347 r = unit_load_related_unit(UNIT(p), ".service", &x);
348 if (r < 0)
349 return r;
350
351 return unit_add_two_dependencies(UNIT(p), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
352 }
353
path_add_extras(Path * p)354 static int path_add_extras(Path *p) {
355 int r;
356
357 assert(p);
358
359 /* To avoid getting pid1 in a busy-loop state (eg: failed condition on associated service),
360 * set a default trigger limit if the user didn't specify any. */
361 if (p->trigger_limit.interval == USEC_INFINITY)
362 p->trigger_limit.interval = 2 * USEC_PER_SEC;
363
364 if (p->trigger_limit.burst == UINT_MAX)
365 p->trigger_limit.burst = 200;
366
367 r = path_add_trigger_dependencies(p);
368 if (r < 0)
369 return r;
370
371 r = path_add_mount_dependencies(p);
372 if (r < 0)
373 return r;
374
375 return path_add_default_dependencies(p);
376 }
377
path_load(Unit * u)378 static int path_load(Unit *u) {
379 Path *p = PATH(u);
380 int r;
381
382 assert(u);
383 assert(u->load_state == UNIT_STUB);
384
385 r = unit_load_fragment_and_dropin(u, true);
386 if (r < 0)
387 return r;
388
389 if (u->load_state != UNIT_LOADED)
390 return 0;
391
392 r = path_add_extras(p);
393 if (r < 0)
394 return r;
395
396 return path_verify(p);
397 }
398
path_dump(Unit * u,FILE * f,const char * prefix)399 static void path_dump(Unit *u, FILE *f, const char *prefix) {
400 Path *p = PATH(u);
401 Unit *trigger;
402
403 assert(p);
404 assert(f);
405
406 trigger = UNIT_TRIGGER(u);
407
408 fprintf(f,
409 "%sPath State: %s\n"
410 "%sResult: %s\n"
411 "%sUnit: %s\n"
412 "%sMakeDirectory: %s\n"
413 "%sDirectoryMode: %04o\n"
414 "%sTriggerLimitIntervalSec: %s\n"
415 "%sTriggerLimitBurst: %u\n",
416 prefix, path_state_to_string(p->state),
417 prefix, path_result_to_string(p->result),
418 prefix, trigger ? trigger->id : "n/a",
419 prefix, yes_no(p->make_directory),
420 prefix, p->directory_mode,
421 prefix, FORMAT_TIMESPAN(p->trigger_limit.interval, USEC_PER_SEC),
422 prefix, p->trigger_limit.burst);
423
424 LIST_FOREACH(spec, s, p->specs)
425 path_spec_dump(s, f, prefix);
426 }
427
path_unwatch(Path * p)428 static void path_unwatch(Path *p) {
429 assert(p);
430
431 LIST_FOREACH(spec, s, p->specs)
432 path_spec_unwatch(s);
433 }
434
path_watch(Path * p)435 static int path_watch(Path *p) {
436 int r;
437
438 assert(p);
439
440 LIST_FOREACH(spec, s, p->specs) {
441 r = path_spec_watch(s, path_dispatch_io);
442 if (r < 0)
443 return r;
444 }
445
446 return 0;
447 }
448
path_set_state(Path * p,PathState state)449 static void path_set_state(Path *p, PathState state) {
450 PathState old_state;
451 assert(p);
452
453 if (p->state != state)
454 bus_unit_send_pending_change_signal(UNIT(p), false);
455
456 old_state = p->state;
457 p->state = state;
458
459 if (!IN_SET(state, PATH_WAITING, PATH_RUNNING))
460 path_unwatch(p);
461
462 if (state != old_state)
463 log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
464
465 unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], 0);
466 }
467
468 static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify);
469
path_coldplug(Unit * u)470 static int path_coldplug(Unit *u) {
471 Path *p = PATH(u);
472
473 assert(p);
474 assert(p->state == PATH_DEAD);
475
476 if (p->deserialized_state != p->state) {
477
478 if (IN_SET(p->deserialized_state, PATH_WAITING, PATH_RUNNING))
479 path_enter_waiting(p, true, false);
480 else
481 path_set_state(p, p->deserialized_state);
482 }
483
484 return 0;
485 }
486
path_enter_dead(Path * p,PathResult f)487 static void path_enter_dead(Path *p, PathResult f) {
488 assert(p);
489
490 if (p->result == PATH_SUCCESS)
491 p->result = f;
492
493 unit_log_result(UNIT(p), p->result == PATH_SUCCESS, path_result_to_string(p->result));
494 path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
495 }
496
path_enter_running(Path * p)497 static void path_enter_running(Path *p) {
498 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
499 Unit *trigger;
500 int r;
501
502 assert(p);
503
504 /* Don't start job if we are supposed to go down */
505 if (unit_stop_pending(UNIT(p)))
506 return;
507
508 if (!ratelimit_below(&p->trigger_limit)) {
509 log_unit_warning(UNIT(p), "Trigger limit hit, refusing further activation.");
510 path_enter_dead(p, PATH_FAILURE_TRIGGER_LIMIT_HIT);
511 return;
512 }
513
514 trigger = UNIT_TRIGGER(UNIT(p));
515 if (!trigger) {
516 log_unit_error(UNIT(p), "Unit to trigger vanished.");
517 path_enter_dead(p, PATH_FAILURE_RESOURCES);
518 return;
519 }
520
521 r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
522 if (r < 0)
523 goto fail;
524
525 path_set_state(p, PATH_RUNNING);
526 path_unwatch(p);
527
528 return;
529
530 fail:
531 log_unit_warning(UNIT(p), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
532 path_enter_dead(p, PATH_FAILURE_RESOURCES);
533 }
534
path_check_good(Path * p,bool initial,bool from_trigger_notify)535 static bool path_check_good(Path *p, bool initial, bool from_trigger_notify) {
536 assert(p);
537
538 LIST_FOREACH(spec, s, p->specs)
539 if (path_spec_check_good(s, initial, from_trigger_notify))
540 return true;
541
542 return false;
543 }
544
path_enter_waiting(Path * p,bool initial,bool from_trigger_notify)545 static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify) {
546 Unit *trigger;
547 int r;
548
549 /* If the triggered unit is already running, so are we */
550 trigger = UNIT_TRIGGER(UNIT(p));
551 if (trigger && !UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(trigger))) {
552 path_set_state(p, PATH_RUNNING);
553 path_unwatch(p);
554 return;
555 }
556
557 if (path_check_good(p, initial, from_trigger_notify)) {
558 log_unit_debug(UNIT(p), "Got triggered.");
559 path_enter_running(p);
560 return;
561 }
562
563 r = path_watch(p);
564 if (r < 0)
565 goto fail;
566
567 /* Hmm, so now we have created inotify watches, but the file
568 * might have appeared/been removed by now, so we must
569 * recheck */
570
571 if (path_check_good(p, false, from_trigger_notify)) {
572 log_unit_debug(UNIT(p), "Got triggered.");
573 path_enter_running(p);
574 return;
575 }
576
577 path_set_state(p, PATH_WAITING);
578 return;
579
580 fail:
581 log_unit_warning_errno(UNIT(p), r, "Failed to enter waiting state: %m");
582 path_enter_dead(p, PATH_FAILURE_RESOURCES);
583 }
584
path_mkdir(Path * p)585 static void path_mkdir(Path *p) {
586 assert(p);
587
588 if (!p->make_directory)
589 return;
590
591 LIST_FOREACH(spec, s, p->specs)
592 path_spec_mkdir(s, p->directory_mode);
593 }
594
path_start(Unit * u)595 static int path_start(Unit *u) {
596 Path *p = PATH(u);
597 int r;
598
599 assert(p);
600 assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED));
601
602 r = unit_test_trigger_loaded(u);
603 if (r < 0)
604 return r;
605
606 r = unit_acquire_invocation_id(u);
607 if (r < 0)
608 return r;
609
610 path_mkdir(p);
611
612 p->result = PATH_SUCCESS;
613 path_enter_waiting(p, true, false);
614
615 return 1;
616 }
617
path_stop(Unit * u)618 static int path_stop(Unit *u) {
619 Path *p = PATH(u);
620
621 assert(p);
622 assert(IN_SET(p->state, PATH_WAITING, PATH_RUNNING));
623
624 path_enter_dead(p, PATH_SUCCESS);
625 return 1;
626 }
627
path_serialize(Unit * u,FILE * f,FDSet * fds)628 static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
629 Path *p = PATH(u);
630
631 assert(u);
632 assert(f);
633 assert(fds);
634
635 (void) serialize_item(f, "state", path_state_to_string(p->state));
636 (void) serialize_item(f, "result", path_result_to_string(p->result));
637
638 LIST_FOREACH(spec, s, p->specs) {
639 const char *type;
640 _cleanup_free_ char *escaped = NULL;
641
642 escaped = cescape(s->path);
643 if (!escaped)
644 return log_oom();
645
646 assert_se(type = path_type_to_string(s->type));
647 (void) serialize_item_format(f, "path-spec", "%s %i %s",
648 type,
649 s->previous_exists,
650 escaped);
651 }
652
653 return 0;
654 }
655
path_deserialize_item(Unit * u,const char * key,const char * value,FDSet * fds)656 static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
657 Path *p = PATH(u);
658
659 assert(u);
660 assert(key);
661 assert(value);
662 assert(fds);
663
664 if (streq(key, "state")) {
665 PathState state;
666
667 state = path_state_from_string(value);
668 if (state < 0)
669 log_unit_debug(u, "Failed to parse state value: %s", value);
670 else
671 p->deserialized_state = state;
672
673 } else if (streq(key, "result")) {
674 PathResult f;
675
676 f = path_result_from_string(value);
677 if (f < 0)
678 log_unit_debug(u, "Failed to parse result value: %s", value);
679 else if (f != PATH_SUCCESS)
680 p->result = f;
681
682 } else if (streq(key, "path-spec")) {
683 int previous_exists, skip = 0;
684 _cleanup_free_ char *type_str = NULL;
685
686 if (sscanf(value, "%ms %i %n", &type_str, &previous_exists, &skip) < 2)
687 log_unit_debug(u, "Failed to parse path-spec value: %s", value);
688 else {
689 _cleanup_free_ char *unescaped = NULL;
690 ssize_t l;
691 PathType type;
692
693 type = path_type_from_string(type_str);
694 if (type < 0) {
695 log_unit_warning(u, "Unknown path type \"%s\", ignoring.", type_str);
696 return 0;
697 }
698
699 l = cunescape(value+skip, 0, &unescaped);
700 if (l < 0) {
701 log_unit_warning_errno(u, l, "Failed to unescape serialize path: %m");
702 return 0;
703 }
704
705 LIST_FOREACH(spec, s, p->specs)
706 if (s->type == type &&
707 path_equal(s->path, unescaped)) {
708
709 s->previous_exists = previous_exists;
710 break;
711 }
712 }
713
714 } else
715 log_unit_debug(u, "Unknown serialization key: %s", key);
716
717 return 0;
718 }
719
path_active_state(Unit * u)720 _pure_ static UnitActiveState path_active_state(Unit *u) {
721 assert(u);
722
723 return state_translation_table[PATH(u)->state];
724 }
725
path_sub_state_to_string(Unit * u)726 _pure_ static const char *path_sub_state_to_string(Unit *u) {
727 assert(u);
728
729 return path_state_to_string(PATH(u)->state);
730 }
731
path_dispatch_io(sd_event_source * source,int fd,uint32_t revents,void * userdata)732 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
733 PathSpec *s = userdata, *found = NULL;
734 Path *p;
735 int changed;
736
737 assert(s);
738 assert(s->unit);
739 assert(fd >= 0);
740
741 p = PATH(s->unit);
742
743 if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
744 return 0;
745
746 LIST_FOREACH(spec, i, p->specs)
747 if (path_spec_owns_inotify_fd(i, fd)) {
748 found = i;
749 break;
750 }
751
752 if (!found) {
753 log_error("Got event on unknown fd.");
754 goto fail;
755 }
756
757 changed = path_spec_fd_event(found, revents);
758 if (changed < 0)
759 goto fail;
760
761 if (changed)
762 path_enter_running(p);
763 else
764 path_enter_waiting(p, false, false);
765
766 return 0;
767
768 fail:
769 path_enter_dead(p, PATH_FAILURE_RESOURCES);
770 return 0;
771 }
772
path_trigger_notify(Unit * u,Unit * other)773 static void path_trigger_notify(Unit *u, Unit *other) {
774 Path *p = PATH(u);
775
776 assert(u);
777 assert(other);
778
779 /* Invoked whenever the unit we trigger changes state or gains or loses a job */
780
781 /* Filter out invocations with bogus state */
782 assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
783
784 /* Don't propagate state changes from the triggered unit if we are already down */
785 if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
786 return;
787
788 /* Propagate start limit hit state */
789 if (other->start_limit_hit) {
790 path_enter_dead(p, PATH_FAILURE_UNIT_START_LIMIT_HIT);
791 return;
792 }
793
794 /* Don't propagate anything if there's still a job queued */
795 if (other->job)
796 return;
797
798 if (p->state == PATH_RUNNING &&
799 UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
800 log_unit_debug(UNIT(p), "Got notified about unit deactivation.");
801 path_enter_waiting(p, false, true);
802 } else if (p->state == PATH_WAITING &&
803 !UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
804 log_unit_debug(UNIT(p), "Got notified about unit activation.");
805 path_enter_waiting(p, false, true);
806 }
807 }
808
path_reset_failed(Unit * u)809 static void path_reset_failed(Unit *u) {
810 Path *p = PATH(u);
811
812 assert(p);
813
814 if (p->state == PATH_FAILED)
815 path_set_state(p, PATH_DEAD);
816
817 p->result = PATH_SUCCESS;
818 }
819
path_can_start(Unit * u)820 static int path_can_start(Unit *u) {
821 Path *p = PATH(u);
822 int r;
823
824 assert(p);
825
826 r = unit_test_start_limit(u);
827 if (r < 0) {
828 path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
829 return r;
830 }
831
832 return 1;
833 }
834
835 static const char* const path_type_table[_PATH_TYPE_MAX] = {
836 [PATH_EXISTS] = "PathExists",
837 [PATH_EXISTS_GLOB] = "PathExistsGlob",
838 [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
839 [PATH_CHANGED] = "PathChanged",
840 [PATH_MODIFIED] = "PathModified",
841 };
842
843 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
844
845 static const char* const path_result_table[_PATH_RESULT_MAX] = {
846 [PATH_SUCCESS] = "success",
847 [PATH_FAILURE_RESOURCES] = "resources",
848 [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
849 [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
850 [PATH_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
851 };
852
853 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
854
855 const UnitVTable path_vtable = {
856 .object_size = sizeof(Path),
857
858 .sections =
859 "Unit\0"
860 "Path\0"
861 "Install\0",
862 .private_section = "Path",
863
864 .can_transient = true,
865 .can_fail = true,
866 .can_trigger = true,
867
868 .init = path_init,
869 .done = path_done,
870 .load = path_load,
871
872 .coldplug = path_coldplug,
873
874 .dump = path_dump,
875
876 .start = path_start,
877 .stop = path_stop,
878
879 .serialize = path_serialize,
880 .deserialize_item = path_deserialize_item,
881
882 .active_state = path_active_state,
883 .sub_state_to_string = path_sub_state_to_string,
884
885 .trigger_notify = path_trigger_notify,
886
887 .reset_failed = path_reset_failed,
888
889 .bus_set_property = bus_path_set_property,
890
891 .can_start = path_can_start,
892 };
893