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