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