]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/path.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / core / path.c
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
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
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
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
200 static bool path_spec_check_good(PathSpec *s, bool initial, bool from_trigger_notify, char **ret_trigger_path) {
201 _cleanup_free_ char *trigger = NULL;
202 bool b, good = false;
203
204 assert(s);
205 assert(ret_trigger_path);
206
207 switch (s->type) {
208
209 case PATH_EXISTS:
210 good = access(s->path, F_OK) >= 0;
211 break;
212
213 case PATH_EXISTS_GLOB:
214 good = glob_first(s->path, &trigger) > 0;
215 break;
216
217 case PATH_DIRECTORY_NOT_EMPTY: {
218 int k;
219
220 k = dir_is_empty(s->path, /* ignore_hidden_or_backup= */ true);
221 good = !(IN_SET(k, -ENOENT, -ENOTDIR) || k > 0);
222 break;
223 }
224
225 case PATH_CHANGED:
226 case PATH_MODIFIED:
227 b = access(s->path, F_OK) >= 0;
228 good = !initial && !from_trigger_notify && b != s->previous_exists;
229 s->previous_exists = b;
230 break;
231
232 default:
233 ;
234 }
235
236 if (good) {
237 if (!trigger) {
238 trigger = strdup(s->path);
239 if (!trigger)
240 (void) log_oom_debug();
241 }
242 *ret_trigger_path = TAKE_PTR(trigger);
243 }
244
245 return good;
246 }
247
248 static void path_spec_mkdir(PathSpec *s, mode_t mode) {
249 int r;
250
251 if (IN_SET(s->type, PATH_EXISTS, PATH_EXISTS_GLOB))
252 return;
253
254 r = mkdir_p_label(s->path, mode);
255 if (r < 0)
256 log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
257 }
258
259 static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
260 const char *type;
261
262 assert_se(type = path_type_to_string(s->type));
263 fprintf(f, "%s%s: %s\n", prefix, type, s->path);
264 }
265
266 void path_spec_done(PathSpec *s) {
267 assert(s);
268 assert(s->inotify_fd == -EBADF);
269
270 free(s->path);
271 }
272
273 static void path_init(Unit *u) {
274 Path *p = PATH(u);
275
276 assert(u);
277 assert(u->load_state == UNIT_STUB);
278
279 p->directory_mode = 0755;
280
281 p->trigger_limit.interval = USEC_INFINITY;
282 p->trigger_limit.burst = UINT_MAX;
283 }
284
285 void path_free_specs(Path *p) {
286 PathSpec *s;
287
288 assert(p);
289
290 while ((s = p->specs)) {
291 path_spec_unwatch(s);
292 LIST_REMOVE(spec, p->specs, s);
293 path_spec_done(s);
294 free(s);
295 }
296 }
297
298 static void path_done(Unit *u) {
299 Path *p = PATH(u);
300
301 assert(p);
302
303 path_free_specs(p);
304 }
305
306 static int path_add_mount_dependencies(Path *p) {
307 int r;
308
309 assert(p);
310
311 LIST_FOREACH(spec, s, p->specs) {
312 r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE);
313 if (r < 0)
314 return r;
315 }
316
317 return 0;
318 }
319
320 static int path_verify(Path *p) {
321 assert(p);
322 assert(UNIT(p)->load_state == UNIT_LOADED);
323
324 if (!p->specs)
325 return log_unit_error_errno(UNIT(p), SYNTHETIC_ERRNO(ENOEXEC), "Path unit lacks path setting. Refusing.");
326
327 return 0;
328 }
329
330 static int path_add_default_dependencies(Path *p) {
331 int r;
332
333 assert(p);
334
335 if (!UNIT(p)->default_dependencies)
336 return 0;
337
338 r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
339 if (r < 0)
340 return r;
341
342 if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
343 r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
344 if (r < 0)
345 return r;
346 }
347
348 return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
349 }
350
351 static int path_add_trigger_dependencies(Path *p) {
352 Unit *x;
353 int r;
354
355 assert(p);
356
357 if (UNIT_TRIGGER(UNIT(p)))
358 return 0;
359
360 r = unit_load_related_unit(UNIT(p), ".service", &x);
361 if (r < 0)
362 return r;
363
364 return unit_add_two_dependencies(UNIT(p), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
365 }
366
367 static int path_add_extras(Path *p) {
368 int r;
369
370 assert(p);
371
372 /* To avoid getting pid1 in a busy-loop state (eg: unmet condition on associated service),
373 * set a default trigger limit if the user didn't specify any. */
374 if (p->trigger_limit.interval == USEC_INFINITY)
375 p->trigger_limit.interval = 2 * USEC_PER_SEC;
376
377 if (p->trigger_limit.burst == UINT_MAX)
378 p->trigger_limit.burst = 200;
379
380 r = path_add_trigger_dependencies(p);
381 if (r < 0)
382 return r;
383
384 r = path_add_mount_dependencies(p);
385 if (r < 0)
386 return r;
387
388 return path_add_default_dependencies(p);
389 }
390
391 static int path_load(Unit *u) {
392 Path *p = PATH(u);
393 int r;
394
395 assert(u);
396 assert(u->load_state == UNIT_STUB);
397
398 r = unit_load_fragment_and_dropin(u, true);
399 if (r < 0)
400 return r;
401
402 if (u->load_state != UNIT_LOADED)
403 return 0;
404
405 r = path_add_extras(p);
406 if (r < 0)
407 return r;
408
409 return path_verify(p);
410 }
411
412 static void path_dump(Unit *u, FILE *f, const char *prefix) {
413 Path *p = PATH(u);
414 Unit *trigger;
415
416 assert(p);
417 assert(f);
418
419 trigger = UNIT_TRIGGER(u);
420
421 fprintf(f,
422 "%sPath State: %s\n"
423 "%sResult: %s\n"
424 "%sUnit: %s\n"
425 "%sMakeDirectory: %s\n"
426 "%sDirectoryMode: %04o\n"
427 "%sTriggerLimitIntervalSec: %s\n"
428 "%sTriggerLimitBurst: %u\n",
429 prefix, path_state_to_string(p->state),
430 prefix, path_result_to_string(p->result),
431 prefix, trigger ? trigger->id : "n/a",
432 prefix, yes_no(p->make_directory),
433 prefix, p->directory_mode,
434 prefix, FORMAT_TIMESPAN(p->trigger_limit.interval, USEC_PER_SEC),
435 prefix, p->trigger_limit.burst);
436
437 LIST_FOREACH(spec, s, p->specs)
438 path_spec_dump(s, f, prefix);
439 }
440
441 static void path_unwatch(Path *p) {
442 assert(p);
443
444 LIST_FOREACH(spec, s, p->specs)
445 path_spec_unwatch(s);
446 }
447
448 static int path_watch(Path *p) {
449 int r;
450
451 assert(p);
452
453 LIST_FOREACH(spec, s, p->specs) {
454 r = path_spec_watch(s, path_dispatch_io);
455 if (r < 0)
456 return r;
457 }
458
459 return 0;
460 }
461
462 static void path_set_state(Path *p, PathState state) {
463 PathState old_state;
464 assert(p);
465
466 if (p->state != state)
467 bus_unit_send_pending_change_signal(UNIT(p), false);
468
469 old_state = p->state;
470 p->state = state;
471
472 if (!IN_SET(state, PATH_WAITING, PATH_RUNNING))
473 path_unwatch(p);
474
475 if (state != old_state)
476 log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
477
478 unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], 0);
479 }
480
481 static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify);
482
483 static int path_coldplug(Unit *u) {
484 Path *p = PATH(u);
485
486 assert(p);
487 assert(p->state == PATH_DEAD);
488
489 if (p->deserialized_state != p->state) {
490
491 if (IN_SET(p->deserialized_state, PATH_WAITING, PATH_RUNNING))
492 path_enter_waiting(p, true, false);
493 else
494 path_set_state(p, p->deserialized_state);
495 }
496
497 return 0;
498 }
499
500 static void path_enter_dead(Path *p, PathResult f) {
501 assert(p);
502
503 if (p->result == PATH_SUCCESS)
504 p->result = f;
505
506 unit_log_result(UNIT(p), p->result == PATH_SUCCESS, path_result_to_string(p->result));
507 path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
508 }
509
510 static void path_enter_running(Path *p, char *trigger_path) {
511 _cleanup_(activation_details_unrefp) ActivationDetails *details = NULL;
512 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
513 Unit *trigger;
514 Job *job;
515 int r;
516
517 assert(p);
518
519 /* Don't start job if we are supposed to go down */
520 if (unit_stop_pending(UNIT(p)))
521 return;
522
523 if (!ratelimit_below(&p->trigger_limit)) {
524 log_unit_warning(UNIT(p), "Trigger limit hit, refusing further activation.");
525 path_enter_dead(p, PATH_FAILURE_TRIGGER_LIMIT_HIT);
526 return;
527 }
528
529 trigger = UNIT_TRIGGER(UNIT(p));
530 if (!trigger) {
531 log_unit_error(UNIT(p), "Unit to trigger vanished.");
532 path_enter_dead(p, PATH_FAILURE_RESOURCES);
533 return;
534 }
535
536 details = activation_details_new(UNIT(p));
537 if (!details) {
538 r = -ENOMEM;
539 goto fail;
540 }
541
542 r = free_and_strdup(&(ACTIVATION_DETAILS_PATH(details))->trigger_path_filename, trigger_path);
543 if (r < 0)
544 goto fail;
545
546 r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, &job);
547 if (r < 0)
548 goto fail;
549
550 job_set_activation_details(job, details);
551
552 path_set_state(p, PATH_RUNNING);
553 path_unwatch(p);
554
555 return;
556
557 fail:
558 log_unit_warning(UNIT(p), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
559 path_enter_dead(p, PATH_FAILURE_RESOURCES);
560 }
561
562 static bool path_check_good(Path *p, bool initial, bool from_trigger_notify, char **ret_trigger_path) {
563 assert(p);
564 assert(ret_trigger_path);
565
566 LIST_FOREACH(spec, s, p->specs)
567 if (path_spec_check_good(s, initial, from_trigger_notify, ret_trigger_path))
568 return true;
569
570 return false;
571 }
572
573 static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify) {
574 _cleanup_free_ char *trigger_path = NULL;
575 Unit *trigger;
576 int r;
577
578 /* If the triggered unit is already running, so are we */
579 trigger = UNIT_TRIGGER(UNIT(p));
580 if (trigger && !UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(trigger))) {
581 path_set_state(p, PATH_RUNNING);
582 path_unwatch(p);
583 return;
584 }
585
586 if (path_check_good(p, initial, from_trigger_notify, &trigger_path)) {
587 log_unit_debug(UNIT(p), "Got triggered.");
588 path_enter_running(p, trigger_path);
589 return;
590 }
591
592 r = path_watch(p);
593 if (r < 0)
594 goto fail;
595
596 /* Hmm, so now we have created inotify watches, but the file
597 * might have appeared/been removed by now, so we must
598 * recheck */
599
600 if (path_check_good(p, false, from_trigger_notify, &trigger_path)) {
601 log_unit_debug(UNIT(p), "Got triggered.");
602 path_enter_running(p, trigger_path);
603 return;
604 }
605
606 path_set_state(p, PATH_WAITING);
607 return;
608
609 fail:
610 log_unit_warning_errno(UNIT(p), r, "Failed to enter waiting state: %m");
611 path_enter_dead(p, PATH_FAILURE_RESOURCES);
612 }
613
614 static void path_mkdir(Path *p) {
615 assert(p);
616
617 if (!p->make_directory)
618 return;
619
620 LIST_FOREACH(spec, s, p->specs)
621 path_spec_mkdir(s, p->directory_mode);
622 }
623
624 static int path_start(Unit *u) {
625 Path *p = PATH(u);
626 int r;
627
628 assert(p);
629 assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED));
630
631 r = unit_test_trigger_loaded(u);
632 if (r < 0)
633 return r;
634
635 r = unit_acquire_invocation_id(u);
636 if (r < 0)
637 return r;
638
639 path_mkdir(p);
640
641 p->result = PATH_SUCCESS;
642 path_enter_waiting(p, true, false);
643
644 return 1;
645 }
646
647 static int path_stop(Unit *u) {
648 Path *p = PATH(u);
649
650 assert(p);
651 assert(IN_SET(p->state, PATH_WAITING, PATH_RUNNING));
652
653 path_enter_dead(p, PATH_SUCCESS);
654 return 1;
655 }
656
657 static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
658 Path *p = PATH(u);
659
660 assert(u);
661 assert(f);
662 assert(fds);
663
664 (void) serialize_item(f, "state", path_state_to_string(p->state));
665 (void) serialize_item(f, "result", path_result_to_string(p->result));
666
667 LIST_FOREACH(spec, s, p->specs) {
668 const char *type;
669 _cleanup_free_ char *escaped = NULL;
670
671 escaped = cescape(s->path);
672 if (!escaped)
673 return log_oom();
674
675 assert_se(type = path_type_to_string(s->type));
676 (void) serialize_item_format(f, "path-spec", "%s %i %s",
677 type,
678 s->previous_exists,
679 escaped);
680 }
681
682 return 0;
683 }
684
685 static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
686 Path *p = PATH(u);
687
688 assert(u);
689 assert(key);
690 assert(value);
691 assert(fds);
692
693 if (streq(key, "state")) {
694 PathState state;
695
696 state = path_state_from_string(value);
697 if (state < 0)
698 log_unit_debug(u, "Failed to parse state value: %s", value);
699 else
700 p->deserialized_state = state;
701
702 } else if (streq(key, "result")) {
703 PathResult f;
704
705 f = path_result_from_string(value);
706 if (f < 0)
707 log_unit_debug(u, "Failed to parse result value: %s", value);
708 else if (f != PATH_SUCCESS)
709 p->result = f;
710
711 } else if (streq(key, "path-spec")) {
712 int previous_exists, skip = 0;
713 _cleanup_free_ char *type_str = NULL;
714
715 if (sscanf(value, "%ms %i %n", &type_str, &previous_exists, &skip) < 2)
716 log_unit_debug(u, "Failed to parse path-spec value: %s", value);
717 else {
718 _cleanup_free_ char *unescaped = NULL;
719 ssize_t l;
720 PathType type;
721
722 type = path_type_from_string(type_str);
723 if (type < 0) {
724 log_unit_warning(u, "Unknown path type \"%s\", ignoring.", type_str);
725 return 0;
726 }
727
728 l = cunescape(value+skip, 0, &unescaped);
729 if (l < 0) {
730 log_unit_warning_errno(u, l, "Failed to unescape serialize path: %m");
731 return 0;
732 }
733
734 LIST_FOREACH(spec, s, p->specs)
735 if (s->type == type &&
736 path_equal(s->path, unescaped)) {
737
738 s->previous_exists = previous_exists;
739 break;
740 }
741 }
742
743 } else
744 log_unit_debug(u, "Unknown serialization key: %s", key);
745
746 return 0;
747 }
748
749 _pure_ static UnitActiveState path_active_state(Unit *u) {
750 assert(u);
751
752 return state_translation_table[PATH(u)->state];
753 }
754
755 _pure_ static const char *path_sub_state_to_string(Unit *u) {
756 assert(u);
757
758 return path_state_to_string(PATH(u)->state);
759 }
760
761 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
762 PathSpec *s = userdata, *found = NULL;
763 Path *p;
764 int changed;
765
766 assert(s);
767 assert(s->unit);
768 assert(fd >= 0);
769
770 p = PATH(s->unit);
771
772 if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
773 return 0;
774
775 LIST_FOREACH(spec, i, p->specs)
776 if (path_spec_owns_inotify_fd(i, fd)) {
777 found = i;
778 break;
779 }
780
781 if (!found) {
782 log_error("Got event on unknown fd.");
783 goto fail;
784 }
785
786 changed = path_spec_fd_event(found, revents);
787 if (changed < 0)
788 goto fail;
789
790 if (changed)
791 path_enter_running(p, found->path);
792 else
793 path_enter_waiting(p, false, false);
794
795 return 0;
796
797 fail:
798 path_enter_dead(p, PATH_FAILURE_RESOURCES);
799 return 0;
800 }
801
802 static void path_trigger_notify(Unit *u, Unit *other) {
803 Path *p = PATH(u);
804
805 assert(u);
806 assert(other);
807
808 /* Invoked whenever the unit we trigger changes state or gains or loses a job */
809
810 /* Filter out invocations with bogus state */
811 assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
812
813 /* Don't propagate state changes from the triggered unit if we are already down */
814 if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
815 return;
816
817 /* Propagate start limit hit state */
818 if (other->start_limit_hit) {
819 path_enter_dead(p, PATH_FAILURE_UNIT_START_LIMIT_HIT);
820 return;
821 }
822
823 /* Don't propagate anything if there's still a job queued */
824 if (other->job)
825 return;
826
827 if (p->state == PATH_RUNNING &&
828 UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
829 log_unit_debug(UNIT(p), "Got notified about unit deactivation.");
830 path_enter_waiting(p, false, true);
831 } else if (p->state == PATH_WAITING &&
832 !UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
833 log_unit_debug(UNIT(p), "Got notified about unit activation.");
834 path_enter_waiting(p, false, true);
835 }
836 }
837
838 static void path_reset_failed(Unit *u) {
839 Path *p = PATH(u);
840
841 assert(p);
842
843 if (p->state == PATH_FAILED)
844 path_set_state(p, PATH_DEAD);
845
846 p->result = PATH_SUCCESS;
847 }
848
849 static int path_can_start(Unit *u) {
850 Path *p = PATH(u);
851 int r;
852
853 assert(p);
854
855 r = unit_test_start_limit(u);
856 if (r < 0) {
857 path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
858 return r;
859 }
860
861 return 1;
862 }
863
864 static void activation_details_path_done(ActivationDetails *details) {
865 ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
866
867 p->trigger_path_filename = mfree(p->trigger_path_filename);
868 }
869
870 static void activation_details_path_serialize(ActivationDetails *details, FILE *f) {
871 ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
872
873 assert(f);
874
875 if (p->trigger_path_filename)
876 (void) serialize_item(f, "activation-details-path-filename", p->trigger_path_filename);
877 }
878
879 static int activation_details_path_deserialize(const char *key, const char *value, ActivationDetails **details) {
880 int r;
881
882 assert(key);
883 assert(value);
884
885 if (!details || !*details)
886 return -EINVAL;
887
888 ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(*details);
889 if (!p)
890 return -EINVAL;
891
892 if (!streq(key, "activation-details-path-filename"))
893 return -EINVAL;
894
895 r = free_and_strdup(&p->trigger_path_filename, value);
896 if (r < 0)
897 return r;
898
899 return 0;
900 }
901
902 static int activation_details_path_append_env(ActivationDetails *details, char ***strv) {
903 ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
904 char *s;
905 int r;
906
907 assert(details);
908 assert(strv);
909 assert(p);
910
911 if (isempty(p->trigger_path_filename))
912 return 0;
913
914 s = strjoin("TRIGGER_PATH=", p->trigger_path_filename);
915 if (!s)
916 return -ENOMEM;
917
918 r = strv_consume(strv, TAKE_PTR(s));
919 if (r < 0)
920 return r;
921
922 return 1; /* Return the number of variables added to the env block */
923 }
924
925 static int activation_details_path_append_pair(ActivationDetails *details, char ***strv) {
926 ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
927 int r;
928
929 assert(details);
930 assert(strv);
931 assert(p);
932
933 if (isempty(p->trigger_path_filename))
934 return 0;
935
936 r = strv_extend(strv, "trigger_path");
937 if (r < 0)
938 return r;
939
940 r = strv_extend(strv, p->trigger_path_filename);
941 if (r < 0)
942 return r;
943
944 return 1; /* Return the number of pairs added to the env block */
945 }
946
947 static const char* const path_type_table[_PATH_TYPE_MAX] = {
948 [PATH_EXISTS] = "PathExists",
949 [PATH_EXISTS_GLOB] = "PathExistsGlob",
950 [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
951 [PATH_CHANGED] = "PathChanged",
952 [PATH_MODIFIED] = "PathModified",
953 };
954
955 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
956
957 static const char* const path_result_table[_PATH_RESULT_MAX] = {
958 [PATH_SUCCESS] = "success",
959 [PATH_FAILURE_RESOURCES] = "resources",
960 [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
961 [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
962 [PATH_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
963 };
964
965 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
966
967 const UnitVTable path_vtable = {
968 .object_size = sizeof(Path),
969
970 .sections =
971 "Unit\0"
972 "Path\0"
973 "Install\0",
974 .private_section = "Path",
975
976 .can_transient = true,
977 .can_fail = true,
978 .can_trigger = true,
979
980 .init = path_init,
981 .done = path_done,
982 .load = path_load,
983
984 .coldplug = path_coldplug,
985
986 .dump = path_dump,
987
988 .start = path_start,
989 .stop = path_stop,
990
991 .serialize = path_serialize,
992 .deserialize_item = path_deserialize_item,
993
994 .active_state = path_active_state,
995 .sub_state_to_string = path_sub_state_to_string,
996
997 .trigger_notify = path_trigger_notify,
998
999 .reset_failed = path_reset_failed,
1000
1001 .bus_set_property = bus_path_set_property,
1002
1003 .can_start = path_can_start,
1004 };
1005
1006 const ActivationDetailsVTable activation_details_path_vtable = {
1007 .object_size = sizeof(ActivationDetailsPath),
1008
1009 .done = activation_details_path_done,
1010 .serialize = activation_details_path_serialize,
1011 .deserialize = activation_details_path_deserialize,
1012 .append_env = activation_details_path_append_env,
1013 .append_pair = activation_details_path_append_pair,
1014 };