]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/path.c
journal: new logging macros to include UNIT=
[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
01f78473
LP
251static void path_done(Unit *u) {
252 Path *p = PATH(u);
253 PathSpec *s;
254
255 assert(p);
256
57020a3a
LP
257 unit_ref_unset(&p->unit);
258
01f78473 259 while ((s = p->specs)) {
57020a3a 260 path_spec_unwatch(s, u);
01f78473 261 LIST_REMOVE(PathSpec, spec, p->specs, s);
57020a3a 262 path_spec_done(s);
01f78473
LP
263 free(s);
264 }
265}
266
267int path_add_one_mount_link(Path *p, Mount *m) {
268 PathSpec *s;
269 int r;
270
271 assert(p);
272 assert(m);
273
1124fe6f
MS
274 if (UNIT(p)->load_state != UNIT_LOADED ||
275 UNIT(m)->load_state != UNIT_LOADED)
01f78473
LP
276 return 0;
277
278 LIST_FOREACH(spec, s, p->specs) {
279
57020a3a 280 if (!path_spec_startswith(s, m->where))
01f78473
LP
281 continue;
282
2c966c03 283 if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
01f78473
LP
284 return r;
285 }
286
287 return 0;
288}
289
290static int path_add_mount_links(Path *p) {
ac155bb8 291 Unit *other;
01f78473
LP
292 int r;
293
294 assert(p);
295
1124fe6f 296 LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT])
595ed347 297 if ((r = path_add_one_mount_link(p, MOUNT(other))) < 0)
01f78473
LP
298 return r;
299
300 return 0;
301}
302
303static int path_verify(Path *p) {
304 assert(p);
305
1124fe6f 306 if (UNIT(p)->load_state != UNIT_LOADED)
01f78473
LP
307 return 0;
308
309 if (!p->specs) {
1124fe6f 310 log_error("%s lacks path setting. Refusing.", UNIT(p)->id);
01f78473
LP
311 return -EINVAL;
312 }
313
314 return 0;
315}
316
6c155fe3
LP
317static int path_add_default_dependencies(Path *p) {
318 int r;
319
320 assert(p);
321
67445f4e 322 if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
2a77d31d
LP
323 if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
324 return r;
325
6c155fe3
LP
326 if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
327 return r;
2a77d31d 328 }
6c155fe3 329
ead8e478 330 return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
6c155fe3
LP
331}
332
01f78473
LP
333static int path_load(Unit *u) {
334 Path *p = PATH(u);
335 int r;
336
337 assert(u);
ac155bb8 338 assert(u->load_state == UNIT_STUB);
01f78473
LP
339
340 if ((r = unit_load_fragment_and_dropin(u)) < 0)
341 return r;
342
ac155bb8 343 if (u->load_state == UNIT_LOADED) {
01f78473 344
57020a3a
LP
345 if (!UNIT_DEREF(p->unit)) {
346 Unit *x;
347
348 r = unit_load_related_unit(u, ".service", &x);
349 if (r < 0)
01f78473
LP
350 return r;
351
57020a3a
LP
352 unit_ref_set(&p->unit, x);
353 }
354
355 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
356 if (r < 0)
01f78473
LP
357 return r;
358
359 if ((r = path_add_mount_links(p)) < 0)
360 return r;
a40eb732 361
1124fe6f 362 if (UNIT(p)->default_dependencies)
6c155fe3 363 if ((r = path_add_default_dependencies(p)) < 0)
a40eb732 364 return r;
01f78473
LP
365 }
366
367 return path_verify(p);
368}
369
370static void path_dump(Unit *u, FILE *f, const char *prefix) {
371 Path *p = PATH(u);
01f78473
LP
372 PathSpec *s;
373
e364ad06
LP
374 assert(p);
375 assert(f);
01f78473
LP
376
377 fprintf(f,
378 "%sPath State: %s\n"
cd43ca73 379 "%sResult: %s\n"
0e456f97
LP
380 "%sUnit: %s\n"
381 "%sMakeDirectory: %s\n"
382 "%sDirectoryMode: %04o\n",
01f78473 383 prefix, path_state_to_string(p->state),
cd43ca73 384 prefix, path_result_to_string(p->result),
ac155bb8 385 prefix, UNIT_DEREF(p->unit)->id,
0e456f97
LP
386 prefix, yes_no(p->make_directory),
387 prefix, p->directory_mode);
01f78473
LP
388
389 LIST_FOREACH(spec, s, p->specs)
57020a3a 390 path_spec_dump(s, f, prefix);
01f78473
LP
391}
392
393static void path_unwatch(Path *p) {
394 PathSpec *s;
395
396 assert(p);
397
398 LIST_FOREACH(spec, s, p->specs)
57020a3a 399 path_spec_unwatch(s, UNIT(p));
01f78473
LP
400}
401
402static int path_watch(Path *p) {
403 int r;
404 PathSpec *s;
405
406 assert(p);
407
408 LIST_FOREACH(spec, s, p->specs)
57020a3a 409 if ((r = path_spec_watch(s, UNIT(p))) < 0)
01f78473
LP
410 return r;
411
412 return 0;
413}
414
415static void path_set_state(Path *p, PathState state) {
416 PathState old_state;
417 assert(p);
418
419 old_state = p->state;
420 p->state = state;
421
672028dc
LP
422 if (state != PATH_WAITING &&
423 (state != PATH_RUNNING || p->inotify_triggered))
01f78473
LP
424 path_unwatch(p);
425
426 if (state != old_state)
427 log_debug("%s changed %s -> %s",
1124fe6f 428 UNIT(p)->id,
01f78473
LP
429 path_state_to_string(old_state),
430 path_state_to_string(state));
431
e2f3b44c 432 unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
01f78473
LP
433}
434
ac3f50ca 435static void path_enter_waiting(Path *p, bool initial, bool recheck);
01f78473
LP
436
437static int path_coldplug(Unit *u) {
438 Path *p = PATH(u);
439
440 assert(p);
441 assert(p->state == PATH_DEAD);
442
443 if (p->deserialized_state != p->state) {
444
445 if (p->deserialized_state == PATH_WAITING ||
446 p->deserialized_state == PATH_RUNNING)
ac3f50ca 447 path_enter_waiting(p, true, true);
01f78473
LP
448 else
449 path_set_state(p, p->deserialized_state);
450 }
451
452 return 0;
453}
454
cd43ca73 455static void path_enter_dead(Path *p, PathResult f) {
01f78473
LP
456 assert(p);
457
cd43ca73
LP
458 if (f != PATH_SUCCESS)
459 p->result = f;
01f78473 460
cd43ca73 461 path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
01f78473
LP
462}
463
464static void path_enter_running(Path *p) {
465 int r;
398ef8ba
LP
466 DBusError error;
467
01f78473 468 assert(p);
398ef8ba 469 dbus_error_init(&error);
01f78473 470
ba3e67a7 471 /* Don't start job if we are supposed to go down */
1124fe6f 472 if (UNIT(p)->job && UNIT(p)->job->type == JOB_STOP)
ba3e67a7
LP
473 return;
474
1124fe6f 475 if ((r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
01f78473
LP
476 goto fail;
477
672028dc
LP
478 p->inotify_triggered = false;
479
480 if ((r = path_watch(p)) < 0)
481 goto fail;
482
01f78473
LP
483 path_set_state(p, PATH_RUNNING);
484 return;
485
486fail:
1124fe6f 487 log_warning("%s failed to queue unit startup job: %s", UNIT(p)->id, bus_error(&error, r));
cd43ca73 488 path_enter_dead(p, PATH_FAILURE_RESOURCES);
398ef8ba
LP
489
490 dbus_error_free(&error);
01f78473
LP
491}
492
ac3f50ca 493static bool path_check_good(Path *p, bool initial) {
01f78473 494 PathSpec *s;
01f78473
LP
495 bool good = false;
496
ac3f50ca 497 assert(p);
672028dc 498
01f78473 499 LIST_FOREACH(spec, s, p->specs) {
57020a3a 500 good = path_spec_check_good(s, initial);
01f78473
LP
501
502 if (good)
503 break;
504 }
505
ac3f50ca
LP
506 return good;
507}
01f78473 508
ac3f50ca
LP
509static void path_enter_waiting(Path *p, bool initial, bool recheck) {
510 int r;
0595f9a1 511
ac3f50ca
LP
512 if (recheck)
513 if (path_check_good(p, initial)) {
1124fe6f 514 log_debug("%s got triggered.", UNIT(p)->id);
ac3f50ca
LP
515 path_enter_running(p);
516 return;
517 }
518
519 if ((r = path_watch(p)) < 0)
520 goto fail;
521
522 /* Hmm, so now we have created inotify watches, but the file
523 * might have appeared/been removed by now, so we must
524 * recheck */
525
526 if (recheck)
527 if (path_check_good(p, false)) {
1124fe6f 528 log_debug("%s got triggered.", UNIT(p)->id);
ac3f50ca
LP
529 path_enter_running(p);
530 return;
531 }
01f78473
LP
532
533 path_set_state(p, PATH_WAITING);
534 return;
535
536fail:
1124fe6f 537 log_warning("%s failed to enter waiting state: %s", UNIT(p)->id, strerror(-r));
cd43ca73 538 path_enter_dead(p, PATH_FAILURE_RESOURCES);
01f78473
LP
539}
540
0e456f97
LP
541static void path_mkdir(Path *p) {
542 PathSpec *s;
543
544 assert(p);
545
546 if (!p->make_directory)
547 return;
548
4b562198 549 LIST_FOREACH(spec, s, p->specs)
57020a3a 550 path_spec_mkdir(s, p->directory_mode);
0e456f97
LP
551}
552
01f78473
LP
553static int path_start(Unit *u) {
554 Path *p = PATH(u);
555
556 assert(p);
fdf20a31 557 assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
01f78473 558
ac155bb8 559 if (UNIT_DEREF(p->unit)->load_state != UNIT_LOADED)
01f78473
LP
560 return -ENOENT;
561
0e456f97
LP
562 path_mkdir(p);
563
cd43ca73 564 p->result = PATH_SUCCESS;
ac3f50ca 565 path_enter_waiting(p, true, true);
00dc5d76 566
01f78473
LP
567 return 0;
568}
569
570static int path_stop(Unit *u) {
571 Path *p = PATH(u);
572
573 assert(p);
574 assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
575
cd43ca73 576 path_enter_dead(p, PATH_SUCCESS);
01f78473
LP
577 return 0;
578}
579
580static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
581 Path *p = PATH(u);
582
583 assert(u);
584 assert(f);
585 assert(fds);
586
587 unit_serialize_item(u, f, "state", path_state_to_string(p->state));
cd43ca73 588 unit_serialize_item(u, f, "result", path_result_to_string(p->result));
01f78473
LP
589
590 return 0;
591}
592
593static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
594 Path *p = PATH(u);
595
596 assert(u);
597 assert(key);
598 assert(value);
599 assert(fds);
600
601 if (streq(key, "state")) {
602 PathState state;
603
604 if ((state = path_state_from_string(value)) < 0)
605 log_debug("Failed to parse state value %s", value);
606 else
607 p->deserialized_state = state;
cd43ca73
LP
608
609 } else if (streq(key, "result")) {
610 PathResult f;
611
612 f = path_result_from_string(value);
613 if (f < 0)
614 log_debug("Failed to parse result value %s", value);
615 else if (f != PATH_SUCCESS)
616 p->result = f;
617
01f78473
LP
618 } else
619 log_debug("Unknown serialization key '%s'", key);
620
621 return 0;
622}
623
624static UnitActiveState path_active_state(Unit *u) {
625 assert(u);
626
627 return state_translation_table[PATH(u)->state];
628}
629
630static const char *path_sub_state_to_string(Unit *u) {
631 assert(u);
632
633 return path_state_to_string(PATH(u)->state);
634}
635
636static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
637 Path *p = PATH(u);
01f78473 638 PathSpec *s;
4b562198 639 int changed;
01f78473
LP
640
641 assert(p);
642 assert(fd >= 0);
643
672028dc
LP
644 if (p->state != PATH_WAITING &&
645 p->state != PATH_RUNNING)
01f78473
LP
646 return;
647
ac155bb8 648 /* log_debug("inotify wakeup on %s.", u->id); */
01f78473 649
01f78473 650 LIST_FOREACH(spec, s, p->specs)
57020a3a 651 if (path_spec_owns_inotify_fd(s, fd))
01f78473
LP
652 break;
653
654 if (!s) {
655 log_error("Got event on unknown fd.");
656 goto fail;
657 }
658
57020a3a 659 changed = path_spec_fd_event(s, events);
4b562198 660 if (changed < 0)
01f78473 661 goto fail;
01f78473 662
672028dc
LP
663 /* If we are already running, then remember that one event was
664 * dispatched so that we restart the service only if something
665 * actually changed on disk */
666 p->inotify_triggered = true;
667
672028dc
LP
668 if (changed)
669 path_enter_running(p);
670 else
ac3f50ca 671 path_enter_waiting(p, false, true);
672028dc 672
01f78473
LP
673 return;
674
675fail:
cd43ca73 676 path_enter_dead(p, PATH_FAILURE_RESOURCES);
01f78473
LP
677}
678
679void path_unit_notify(Unit *u, UnitActiveState new_state) {
01f78473 680 Iterator i;
57020a3a 681 Unit *k;
01f78473 682
ac155bb8 683 if (u->type == UNIT_PATH)
01f78473
LP
684 return;
685
ac155bb8 686 SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
01f78473
LP
687 Path *p;
688
ac155bb8 689 if (k->type != UNIT_PATH)
01f78473
LP
690 continue;
691
ac155bb8 692 if (k->load_state != UNIT_LOADED)
01f78473
LP
693 continue;
694
57020a3a 695 p = PATH(k);
01f78473
LP
696
697 if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
1124fe6f 698 log_debug("%s got notified about unit deactivation.", UNIT(p)->id);
672028dc
LP
699
700 /* Hmm, so inotify was triggered since the
701 * last activation, so I guess we need to
702 * recheck what is going on. */
ac3f50ca 703 path_enter_waiting(p, false, p->inotify_triggered);
01f78473
LP
704 }
705 }
01f78473
LP
706}
707
fdf20a31 708static void path_reset_failed(Unit *u) {
5632e374
LP
709 Path *p = PATH(u);
710
711 assert(p);
712
fdf20a31 713 if (p->state == PATH_FAILED)
5632e374
LP
714 path_set_state(p, PATH_DEAD);
715
cd43ca73 716 p->result = PATH_SUCCESS;
5632e374
LP
717}
718
01f78473
LP
719static const char* const path_state_table[_PATH_STATE_MAX] = {
720 [PATH_DEAD] = "dead",
721 [PATH_WAITING] = "waiting",
722 [PATH_RUNNING] = "running",
fdf20a31 723 [PATH_FAILED] = "failed"
01f78473
LP
724};
725
726DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
727
728static const char* const path_type_table[_PATH_TYPE_MAX] = {
729 [PATH_EXISTS] = "PathExists",
8092a428 730 [PATH_EXISTS_GLOB] = "PathExistsGlob",
01f78473 731 [PATH_CHANGED] = "PathChanged",
e9223856 732 [PATH_MODIFIED] = "PathModified",
01f78473
LP
733 [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty"
734};
735
736DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
737
cd43ca73
LP
738static const char* const path_result_table[_PATH_RESULT_MAX] = {
739 [PATH_SUCCESS] = "success",
740 [PATH_FAILURE_RESOURCES] = "resources"
741};
742
743DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
744
01f78473 745const UnitVTable path_vtable = {
7d17cfbc 746 .object_size = sizeof(Path),
f975e971
LP
747 .sections =
748 "Unit\0"
749 "Path\0"
750 "Install\0",
01f78473 751
0e456f97 752 .init = path_init,
01f78473
LP
753 .done = path_done,
754 .load = path_load,
755
756 .coldplug = path_coldplug,
757
758 .dump = path_dump,
759
760 .start = path_start,
761 .stop = path_stop,
762
763 .serialize = path_serialize,
764 .deserialize_item = path_deserialize_item,
765
766 .active_state = path_active_state,
767 .sub_state_to_string = path_sub_state_to_string,
768
769 .fd_event = path_fd_event,
770
fdf20a31 771 .reset_failed = path_reset_failed,
5632e374 772
c4e2ceae 773 .bus_interface = "org.freedesktop.systemd1.Path",
cd43ca73
LP
774 .bus_message_handler = bus_path_message_handler,
775 .bus_invalidating_properties = bus_path_invalidating_properties
01f78473 776};