]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/path.c
units: for all unit settings that take lists, allow the empty string for resetting...
[thirdparty/systemd.git] / src / core / path.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
01f78473
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
01f78473
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
01f78473 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
01f78473
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/inotify.h>
23#include <sys/epoll.h>
24#include <sys/ioctl.h>
25#include <errno.h>
26#include <unistd.h>
27
28#include "unit.h"
29#include "unit-name.h"
30#include "path.h"
49e942b2 31#include "mkdir.h"
01f78473 32#include "dbus-path.h"
a40eb732 33#include "special.h"
398ef8ba 34#include "bus-errors.h"
9eb977db 35#include "path-util.h"
01f78473
LP
36
37static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
38 [PATH_DEAD] = UNIT_INACTIVE,
39 [PATH_WAITING] = UNIT_ACTIVE,
40 [PATH_RUNNING] = UNIT_ACTIVE,
fdf20a31 41 [PATH_FAILED] = UNIT_FAILED
01f78473
LP
42};
43
57020a3a
LP
44int path_spec_watch(PathSpec *s, Unit *u) {
45
4b562198
MS
46 static const int flags_table[_PATH_TYPE_MAX] = {
47 [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
48 [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
49 [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
e9223856 50 [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,
4b562198
MS
51 [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
52 };
53
54 bool exists = false;
55 char *k, *slash;
56 int r;
0e456f97
LP
57
58 assert(u);
4b562198 59 assert(s);
0e456f97 60
57020a3a 61 path_spec_unwatch(s, u);
4b562198
MS
62
63 if (!(k = strdup(s->path)))
64 return -ENOMEM;
65
66 if ((s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC)) < 0) {
67 r = -errno;
68 goto fail;
69 }
70
71 if (unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch) < 0) {
72 r = -errno;
73 goto fail;
74 }
75
7ceba241
LP
76 s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type]);
77 if (s->primary_wd >= 0)
4b562198
MS
78 exists = true;
79
80 do {
81 int flags;
82
83 /* This assumes the path was passed through path_kill_slashes()! */
7ceba241
LP
84 slash = strrchr(k, '/');
85 if (!slash)
4b562198
MS
86 break;
87
88 /* Trim the path at the last slash. Keep the slash if it's the root dir. */
89 slash[slash == k] = 0;
90
91 flags = IN_MOVE_SELF;
92 if (!exists)
93 flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
94
95 if (inotify_add_watch(s->inotify_fd, k, flags) >= 0)
96 exists = true;
97 } while (slash != k);
98
99 return 0;
100
101fail:
102 free(k);
103
57020a3a 104 path_spec_unwatch(s, u);
4b562198 105 return r;
0e456f97
LP
106}
107
57020a3a 108void path_spec_unwatch(PathSpec *s, Unit *u) {
62347bc2
LP
109
110 if (s->inotify_fd < 0)
111 return;
112
4b562198 113 unit_unwatch_fd(u, &s->watch);
62347bc2
LP
114
115 close_nointr_nofail(s->inotify_fd);
116 s->inotify_fd = -1;
117}
118
57020a3a 119int path_spec_fd_event(PathSpec *s, uint32_t events) {
4b562198
MS
120 uint8_t *buf = NULL;
121 struct inotify_event *e;
122 ssize_t k;
123 int l;
124 int r = 0;
125
126 if (events != EPOLLIN) {
15f55e80 127 log_error("Got invalid poll event on inotify.");
4b562198
MS
128 r = -EINVAL;
129 goto out;
130 }
131
132 if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) {
133 log_error("FIONREAD failed: %m");
134 r = -errno;
135 goto out;
136 }
137
138 assert(l > 0);
139
15f55e80
ZJS
140 buf = malloc(l);
141 if (!buf) {
4b562198
MS
142 log_error("Failed to allocate buffer: %m");
143 r = -errno;
144 goto out;
145 }
146
15f55e80
ZJS
147 k = read(s->inotify_fd, buf, l);
148 if (k < 0) {
4b562198
MS
149 log_error("Failed to read inotify event: %m");
150 r = -errno;
151 goto out;
152 }
153
154 e = (struct inotify_event*) buf;
155
156 while (k > 0) {
157 size_t step;
158
714d943f
MS
159 if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
160 s->primary_wd == e->wd)
4b562198
MS
161 r = 1;
162
163 step = sizeof(struct inotify_event) + e->len;
164 assert(step <= (size_t) k);
165
166 e = (struct inotify_event*) ((uint8_t*) e + step);
167 k -= step;
168 }
169out:
170 free(buf);
171 return r;
172}
173
57020a3a 174static bool path_spec_check_good(PathSpec *s, bool initial) {
4b562198
MS
175 bool good = false;
176
177 switch (s->type) {
178
179 case PATH_EXISTS:
180 good = access(s->path, F_OK) >= 0;
181 break;
182
183 case PATH_EXISTS_GLOB:
184 good = glob_exists(s->path) > 0;
185 break;
186
187 case PATH_DIRECTORY_NOT_EMPTY: {
188 int k;
189
190 k = dir_is_empty(s->path);
191 good = !(k == -ENOENT || k > 0);
192 break;
193 }
194
714d943f
MS
195 case PATH_CHANGED:
196 case PATH_MODIFIED: {
4b562198
MS
197 bool b;
198
199 b = access(s->path, F_OK) >= 0;
200 good = !initial && b != s->previous_exists;
201 s->previous_exists = b;
202 break;
203 }
204
205 default:
206 ;
207 }
208
209 return good;
210}
211
57020a3a 212static bool path_spec_startswith(PathSpec *s, const char *what) {
4b562198
MS
213 return path_startswith(s->path, what);
214}
215
57020a3a 216static void path_spec_mkdir(PathSpec *s, mode_t mode) {
4b562198
MS
217 int r;
218
219 if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
220 return;
221
15f55e80
ZJS
222 r = mkdir_p_label(s->path, mode);
223 if (r < 0)
4b562198
MS
224 log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
225}
226
57020a3a 227static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
4b562198
MS
228 fprintf(f,
229 "%s%s: %s\n",
230 prefix,
231 path_type_to_string(s->type),
232 s->path);
233}
234
57020a3a
LP
235void path_spec_done(PathSpec *s) {
236 assert(s);
4b562198 237 assert(s->inotify_fd == -1);
57020a3a 238
4b562198
MS
239 free(s->path);
240}
241
242static void path_init(Unit *u) {
243 Path *p = PATH(u);
244
245 assert(u);
ac155bb8 246 assert(u->load_state == UNIT_STUB);
4b562198
MS
247
248 p->directory_mode = 0755;
249}
250
74051b9b 251void path_free_specs(Path *p) {
01f78473
LP
252 PathSpec *s;
253
254 assert(p);
255
256 while ((s = p->specs)) {
74051b9b 257 path_spec_unwatch(s, UNIT(p));
01f78473 258 LIST_REMOVE(PathSpec, spec, p->specs, s);
57020a3a 259 path_spec_done(s);
01f78473
LP
260 free(s);
261 }
262}
263
74051b9b
LP
264static void path_done(Unit *u) {
265 Path *p = PATH(u);
266
267 assert(p);
268
269 unit_ref_unset(&p->unit);
270 path_free_specs(p);
271}
272
01f78473
LP
273int path_add_one_mount_link(Path *p, Mount *m) {
274 PathSpec *s;
275 int r;
276
277 assert(p);
278 assert(m);
279
1124fe6f
MS
280 if (UNIT(p)->load_state != UNIT_LOADED ||
281 UNIT(m)->load_state != UNIT_LOADED)
01f78473
LP
282 return 0;
283
284 LIST_FOREACH(spec, s, p->specs) {
285
57020a3a 286 if (!path_spec_startswith(s, m->where))
01f78473
LP
287 continue;
288
2c966c03 289 if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
01f78473
LP
290 return r;
291 }
292
293 return 0;
294}
295
296static int path_add_mount_links(Path *p) {
ac155bb8 297 Unit *other;
01f78473
LP
298 int r;
299
300 assert(p);
301
1124fe6f 302 LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT])
595ed347 303 if ((r = path_add_one_mount_link(p, MOUNT(other))) < 0)
01f78473
LP
304 return r;
305
306 return 0;
307}
308
309static int path_verify(Path *p) {
310 assert(p);
311
1124fe6f 312 if (UNIT(p)->load_state != UNIT_LOADED)
01f78473
LP
313 return 0;
314
315 if (!p->specs) {
66870f90
ZJS
316 log_error_unit(UNIT(p)->id,
317 "%s lacks path setting. Refusing.", UNIT(p)->id);
01f78473
LP
318 return -EINVAL;
319 }
320
321 return 0;
322}
323
6c155fe3
LP
324static int path_add_default_dependencies(Path *p) {
325 int r;
326
327 assert(p);
328
67445f4e 329 if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
2a77d31d
LP
330 if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
331 return r;
332
6c155fe3
LP
333 if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
334 return r;
2a77d31d 335 }
6c155fe3 336
ead8e478 337 return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
6c155fe3
LP
338}
339
01f78473
LP
340static int path_load(Unit *u) {
341 Path *p = PATH(u);
342 int r;
343
344 assert(u);
ac155bb8 345 assert(u->load_state == UNIT_STUB);
01f78473
LP
346
347 if ((r = unit_load_fragment_and_dropin(u)) < 0)
348 return r;
349
ac155bb8 350 if (u->load_state == UNIT_LOADED) {
01f78473 351
57020a3a
LP
352 if (!UNIT_DEREF(p->unit)) {
353 Unit *x;
354
355 r = unit_load_related_unit(u, ".service", &x);
356 if (r < 0)
01f78473
LP
357 return r;
358
57020a3a
LP
359 unit_ref_set(&p->unit, x);
360 }
361
362 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
363 if (r < 0)
01f78473
LP
364 return r;
365
366 if ((r = path_add_mount_links(p)) < 0)
367 return r;
a40eb732 368
1124fe6f 369 if (UNIT(p)->default_dependencies)
6c155fe3 370 if ((r = path_add_default_dependencies(p)) < 0)
a40eb732 371 return r;
01f78473
LP
372 }
373
374 return path_verify(p);
375}
376
377static void path_dump(Unit *u, FILE *f, const char *prefix) {
378 Path *p = PATH(u);
01f78473
LP
379 PathSpec *s;
380
e364ad06
LP
381 assert(p);
382 assert(f);
01f78473
LP
383
384 fprintf(f,
385 "%sPath State: %s\n"
cd43ca73 386 "%sResult: %s\n"
0e456f97
LP
387 "%sUnit: %s\n"
388 "%sMakeDirectory: %s\n"
389 "%sDirectoryMode: %04o\n",
01f78473 390 prefix, path_state_to_string(p->state),
cd43ca73 391 prefix, path_result_to_string(p->result),
ac155bb8 392 prefix, UNIT_DEREF(p->unit)->id,
0e456f97
LP
393 prefix, yes_no(p->make_directory),
394 prefix, p->directory_mode);
01f78473
LP
395
396 LIST_FOREACH(spec, s, p->specs)
57020a3a 397 path_spec_dump(s, f, prefix);
01f78473
LP
398}
399
400static void path_unwatch(Path *p) {
401 PathSpec *s;
402
403 assert(p);
404
405 LIST_FOREACH(spec, s, p->specs)
57020a3a 406 path_spec_unwatch(s, UNIT(p));
01f78473
LP
407}
408
409static int path_watch(Path *p) {
410 int r;
411 PathSpec *s;
412
413 assert(p);
414
415 LIST_FOREACH(spec, s, p->specs)
57020a3a 416 if ((r = path_spec_watch(s, UNIT(p))) < 0)
01f78473
LP
417 return r;
418
419 return 0;
420}
421
422static void path_set_state(Path *p, PathState state) {
423 PathState old_state;
424 assert(p);
425
426 old_state = p->state;
427 p->state = state;
428
672028dc
LP
429 if (state != PATH_WAITING &&
430 (state != PATH_RUNNING || p->inotify_triggered))
01f78473
LP
431 path_unwatch(p);
432
433 if (state != old_state)
434 log_debug("%s changed %s -> %s",
1124fe6f 435 UNIT(p)->id,
01f78473
LP
436 path_state_to_string(old_state),
437 path_state_to_string(state));
438
e2f3b44c 439 unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
01f78473
LP
440}
441
ac3f50ca 442static void path_enter_waiting(Path *p, bool initial, bool recheck);
01f78473
LP
443
444static int path_coldplug(Unit *u) {
445 Path *p = PATH(u);
446
447 assert(p);
448 assert(p->state == PATH_DEAD);
449
450 if (p->deserialized_state != p->state) {
451
452 if (p->deserialized_state == PATH_WAITING ||
453 p->deserialized_state == PATH_RUNNING)
ac3f50ca 454 path_enter_waiting(p, true, true);
01f78473
LP
455 else
456 path_set_state(p, p->deserialized_state);
457 }
458
459 return 0;
460}
461
cd43ca73 462static void path_enter_dead(Path *p, PathResult f) {
01f78473
LP
463 assert(p);
464
cd43ca73
LP
465 if (f != PATH_SUCCESS)
466 p->result = f;
01f78473 467
cd43ca73 468 path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
01f78473
LP
469}
470
471static void path_enter_running(Path *p) {
472 int r;
398ef8ba
LP
473 DBusError error;
474
01f78473 475 assert(p);
398ef8ba 476 dbus_error_init(&error);
01f78473 477
ba3e67a7 478 /* Don't start job if we are supposed to go down */
1124fe6f 479 if (UNIT(p)->job && UNIT(p)->job->type == JOB_STOP)
ba3e67a7
LP
480 return;
481
1124fe6f 482 if ((r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
01f78473
LP
483 goto fail;
484
672028dc
LP
485 p->inotify_triggered = false;
486
487 if ((r = path_watch(p)) < 0)
488 goto fail;
489
01f78473
LP
490 path_set_state(p, PATH_RUNNING);
491 return;
492
493fail:
1124fe6f 494 log_warning("%s failed to queue unit startup job: %s", UNIT(p)->id, bus_error(&error, r));
cd43ca73 495 path_enter_dead(p, PATH_FAILURE_RESOURCES);
398ef8ba
LP
496
497 dbus_error_free(&error);
01f78473
LP
498}
499
ac3f50ca 500static bool path_check_good(Path *p, bool initial) {
01f78473 501 PathSpec *s;
01f78473
LP
502 bool good = false;
503
ac3f50ca 504 assert(p);
672028dc 505
01f78473 506 LIST_FOREACH(spec, s, p->specs) {
57020a3a 507 good = path_spec_check_good(s, initial);
01f78473
LP
508
509 if (good)
510 break;
511 }
512
ac3f50ca
LP
513 return good;
514}
01f78473 515
ac3f50ca
LP
516static void path_enter_waiting(Path *p, bool initial, bool recheck) {
517 int r;
0595f9a1 518
ac3f50ca
LP
519 if (recheck)
520 if (path_check_good(p, initial)) {
1124fe6f 521 log_debug("%s got triggered.", UNIT(p)->id);
ac3f50ca
LP
522 path_enter_running(p);
523 return;
524 }
525
526 if ((r = path_watch(p)) < 0)
527 goto fail;
528
529 /* Hmm, so now we have created inotify watches, but the file
530 * might have appeared/been removed by now, so we must
531 * recheck */
532
533 if (recheck)
534 if (path_check_good(p, false)) {
1124fe6f 535 log_debug("%s got triggered.", UNIT(p)->id);
ac3f50ca
LP
536 path_enter_running(p);
537 return;
538 }
01f78473
LP
539
540 path_set_state(p, PATH_WAITING);
541 return;
542
543fail:
1124fe6f 544 log_warning("%s failed to enter waiting state: %s", UNIT(p)->id, strerror(-r));
cd43ca73 545 path_enter_dead(p, PATH_FAILURE_RESOURCES);
01f78473
LP
546}
547
0e456f97
LP
548static void path_mkdir(Path *p) {
549 PathSpec *s;
550
551 assert(p);
552
553 if (!p->make_directory)
554 return;
555
4b562198 556 LIST_FOREACH(spec, s, p->specs)
57020a3a 557 path_spec_mkdir(s, p->directory_mode);
0e456f97
LP
558}
559
01f78473
LP
560static int path_start(Unit *u) {
561 Path *p = PATH(u);
562
563 assert(p);
fdf20a31 564 assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
01f78473 565
ac155bb8 566 if (UNIT_DEREF(p->unit)->load_state != UNIT_LOADED)
01f78473
LP
567 return -ENOENT;
568
0e456f97
LP
569 path_mkdir(p);
570
cd43ca73 571 p->result = PATH_SUCCESS;
ac3f50ca 572 path_enter_waiting(p, true, true);
00dc5d76 573
01f78473
LP
574 return 0;
575}
576
577static int path_stop(Unit *u) {
578 Path *p = PATH(u);
579
580 assert(p);
581 assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
582
cd43ca73 583 path_enter_dead(p, PATH_SUCCESS);
01f78473
LP
584 return 0;
585}
586
587static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
588 Path *p = PATH(u);
589
590 assert(u);
591 assert(f);
592 assert(fds);
593
594 unit_serialize_item(u, f, "state", path_state_to_string(p->state));
cd43ca73 595 unit_serialize_item(u, f, "result", path_result_to_string(p->result));
01f78473
LP
596
597 return 0;
598}
599
600static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
601 Path *p = PATH(u);
602
603 assert(u);
604 assert(key);
605 assert(value);
606 assert(fds);
607
608 if (streq(key, "state")) {
609 PathState state;
610
611 if ((state = path_state_from_string(value)) < 0)
612 log_debug("Failed to parse state value %s", value);
613 else
614 p->deserialized_state = state;
cd43ca73
LP
615
616 } else if (streq(key, "result")) {
617 PathResult f;
618
619 f = path_result_from_string(value);
620 if (f < 0)
621 log_debug("Failed to parse result value %s", value);
622 else if (f != PATH_SUCCESS)
623 p->result = f;
624
01f78473
LP
625 } else
626 log_debug("Unknown serialization key '%s'", key);
627
628 return 0;
629}
630
631static UnitActiveState path_active_state(Unit *u) {
632 assert(u);
633
634 return state_translation_table[PATH(u)->state];
635}
636
637static const char *path_sub_state_to_string(Unit *u) {
638 assert(u);
639
640 return path_state_to_string(PATH(u)->state);
641}
642
643static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
644 Path *p = PATH(u);
01f78473 645 PathSpec *s;
4b562198 646 int changed;
01f78473
LP
647
648 assert(p);
649 assert(fd >= 0);
650
672028dc
LP
651 if (p->state != PATH_WAITING &&
652 p->state != PATH_RUNNING)
01f78473
LP
653 return;
654
ac155bb8 655 /* log_debug("inotify wakeup on %s.", u->id); */
01f78473 656
01f78473 657 LIST_FOREACH(spec, s, p->specs)
57020a3a 658 if (path_spec_owns_inotify_fd(s, fd))
01f78473
LP
659 break;
660
661 if (!s) {
662 log_error("Got event on unknown fd.");
663 goto fail;
664 }
665
57020a3a 666 changed = path_spec_fd_event(s, events);
4b562198 667 if (changed < 0)
01f78473 668 goto fail;
01f78473 669
672028dc
LP
670 /* If we are already running, then remember that one event was
671 * dispatched so that we restart the service only if something
672 * actually changed on disk */
673 p->inotify_triggered = true;
674
672028dc
LP
675 if (changed)
676 path_enter_running(p);
677 else
ac3f50ca 678 path_enter_waiting(p, false, true);
672028dc 679
01f78473
LP
680 return;
681
682fail:
cd43ca73 683 path_enter_dead(p, PATH_FAILURE_RESOURCES);
01f78473
LP
684}
685
686void path_unit_notify(Unit *u, UnitActiveState new_state) {
01f78473 687 Iterator i;
57020a3a 688 Unit *k;
01f78473 689
ac155bb8 690 if (u->type == UNIT_PATH)
01f78473
LP
691 return;
692
ac155bb8 693 SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
01f78473
LP
694 Path *p;
695
ac155bb8 696 if (k->type != UNIT_PATH)
01f78473
LP
697 continue;
698
ac155bb8 699 if (k->load_state != UNIT_LOADED)
01f78473
LP
700 continue;
701
57020a3a 702 p = PATH(k);
01f78473
LP
703
704 if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
1124fe6f 705 log_debug("%s got notified about unit deactivation.", UNIT(p)->id);
672028dc
LP
706
707 /* Hmm, so inotify was triggered since the
708 * last activation, so I guess we need to
709 * recheck what is going on. */
ac3f50ca 710 path_enter_waiting(p, false, p->inotify_triggered);
01f78473
LP
711 }
712 }
01f78473
LP
713}
714
fdf20a31 715static void path_reset_failed(Unit *u) {
5632e374
LP
716 Path *p = PATH(u);
717
718 assert(p);
719
fdf20a31 720 if (p->state == PATH_FAILED)
5632e374
LP
721 path_set_state(p, PATH_DEAD);
722
cd43ca73 723 p->result = PATH_SUCCESS;
5632e374
LP
724}
725
01f78473
LP
726static const char* const path_state_table[_PATH_STATE_MAX] = {
727 [PATH_DEAD] = "dead",
728 [PATH_WAITING] = "waiting",
729 [PATH_RUNNING] = "running",
fdf20a31 730 [PATH_FAILED] = "failed"
01f78473
LP
731};
732
733DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
734
735static const char* const path_type_table[_PATH_TYPE_MAX] = {
736 [PATH_EXISTS] = "PathExists",
8092a428 737 [PATH_EXISTS_GLOB] = "PathExistsGlob",
01f78473 738 [PATH_CHANGED] = "PathChanged",
e9223856 739 [PATH_MODIFIED] = "PathModified",
01f78473
LP
740 [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty"
741};
742
743DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
744
cd43ca73
LP
745static const char* const path_result_table[_PATH_RESULT_MAX] = {
746 [PATH_SUCCESS] = "success",
747 [PATH_FAILURE_RESOURCES] = "resources"
748};
749
750DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
751
01f78473 752const UnitVTable path_vtable = {
7d17cfbc 753 .object_size = sizeof(Path),
f975e971
LP
754 .sections =
755 "Unit\0"
756 "Path\0"
757 "Install\0",
01f78473 758
0e456f97 759 .init = path_init,
01f78473
LP
760 .done = path_done,
761 .load = path_load,
762
763 .coldplug = path_coldplug,
764
765 .dump = path_dump,
766
767 .start = path_start,
768 .stop = path_stop,
769
770 .serialize = path_serialize,
771 .deserialize_item = path_deserialize_item,
772
773 .active_state = path_active_state,
774 .sub_state_to_string = path_sub_state_to_string,
775
776 .fd_event = path_fd_event,
777
fdf20a31 778 .reset_failed = path_reset_failed,
5632e374 779
c4e2ceae 780 .bus_interface = "org.freedesktop.systemd1.Path",
cd43ca73
LP
781 .bus_message_handler = bus_path_message_handler,
782 .bus_invalidating_properties = bus_path_invalidating_properties
01f78473 783};