2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/epoll.h>
22 #include <sys/inotify.h>
25 #include "bus-error.h"
27 #include "dbus-path.h"
30 #include "glob-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
38 #include "unit-name.h"
41 static const UnitActiveState state_translation_table
[_PATH_STATE_MAX
] = {
42 [PATH_DEAD
] = UNIT_INACTIVE
,
43 [PATH_WAITING
] = UNIT_ACTIVE
,
44 [PATH_RUNNING
] = UNIT_ACTIVE
,
45 [PATH_FAILED
] = UNIT_FAILED
48 static int path_dispatch_io(sd_event_source
*source
, int fd
, uint32_t revents
, void *userdata
);
50 int path_spec_watch(PathSpec
*s
, sd_event_io_handler_t handler
) {
52 static const int flags_table
[_PATH_TYPE_MAX
] = {
53 [PATH_EXISTS
] = IN_DELETE_SELF
|IN_MOVE_SELF
|IN_ATTRIB
,
54 [PATH_EXISTS_GLOB
] = IN_DELETE_SELF
|IN_MOVE_SELF
|IN_ATTRIB
,
55 [PATH_CHANGED
] = IN_DELETE_SELF
|IN_MOVE_SELF
|IN_ATTRIB
|IN_CLOSE_WRITE
|IN_CREATE
|IN_DELETE
|IN_MOVED_FROM
|IN_MOVED_TO
,
56 [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
,
57 [PATH_DIRECTORY_NOT_EMPTY
] = IN_DELETE_SELF
|IN_MOVE_SELF
|IN_ATTRIB
|IN_CREATE
|IN_MOVED_TO
61 char *slash
, *oldslash
= NULL
;
70 s
->inotify_fd
= inotify_init1(IN_NONBLOCK
|IN_CLOEXEC
);
71 if (s
->inotify_fd
< 0) {
76 r
= sd_event_add_io(s
->unit
->manager
->event
, &s
->event_source
, s
->inotify_fd
, EPOLLIN
, handler
, s
);
80 (void) sd_event_source_set_description(s
->event_source
, "path");
82 /* This assumes the path was passed through path_kill_slashes()! */
84 for (slash
= strchr(s
->path
, '/'); ; slash
= strchr(slash
+1, '/')) {
90 cut
= slash
+ (slash
== s
->path
);
94 flags
= IN_MOVE_SELF
| IN_DELETE_SELF
| IN_ATTRIB
| IN_CREATE
| IN_MOVED_TO
;
96 flags
= flags_table
[s
->type
];
98 r
= inotify_add_watch(s
->inotify_fd
, s
->path
, flags
);
100 if (errno
== EACCES
|| errno
== ENOENT
) {
106 r
= log_warning_errno(errno
, "Failed to add watch on %s: %s", s
->path
, errno
== ENOSPC
? "too many watches" : strerror(-r
));
113 /* Path exists, we don't need to watch parent too closely. */
115 char *cut2
= oldslash
+ (oldslash
== s
->path
);
119 (void) inotify_add_watch(s
->inotify_fd
, s
->path
, IN_MOVE_SELF
);
120 /* Error is ignored, the worst can happen is we get spurious events. */
132 /* whole path has been iterated over */
139 r
= log_error_errno(errno
, "Failed to add watch on any of the components of %s: %m", s
->path
);
140 /* either EACCESS or ENOENT */
147 path_spec_unwatch(s
);
151 void path_spec_unwatch(PathSpec
*s
) {
154 s
->event_source
= sd_event_source_unref(s
->event_source
);
155 s
->inotify_fd
= safe_close(s
->inotify_fd
);
158 int path_spec_fd_event(PathSpec
*s
, uint32_t revents
) {
159 union inotify_event_buffer buffer
;
160 struct inotify_event
*e
;
164 if (revents
!= EPOLLIN
) {
165 log_error("Got invalid poll event on inotify.");
169 l
= read(s
->inotify_fd
, &buffer
, sizeof(buffer
));
171 if (errno
== EAGAIN
|| errno
== EINTR
)
174 return log_error_errno(errno
, "Failed to read inotify event: %m");
177 FOREACH_INOTIFY_EVENT(e
, buffer
, l
) {
178 if ((s
->type
== PATH_CHANGED
|| s
->type
== PATH_MODIFIED
) &&
179 s
->primary_wd
== e
->wd
)
186 static bool path_spec_check_good(PathSpec
*s
, bool initial
) {
192 good
= access(s
->path
, F_OK
) >= 0;
195 case PATH_EXISTS_GLOB
:
196 good
= glob_exists(s
->path
) > 0;
199 case PATH_DIRECTORY_NOT_EMPTY
: {
202 k
= dir_is_empty(s
->path
);
203 good
= !(k
== -ENOENT
|| k
> 0);
208 case PATH_MODIFIED
: {
211 b
= access(s
->path
, F_OK
) >= 0;
212 good
= !initial
&& b
!= s
->previous_exists
;
213 s
->previous_exists
= b
;
224 static void path_spec_mkdir(PathSpec
*s
, mode_t mode
) {
227 if (s
->type
== PATH_EXISTS
|| s
->type
== PATH_EXISTS_GLOB
)
230 r
= mkdir_p_label(s
->path
, mode
);
232 log_warning_errno(r
, "mkdir(%s) failed: %m", s
->path
);
235 static void path_spec_dump(PathSpec
*s
, FILE *f
, const char *prefix
) {
239 path_type_to_string(s
->type
),
243 void path_spec_done(PathSpec
*s
) {
245 assert(s
->inotify_fd
== -1);
250 static void path_init(Unit
*u
) {
254 assert(u
->load_state
== UNIT_STUB
);
256 p
->directory_mode
= 0755;
259 void path_free_specs(Path
*p
) {
264 while ((s
= p
->specs
)) {
265 path_spec_unwatch(s
);
266 LIST_REMOVE(spec
, p
->specs
, s
);
272 static void path_done(Unit
*u
) {
280 static int path_add_mount_links(Path
*p
) {
286 LIST_FOREACH(spec
, s
, p
->specs
) {
287 r
= unit_require_mounts_for(UNIT(p
), s
->path
);
295 static int path_verify(Path
*p
) {
298 if (UNIT(p
)->load_state
!= UNIT_LOADED
)
302 log_unit_error(UNIT(p
), "Path unit lacks path setting. Refusing.");
309 static int path_add_default_dependencies(Path
*p
) {
314 if (!UNIT(p
)->default_dependencies
)
317 r
= unit_add_dependency_by_name(UNIT(p
), UNIT_BEFORE
, SPECIAL_PATHS_TARGET
, NULL
, true);
321 if (MANAGER_IS_SYSTEM(UNIT(p
)->manager
)) {
322 r
= unit_add_two_dependencies_by_name(UNIT(p
), UNIT_AFTER
, UNIT_REQUIRES
, SPECIAL_SYSINIT_TARGET
, NULL
, true);
327 return unit_add_two_dependencies_by_name(UNIT(p
), UNIT_BEFORE
, UNIT_CONFLICTS
, SPECIAL_SHUTDOWN_TARGET
, NULL
, true);
330 static int path_load(Unit
*u
) {
335 assert(u
->load_state
== UNIT_STUB
);
337 r
= unit_load_fragment_and_dropin(u
);
341 if (u
->load_state
== UNIT_LOADED
) {
343 if (set_isempty(u
->dependencies
[UNIT_TRIGGERS
])) {
346 r
= unit_load_related_unit(u
, ".service", &x
);
350 r
= unit_add_two_dependencies(u
, UNIT_BEFORE
, UNIT_TRIGGERS
, x
, true);
355 r
= path_add_mount_links(p
);
359 r
= path_add_default_dependencies(p
);
364 return path_verify(p
);
367 static void path_dump(Unit
*u
, FILE *f
, const char *prefix
) {
375 trigger
= UNIT_TRIGGER(u
);
381 "%sMakeDirectory: %s\n"
382 "%sDirectoryMode: %04o\n",
383 prefix
, path_state_to_string(p
->state
),
384 prefix
, path_result_to_string(p
->result
),
385 prefix
, trigger
? trigger
->id
: "n/a",
386 prefix
, yes_no(p
->make_directory
),
387 prefix
, p
->directory_mode
);
389 LIST_FOREACH(spec
, s
, p
->specs
)
390 path_spec_dump(s
, f
, prefix
);
393 static void path_unwatch(Path
*p
) {
398 LIST_FOREACH(spec
, s
, p
->specs
)
399 path_spec_unwatch(s
);
402 static int path_watch(Path
*p
) {
408 LIST_FOREACH(spec
, s
, p
->specs
) {
409 r
= path_spec_watch(s
, path_dispatch_io
);
417 static void path_set_state(Path
*p
, PathState state
) {
421 old_state
= p
->state
;
424 if (state
!= PATH_WAITING
&&
425 (state
!= PATH_RUNNING
|| p
->inotify_triggered
))
428 if (state
!= old_state
)
429 log_unit_debug(UNIT(p
), "Changed %s -> %s", path_state_to_string(old_state
), path_state_to_string(state
));
431 unit_notify(UNIT(p
), state_translation_table
[old_state
], state_translation_table
[state
], true);
434 static void path_enter_waiting(Path
*p
, bool initial
, bool recheck
);
436 static int path_coldplug(Unit
*u
) {
440 assert(p
->state
== PATH_DEAD
);
442 if (p
->deserialized_state
!= p
->state
) {
444 if (p
->deserialized_state
== PATH_WAITING
||
445 p
->deserialized_state
== PATH_RUNNING
)
446 path_enter_waiting(p
, true, true);
448 path_set_state(p
, p
->deserialized_state
);
454 static void path_enter_dead(Path
*p
, PathResult f
) {
457 if (f
!= PATH_SUCCESS
)
460 path_set_state(p
, p
->result
!= PATH_SUCCESS
? PATH_FAILED
: PATH_DEAD
);
463 static void path_enter_running(Path
*p
) {
464 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
470 /* Don't start job if we are supposed to go down */
471 if (unit_stop_pending(UNIT(p
)))
474 trigger
= UNIT_TRIGGER(UNIT(p
));
476 log_unit_error(UNIT(p
), "Unit to trigger vanished.");
477 path_enter_dead(p
, PATH_FAILURE_RESOURCES
);
481 r
= manager_add_job(UNIT(p
)->manager
, JOB_START
, trigger
, JOB_REPLACE
, &error
, NULL
);
485 p
->inotify_triggered
= false;
491 path_set_state(p
, PATH_RUNNING
);
495 log_unit_warning(UNIT(p
), "Failed to queue unit startup job: %s", bus_error_message(&error
, r
));
496 path_enter_dead(p
, PATH_FAILURE_RESOURCES
);
499 static bool path_check_good(Path
*p
, bool initial
) {
505 LIST_FOREACH(spec
, s
, p
->specs
) {
506 good
= path_spec_check_good(s
, initial
);
515 static void path_enter_waiting(Path
*p
, bool initial
, bool recheck
) {
519 if (path_check_good(p
, initial
)) {
520 log_unit_debug(UNIT(p
), "Got triggered.");
521 path_enter_running(p
);
529 /* Hmm, so now we have created inotify watches, but the file
530 * might have appeared/been removed by now, so we must
534 if (path_check_good(p
, false)) {
535 log_unit_debug(UNIT(p
), "Got triggered.");
536 path_enter_running(p
);
540 path_set_state(p
, PATH_WAITING
);
544 log_unit_warning_errno(UNIT(p
), r
, "Failed to enter waiting state: %m");
545 path_enter_dead(p
, PATH_FAILURE_RESOURCES
);
548 static void path_mkdir(Path
*p
) {
553 if (!p
->make_directory
)
556 LIST_FOREACH(spec
, s
, p
->specs
)
557 path_spec_mkdir(s
, p
->directory_mode
);
560 static int path_start(Unit
*u
) {
566 assert(p
->state
== PATH_DEAD
|| p
->state
== PATH_FAILED
);
568 trigger
= UNIT_TRIGGER(u
);
569 if (!trigger
|| trigger
->load_state
!= UNIT_LOADED
) {
570 log_unit_error(u
, "Refusing to start, unit to trigger not loaded.");
574 r
= unit_start_limit_test(u
);
576 path_enter_dead(p
, PATH_FAILURE_START_LIMIT_HIT
);
582 p
->result
= PATH_SUCCESS
;
583 path_enter_waiting(p
, true, true);
588 static int path_stop(Unit
*u
) {
592 assert(p
->state
== PATH_WAITING
|| p
->state
== PATH_RUNNING
);
594 path_enter_dead(p
, PATH_SUCCESS
);
598 static int path_serialize(Unit
*u
, FILE *f
, FDSet
*fds
) {
605 unit_serialize_item(u
, f
, "state", path_state_to_string(p
->state
));
606 unit_serialize_item(u
, f
, "result", path_result_to_string(p
->result
));
611 static int path_deserialize_item(Unit
*u
, const char *key
, const char *value
, FDSet
*fds
) {
619 if (streq(key
, "state")) {
622 state
= path_state_from_string(value
);
624 log_unit_debug(u
, "Failed to parse state value: %s", value
);
626 p
->deserialized_state
= state
;
628 } else if (streq(key
, "result")) {
631 f
= path_result_from_string(value
);
633 log_unit_debug(u
, "Failed to parse result value: %s", value
);
634 else if (f
!= PATH_SUCCESS
)
638 log_unit_debug(u
, "Unknown serialization key: %s", key
);
643 _pure_
static UnitActiveState
path_active_state(Unit
*u
) {
646 return state_translation_table
[PATH(u
)->state
];
649 _pure_
static const char *path_sub_state_to_string(Unit
*u
) {
652 return path_state_to_string(PATH(u
)->state
);
655 static int path_dispatch_io(sd_event_source
*source
, int fd
, uint32_t revents
, void *userdata
) {
656 PathSpec
*s
= userdata
;
666 if (p
->state
!= PATH_WAITING
&&
667 p
->state
!= PATH_RUNNING
)
670 /* log_debug("inotify wakeup on %s.", u->id); */
672 LIST_FOREACH(spec
, s
, p
->specs
)
673 if (path_spec_owns_inotify_fd(s
, fd
))
677 log_error("Got event on unknown fd.");
681 changed
= path_spec_fd_event(s
, revents
);
685 /* If we are already running, then remember that one event was
686 * dispatched so that we restart the service only if something
687 * actually changed on disk */
688 p
->inotify_triggered
= true;
691 path_enter_running(p
);
693 path_enter_waiting(p
, false, true);
698 path_enter_dead(p
, PATH_FAILURE_RESOURCES
);
702 static void path_trigger_notify(Unit
*u
, Unit
*other
) {
708 /* Invoked whenever the unit we trigger changes state or gains
711 if (other
->load_state
!= UNIT_LOADED
)
714 if (p
->state
== PATH_RUNNING
&&
715 UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other
))) {
716 log_unit_debug(UNIT(p
), "Got notified about unit deactivation.");
718 /* Hmm, so inotify was triggered since the
719 * last activation, so I guess we need to
720 * recheck what is going on. */
721 path_enter_waiting(p
, false, p
->inotify_triggered
);
725 static void path_reset_failed(Unit
*u
) {
730 if (p
->state
== PATH_FAILED
)
731 path_set_state(p
, PATH_DEAD
);
733 p
->result
= PATH_SUCCESS
;
736 static const char* const path_type_table
[_PATH_TYPE_MAX
] = {
737 [PATH_EXISTS
] = "PathExists",
738 [PATH_EXISTS_GLOB
] = "PathExistsGlob",
739 [PATH_DIRECTORY_NOT_EMPTY
] = "DirectoryNotEmpty",
740 [PATH_CHANGED
] = "PathChanged",
741 [PATH_MODIFIED
] = "PathModified",
744 DEFINE_STRING_TABLE_LOOKUP(path_type
, PathType
);
746 static const char* const path_result_table
[_PATH_RESULT_MAX
] = {
747 [PATH_SUCCESS
] = "success",
748 [PATH_FAILURE_RESOURCES
] = "resources",
749 [PATH_FAILURE_START_LIMIT_HIT
] = "start-limit-hit",
752 DEFINE_STRING_TABLE_LOOKUP(path_result
, PathResult
);
754 const UnitVTable path_vtable
= {
755 .object_size
= sizeof(Path
),
766 .coldplug
= path_coldplug
,
773 .serialize
= path_serialize
,
774 .deserialize_item
= path_deserialize_item
,
776 .active_state
= path_active_state
,
777 .sub_state_to_string
= path_sub_state_to_string
,
779 .trigger_notify
= path_trigger_notify
,
781 .reset_failed
= path_reset_failed
,
783 .bus_vtable
= bus_path_vtable