]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/path.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / core / path.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <sys/epoll.h>
24 #include <sys/inotify.h>
25 #include <unistd.h>
26
27 #include "bus-error.h"
28 #include "bus-util.h"
29 #include "dbus-path.h"
30 #include "macro.h"
31 #include "mkdir.h"
32 #include "special.h"
33 #include "string-util.h"
34 #include "unit-name.h"
35 #include "unit.h"
36 #include "path.h"
37
38 static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
39 [PATH_DEAD] = UNIT_INACTIVE,
40 [PATH_WAITING] = UNIT_ACTIVE,
41 [PATH_RUNNING] = UNIT_ACTIVE,
42 [PATH_FAILED] = UNIT_FAILED
43 };
44
45 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
46
47 int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
48
49 static const int flags_table[_PATH_TYPE_MAX] = {
50 [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
51 [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
52 [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
53 [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,
54 [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
55 };
56
57 bool exists = false;
58 char *slash, *oldslash = NULL;
59 int r;
60
61 assert(s);
62 assert(s->unit);
63 assert(handler);
64
65 path_spec_unwatch(s);
66
67 s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
68 if (s->inotify_fd < 0) {
69 r = -errno;
70 goto fail;
71 }
72
73 r = sd_event_add_io(s->unit->manager->event, &s->event_source, s->inotify_fd, EPOLLIN, handler, s);
74 if (r < 0)
75 goto fail;
76
77 (void) sd_event_source_set_description(s->event_source, "path");
78
79 /* This assumes the path was passed through path_kill_slashes()! */
80
81 for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
82 char *cut = NULL;
83 int flags;
84 char tmp;
85
86 if (slash) {
87 cut = slash + (slash == s->path);
88 tmp = *cut;
89 *cut = '\0';
90
91 flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
92 } else
93 flags = flags_table[s->type];
94
95 r = inotify_add_watch(s->inotify_fd, s->path, flags);
96 if (r < 0) {
97 if (errno == EACCES || errno == ENOENT) {
98 if (cut)
99 *cut = tmp;
100 break;
101 }
102
103 r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror(-r));
104 if (cut)
105 *cut = tmp;
106 goto fail;
107 } else {
108 exists = true;
109
110 /* Path exists, we don't need to watch parent
111 too closely. */
112 if (oldslash) {
113 char *cut2 = oldslash + (oldslash == s->path);
114 char tmp2 = *cut2;
115 *cut2 = '\0';
116
117 inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
118 /* Error is ignored, the worst can happen is
119 we get spurious events. */
120
121 *cut2 = tmp2;
122 }
123 }
124
125 if (cut)
126 *cut = tmp;
127
128 if (slash)
129 oldslash = slash;
130 else {
131 /* whole path has been iterated over */
132 s->primary_wd = r;
133 break;
134 }
135 }
136
137 if (!exists) {
138 r = log_error_errno(errno, "Failed to add watch on any of the components of %s: %m", s->path);
139 /* either EACCESS or ENOENT */
140 goto fail;
141 }
142
143 return 0;
144
145 fail:
146 path_spec_unwatch(s);
147 return r;
148 }
149
150 void path_spec_unwatch(PathSpec *s) {
151 assert(s);
152
153 s->event_source = sd_event_source_unref(s->event_source);
154 s->inotify_fd = safe_close(s->inotify_fd);
155 }
156
157 int path_spec_fd_event(PathSpec *s, uint32_t revents) {
158 union inotify_event_buffer buffer;
159 struct inotify_event *e;
160 ssize_t l;
161 int r = 0;
162
163 if (revents != EPOLLIN) {
164 log_error("Got invalid poll event on inotify.");
165 return -EINVAL;
166 }
167
168 l = read(s->inotify_fd, &buffer, sizeof(buffer));
169 if (l < 0) {
170 if (errno == EAGAIN || errno == EINTR)
171 return 0;
172
173 return log_error_errno(errno, "Failed to read inotify event: %m");
174 }
175
176 FOREACH_INOTIFY_EVENT(e, buffer, l) {
177 if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
178 s->primary_wd == e->wd)
179 r = 1;
180 }
181
182 return r;
183 }
184
185 static bool path_spec_check_good(PathSpec *s, bool initial) {
186 bool good = false;
187
188 switch (s->type) {
189
190 case PATH_EXISTS:
191 good = access(s->path, F_OK) >= 0;
192 break;
193
194 case PATH_EXISTS_GLOB:
195 good = glob_exists(s->path) > 0;
196 break;
197
198 case PATH_DIRECTORY_NOT_EMPTY: {
199 int k;
200
201 k = dir_is_empty(s->path);
202 good = !(k == -ENOENT || k > 0);
203 break;
204 }
205
206 case PATH_CHANGED:
207 case PATH_MODIFIED: {
208 bool b;
209
210 b = access(s->path, F_OK) >= 0;
211 good = !initial && b != s->previous_exists;
212 s->previous_exists = b;
213 break;
214 }
215
216 default:
217 ;
218 }
219
220 return good;
221 }
222
223 static void path_spec_mkdir(PathSpec *s, mode_t mode) {
224 int r;
225
226 if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
227 return;
228
229 r = mkdir_p_label(s->path, mode);
230 if (r < 0)
231 log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
232 }
233
234 static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
235 fprintf(f,
236 "%s%s: %s\n",
237 prefix,
238 path_type_to_string(s->type),
239 s->path);
240 }
241
242 void path_spec_done(PathSpec *s) {
243 assert(s);
244 assert(s->inotify_fd == -1);
245
246 free(s->path);
247 }
248
249 static void path_init(Unit *u) {
250 Path *p = PATH(u);
251
252 assert(u);
253 assert(u->load_state == UNIT_STUB);
254
255 p->directory_mode = 0755;
256 }
257
258 void path_free_specs(Path *p) {
259 PathSpec *s;
260
261 assert(p);
262
263 while ((s = p->specs)) {
264 path_spec_unwatch(s);
265 LIST_REMOVE(spec, p->specs, s);
266 path_spec_done(s);
267 free(s);
268 }
269 }
270
271 static void path_done(Unit *u) {
272 Path *p = PATH(u);
273
274 assert(p);
275
276 path_free_specs(p);
277 }
278
279 static int path_add_mount_links(Path *p) {
280 PathSpec *s;
281 int r;
282
283 assert(p);
284
285 LIST_FOREACH(spec, s, p->specs) {
286 r = unit_require_mounts_for(UNIT(p), s->path);
287 if (r < 0)
288 return r;
289 }
290
291 return 0;
292 }
293
294 static int path_verify(Path *p) {
295 assert(p);
296
297 if (UNIT(p)->load_state != UNIT_LOADED)
298 return 0;
299
300 if (!p->specs) {
301 log_unit_error(UNIT(p), "Path unit lacks path setting. Refusing.");
302 return -EINVAL;
303 }
304
305 return 0;
306 }
307
308 static int path_add_default_dependencies(Path *p) {
309 int r;
310
311 assert(p);
312
313 r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
314 SPECIAL_PATHS_TARGET, NULL, true);
315 if (r < 0)
316 return r;
317
318 if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
319 r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
320 SPECIAL_SYSINIT_TARGET, NULL, true);
321 if (r < 0)
322 return r;
323 }
324
325 return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
326 SPECIAL_SHUTDOWN_TARGET, NULL, true);
327 }
328
329 static int path_load(Unit *u) {
330 Path *p = PATH(u);
331 int r;
332
333 assert(u);
334 assert(u->load_state == UNIT_STUB);
335
336 r = unit_load_fragment_and_dropin(u);
337 if (r < 0)
338 return r;
339
340 if (u->load_state == UNIT_LOADED) {
341
342 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
343 Unit *x;
344
345 r = unit_load_related_unit(u, ".service", &x);
346 if (r < 0)
347 return r;
348
349 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
350 if (r < 0)
351 return r;
352 }
353
354 r = path_add_mount_links(p);
355 if (r < 0)
356 return r;
357
358 if (UNIT(p)->default_dependencies) {
359 r = path_add_default_dependencies(p);
360 if (r < 0)
361 return r;
362 }
363 }
364
365 return path_verify(p);
366 }
367
368 static void path_dump(Unit *u, FILE *f, const char *prefix) {
369 Path *p = PATH(u);
370 Unit *trigger;
371 PathSpec *s;
372
373 assert(p);
374 assert(f);
375
376 trigger = UNIT_TRIGGER(u);
377
378 fprintf(f,
379 "%sPath State: %s\n"
380 "%sResult: %s\n"
381 "%sUnit: %s\n"
382 "%sMakeDirectory: %s\n"
383 "%sDirectoryMode: %04o\n",
384 prefix, path_state_to_string(p->state),
385 prefix, path_result_to_string(p->result),
386 prefix, trigger ? trigger->id : "n/a",
387 prefix, yes_no(p->make_directory),
388 prefix, p->directory_mode);
389
390 LIST_FOREACH(spec, s, p->specs)
391 path_spec_dump(s, f, prefix);
392 }
393
394 static void path_unwatch(Path *p) {
395 PathSpec *s;
396
397 assert(p);
398
399 LIST_FOREACH(spec, s, p->specs)
400 path_spec_unwatch(s);
401 }
402
403 static int path_watch(Path *p) {
404 int r;
405 PathSpec *s;
406
407 assert(p);
408
409 LIST_FOREACH(spec, s, p->specs) {
410 r = path_spec_watch(s, path_dispatch_io);
411 if (r < 0)
412 return r;
413 }
414
415 return 0;
416 }
417
418 static void path_set_state(Path *p, PathState state) {
419 PathState old_state;
420 assert(p);
421
422 old_state = p->state;
423 p->state = state;
424
425 if (state != PATH_WAITING &&
426 (state != PATH_RUNNING || p->inotify_triggered))
427 path_unwatch(p);
428
429 if (state != old_state)
430 log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
431
432 unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
433 }
434
435 static void path_enter_waiting(Path *p, bool initial, bool recheck);
436
437 static 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)
447 path_enter_waiting(p, true, true);
448 else
449 path_set_state(p, p->deserialized_state);
450 }
451
452 return 0;
453 }
454
455 static void path_enter_dead(Path *p, PathResult f) {
456 assert(p);
457
458 if (f != PATH_SUCCESS)
459 p->result = f;
460
461 path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
462 }
463
464 static void path_enter_running(Path *p) {
465 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
466 int r;
467
468 assert(p);
469
470 /* Don't start job if we are supposed to go down */
471 if (unit_stop_pending(UNIT(p)))
472 return;
473
474 r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
475 JOB_REPLACE, true, &error, NULL);
476 if (r < 0)
477 goto fail;
478
479 p->inotify_triggered = false;
480
481 r = path_watch(p);
482 if (r < 0)
483 goto fail;
484
485 path_set_state(p, PATH_RUNNING);
486 return;
487
488 fail:
489 log_unit_warning(UNIT(p), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
490 path_enter_dead(p, PATH_FAILURE_RESOURCES);
491 }
492
493 static bool path_check_good(Path *p, bool initial) {
494 PathSpec *s;
495 bool good = false;
496
497 assert(p);
498
499 LIST_FOREACH(spec, s, p->specs) {
500 good = path_spec_check_good(s, initial);
501
502 if (good)
503 break;
504 }
505
506 return good;
507 }
508
509 static void path_enter_waiting(Path *p, bool initial, bool recheck) {
510 int r;
511
512 if (recheck)
513 if (path_check_good(p, initial)) {
514 log_unit_debug(UNIT(p), "Got triggered.");
515 path_enter_running(p);
516 return;
517 }
518
519 r = path_watch(p);
520 if (r < 0)
521 goto fail;
522
523 /* Hmm, so now we have created inotify watches, but the file
524 * might have appeared/been removed by now, so we must
525 * recheck */
526
527 if (recheck)
528 if (path_check_good(p, false)) {
529 log_unit_debug(UNIT(p), "Got triggered.");
530 path_enter_running(p);
531 return;
532 }
533
534 path_set_state(p, PATH_WAITING);
535 return;
536
537 fail:
538 log_unit_warning_errno(UNIT(p), r, "Failed to enter waiting state: %m");
539 path_enter_dead(p, PATH_FAILURE_RESOURCES);
540 }
541
542 static void path_mkdir(Path *p) {
543 PathSpec *s;
544
545 assert(p);
546
547 if (!p->make_directory)
548 return;
549
550 LIST_FOREACH(spec, s, p->specs)
551 path_spec_mkdir(s, p->directory_mode);
552 }
553
554 static int path_start(Unit *u) {
555 Path *p = PATH(u);
556
557 assert(p);
558 assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
559
560 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
561 return -ENOENT;
562
563 path_mkdir(p);
564
565 p->result = PATH_SUCCESS;
566 path_enter_waiting(p, true, true);
567
568 return 1;
569 }
570
571 static int path_stop(Unit *u) {
572 Path *p = PATH(u);
573
574 assert(p);
575 assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
576
577 path_enter_dead(p, PATH_SUCCESS);
578 return 1;
579 }
580
581 static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
582 Path *p = PATH(u);
583
584 assert(u);
585 assert(f);
586 assert(fds);
587
588 unit_serialize_item(u, f, "state", path_state_to_string(p->state));
589 unit_serialize_item(u, f, "result", path_result_to_string(p->result));
590
591 return 0;
592 }
593
594 static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
595 Path *p = PATH(u);
596
597 assert(u);
598 assert(key);
599 assert(value);
600 assert(fds);
601
602 if (streq(key, "state")) {
603 PathState state;
604
605 state = path_state_from_string(value);
606 if (state < 0)
607 log_unit_debug(u, "Failed to parse state value: %s", value);
608 else
609 p->deserialized_state = state;
610
611 } else if (streq(key, "result")) {
612 PathResult f;
613
614 f = path_result_from_string(value);
615 if (f < 0)
616 log_unit_debug(u, "Failed to parse result value: %s", value);
617 else if (f != PATH_SUCCESS)
618 p->result = f;
619
620 } else
621 log_unit_debug(u, "Unknown serialization key: %s", key);
622
623 return 0;
624 }
625
626 _pure_ static UnitActiveState path_active_state(Unit *u) {
627 assert(u);
628
629 return state_translation_table[PATH(u)->state];
630 }
631
632 _pure_ static const char *path_sub_state_to_string(Unit *u) {
633 assert(u);
634
635 return path_state_to_string(PATH(u)->state);
636 }
637
638 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
639 PathSpec *s = userdata;
640 Path *p;
641 int changed;
642
643 assert(s);
644 assert(s->unit);
645 assert(fd >= 0);
646
647 p = PATH(s->unit);
648
649 if (p->state != PATH_WAITING &&
650 p->state != PATH_RUNNING)
651 return 0;
652
653 /* log_debug("inotify wakeup on %s.", u->id); */
654
655 LIST_FOREACH(spec, s, p->specs)
656 if (path_spec_owns_inotify_fd(s, fd))
657 break;
658
659 if (!s) {
660 log_error("Got event on unknown fd.");
661 goto fail;
662 }
663
664 changed = path_spec_fd_event(s, revents);
665 if (changed < 0)
666 goto fail;
667
668 /* If we are already running, then remember that one event was
669 * dispatched so that we restart the service only if something
670 * actually changed on disk */
671 p->inotify_triggered = true;
672
673 if (changed)
674 path_enter_running(p);
675 else
676 path_enter_waiting(p, false, true);
677
678 return 0;
679
680 fail:
681 path_enter_dead(p, PATH_FAILURE_RESOURCES);
682 return 0;
683 }
684
685 static void path_trigger_notify(Unit *u, Unit *other) {
686 Path *p = PATH(u);
687
688 assert(u);
689 assert(other);
690
691 /* Invoked whenever the unit we trigger changes state or gains
692 * or loses a job */
693
694 if (other->load_state != UNIT_LOADED)
695 return;
696
697 if (p->state == PATH_RUNNING &&
698 UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
699 log_unit_debug(UNIT(p), "Got notified about unit deactivation.");
700
701 /* Hmm, so inotify was triggered since the
702 * last activation, so I guess we need to
703 * recheck what is going on. */
704 path_enter_waiting(p, false, p->inotify_triggered);
705 }
706 }
707
708 static void path_reset_failed(Unit *u) {
709 Path *p = PATH(u);
710
711 assert(p);
712
713 if (p->state == PATH_FAILED)
714 path_set_state(p, PATH_DEAD);
715
716 p->result = PATH_SUCCESS;
717 }
718
719 static const char* const path_type_table[_PATH_TYPE_MAX] = {
720 [PATH_EXISTS] = "PathExists",
721 [PATH_EXISTS_GLOB] = "PathExistsGlob",
722 [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
723 [PATH_CHANGED] = "PathChanged",
724 [PATH_MODIFIED] = "PathModified",
725 };
726
727 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
728
729 static const char* const path_result_table[_PATH_RESULT_MAX] = {
730 [PATH_SUCCESS] = "success",
731 [PATH_FAILURE_RESOURCES] = "resources",
732 };
733
734 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
735
736 const UnitVTable path_vtable = {
737 .object_size = sizeof(Path),
738
739 .sections =
740 "Unit\0"
741 "Path\0"
742 "Install\0",
743
744 .init = path_init,
745 .done = path_done,
746 .load = path_load,
747
748 .coldplug = path_coldplug,
749
750 .dump = path_dump,
751
752 .start = path_start,
753 .stop = path_stop,
754
755 .serialize = path_serialize,
756 .deserialize_item = path_deserialize_item,
757
758 .active_state = path_active_state,
759 .sub_state_to_string = path_sub_state_to_string,
760
761 .trigger_notify = path_trigger_notify,
762
763 .reset_failed = path_reset_failed,
764
765 .bus_vtable = bus_path_vtable
766 };