Merge pull request #3170 from poettering/v230-preparation-fixes

make virtualization detection quieter, rework unit start limit logic, detect unit file drop-in changes correctly, fix autofs state propagation
This commit is contained in:
Lennart Poettering 2016-05-04 10:46:13 +02:00
commit 1ed7ebcfca
22 changed files with 172 additions and 106 deletions

View File

@ -770,7 +770,9 @@
<command>systemctl reset-failed</command> will cause the restart rate counter for a service to be flushed,
which is useful if the administrator wants to manually start a unit and the start limit interferes with
that. Note that this rate-limiting is enforced after any unit condition checks are executed, and hence unit
activations with failing conditions are not counted by this rate limiting.</para></listitem>
activations with failing conditions are not counted by this rate limiting. Slice, target, device and scope
units do not enforce this setting, as they are unit types whose activation may either never fail, or may
succeed only a single time.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -280,7 +280,7 @@ static int detect_vm_uml(void) {
return VIRTUALIZATION_UML;
}
log_debug("No virtualization found in /proc/cpuinfo (%s)", cpuinfo_contents);
log_debug("No virtualization found in /proc/cpuinfo.");
return VIRTUALIZATION_NONE;
}

View File

@ -75,6 +75,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
static int open_dev_autofs(Manager *m);
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
static int automount_start_expire(Automount *a);
static void automount_stop_expire(Automount *a);
static int automount_send_ready(Automount *a, Set *tokens, int status);
static void automount_init(Unit *u) {
Automount *a = AUTOMOUNT(u);
@ -87,8 +90,6 @@ static void automount_init(Unit *u) {
UNIT(a)->ignore_on_isolate = true;
}
static int automount_send_ready(Automount *a, Set *tokens, int status);
static void unmount_autofs(Automount *a) {
int r;
@ -235,6 +236,9 @@ static void automount_set_state(Automount *a, AutomountState state) {
old_state = a->state;
a->state = state;
if (state != AUTOMOUNT_RUNNING)
automount_stop_expire(a);
if (state != AUTOMOUNT_WAITING &&
state != AUTOMOUNT_RUNNING)
unmount_autofs(a);
@ -408,7 +412,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in
init_autofs_dev_ioctl(&param);
param.ioctlfd = ioctl_fd;
if (status) {
if (status != 0) {
param.fail.token = token;
param.fail.status = status;
} else
@ -435,7 +439,7 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
if (ioctl_fd < 0)
return ioctl_fd;
if (status)
if (status != 0)
log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
else
log_unit_debug(UNIT(a), "Sending success.");
@ -462,59 +466,54 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
return r;
}
static int automount_start_expire(Automount *a);
int automount_update_mount(Automount *a, MountState old_state, MountState state) {
static void automount_trigger_notify(Unit *u, Unit *other) {
Automount *a = AUTOMOUNT(u);
int r;
assert(a);
assert(other);
/* Filter out invocations with bogus state */
if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT)
return;
/* Don't propagate state changes from the mount if we are already down */
if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
return;
/* Propagate start limit hit state */
if (other->start_limit_hit) {
automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT);
return;
}
/* Don't propagate anything if there's still a job queued */
if (other->job)
return;
/* The mount is successfully established */
if (IN_SET(MOUNT(other)->state, MOUNT_MOUNTED, MOUNT_REMOUNTING)) {
(void) automount_send_ready(a, a->tokens, 0);
switch (state) {
case MOUNT_MOUNTED:
case MOUNT_REMOUNTING:
automount_send_ready(a, a->tokens, 0);
r = automount_start_expire(a);
if (r < 0)
log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
break;
case MOUNT_DEAD:
case MOUNT_UNMOUNTING:
case MOUNT_MOUNTING_SIGTERM:
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGTERM:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_FAILED:
if (old_state != state)
automount_send_ready(a, a->tokens, -ENODEV);
(void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
break;
default:
break;
automount_set_state(a, AUTOMOUNT_RUNNING);
}
switch (state) {
case MOUNT_DEAD:
automount_send_ready(a, a->expire_tokens, 0);
break;
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
case MOUNT_MOUNTING_SIGTERM:
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGTERM:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_FAILED:
if (old_state != state)
automount_send_ready(a, a->expire_tokens, -ENODEV);
break;
default:
break;
}
/* The mount is in some unhappy state now, let's unfreeze any waiting clients */
if (IN_SET(MOUNT(other)->state,
MOUNT_DEAD, MOUNT_UNMOUNTING,
MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
MOUNT_FAILED)) {
return 0;
(void) automount_send_ready(a, a->tokens, -ENODEV);
automount_set_state(a, AUTOMOUNT_WAITING);
}
}
static void automount_enter_waiting(Automount *a) {
@ -699,6 +698,15 @@ static int automount_start_expire(Automount *a) {
return 0;
}
static void automount_stop_expire(Automount *a) {
assert(a);
if (!a->expire_event_source)
return;
(void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
}
static void automount_enter_runnning(Automount *a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
struct stat st;
@ -751,6 +759,7 @@ fail:
static int automount_start(Unit *u) {
Automount *a = AUTOMOUNT(u);
Unit *trigger;
int r;
assert(a);
assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
@ -766,6 +775,12 @@ static int automount_start(Unit *u) {
return -ENOENT;
}
r = unit_start_limit_test(u);
if (r < 0) {
automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
return r;
}
a->result = AUTOMOUNT_SUCCESS;
automount_enter_waiting(a);
return 1;
@ -958,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
case autofs_ptype_expire_direct:
log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
(void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
automount_stop_expire(a);
r = set_ensure_allocated(&a->expire_tokens, NULL);
if (r < 0) {
@ -1037,7 +1052,9 @@ static bool automount_supported(void) {
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
[AUTOMOUNT_FAILURE_RESOURCES] = "resources"
[AUTOMOUNT_FAILURE_RESOURCES] = "resources",
[AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
@ -1069,6 +1086,8 @@ const UnitVTable automount_vtable = {
.check_gc = automount_check_gc,
.trigger_notify = automount_trigger_notify,
.reset_failed = automount_reset_failed,
.bus_vtable = bus_automount_vtable,

View File

@ -26,6 +26,8 @@ typedef struct Automount Automount;
typedef enum AutomountResult {
AUTOMOUNT_SUCCESS,
AUTOMOUNT_FAILURE_RESOURCES,
AUTOMOUNT_FAILURE_START_LIMIT_HIT,
AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT,
_AUTOMOUNT_RESULT_MAX,
_AUTOMOUNT_RESULT_INVALID = -1
} AutomountResult;
@ -53,7 +55,5 @@ struct Automount {
extern const UnitVTable automount_vtable;
int automount_update_mount(Automount *a, MountState old_state, MountState state);
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;

View File

@ -607,6 +607,7 @@ fail:
static int busname_start(Unit *u) {
BusName *n = BUSNAME(u);
int r;
assert(n);
@ -632,6 +633,12 @@ static int busname_start(Unit *u) {
assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
r = unit_start_limit_test(u);
if (r < 0) {
busname_enter_dead(n, BUSNAME_FAILURE_START_LIMIT_HIT);
return r;
}
n->result = BUSNAME_SUCCESS;
busname_enter_making(n);
@ -1014,6 +1021,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_FAILURE_EXIT_CODE] = "exit-code",
[BUSNAME_FAILURE_SIGNAL] = "signal",
[BUSNAME_FAILURE_CORE_DUMP] = "core-dump",
[BUSNAME_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit",
};

View File

@ -32,6 +32,7 @@ typedef enum BusNameResult {
BUSNAME_FAILURE_EXIT_CODE,
BUSNAME_FAILURE_SIGNAL,
BUSNAME_FAILURE_CORE_DUMP,
BUSNAME_FAILURE_START_LIMIT_HIT,
BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT,
_BUSNAME_RESULT_MAX,
_BUSNAME_RESULT_INVALID = -1

View File

@ -584,23 +584,6 @@ static int mount_load(Unit *u) {
return mount_verify(m);
}
static int mount_notify_automount(Mount *m, MountState old_state, MountState state) {
Unit *p;
int r;
Iterator i;
assert(m);
SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
if (p->type == UNIT_AUTOMOUNT) {
r = automount_update_mount(AUTOMOUNT(p), old_state, state);
if (r < 0)
return r;
}
return 0;
}
static void mount_set_state(Mount *m, MountState state) {
MountState old_state;
assert(m);
@ -624,8 +607,6 @@ static void mount_set_state(Mount *m, MountState state) {
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
}
mount_notify_automount(m, old_state, state);
if (state != old_state)
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
@ -984,6 +965,7 @@ fail:
static int mount_start(Unit *u) {
Mount *m = MOUNT(u);
int r;
assert(m);
@ -1002,6 +984,12 @@ static int mount_start(Unit *u) {
assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
r = unit_start_limit_test(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
return r;
}
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
m->reset_cpu_usage = true;
@ -1821,7 +1809,8 @@ static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
[MOUNT_FAILURE_TIMEOUT] = "timeout",
[MOUNT_FAILURE_EXIT_CODE] = "exit-code",
[MOUNT_FAILURE_SIGNAL] = "signal",
[MOUNT_FAILURE_CORE_DUMP] = "core-dump"
[MOUNT_FAILURE_CORE_DUMP] = "core-dump",
[MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);

View File

@ -39,6 +39,7 @@ typedef enum MountResult {
MOUNT_FAILURE_EXIT_CODE,
MOUNT_FAILURE_SIGNAL,
MOUNT_FAILURE_CORE_DUMP,
MOUNT_FAILURE_START_LIMIT_HIT,
_MOUNT_RESULT_MAX,
_MOUNT_RESULT_INVALID = -1
} MountResult;

View File

@ -560,6 +560,7 @@ static void path_mkdir(Path *p) {
static int path_start(Unit *u) {
Path *p = PATH(u);
Unit *trigger;
int r;
assert(p);
assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
@ -570,6 +571,12 @@ static int path_start(Unit *u) {
return -ENOENT;
}
r = unit_start_limit_test(u);
if (r < 0) {
path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
return r;
}
path_mkdir(p);
p->result = PATH_SUCCESS;
@ -739,6 +746,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
static const char* const path_result_table[_PATH_RESULT_MAX] = {
[PATH_SUCCESS] = "success",
[PATH_FAILURE_RESOURCES] = "resources",
[PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);

View File

@ -62,6 +62,7 @@ static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
typedef enum PathResult {
PATH_SUCCESS,
PATH_FAILURE_RESOURCES,
PATH_FAILURE_START_LIMIT_HIT,
_PATH_RESULT_MAX,
_PATH_RESULT_INVALID = -1
} PathResult;

View File

@ -1957,6 +1957,7 @@ fail:
static int service_start(Unit *u) {
Service *s = SERVICE(u);
int r;
assert(s);
@ -1983,6 +1984,13 @@ static int service_start(Unit *u) {
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
/* Make sure we don't enter a busy loop of some kind. */
r = unit_start_limit_test(u);
if (r < 0) {
service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
return r;
}
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
s->main_pid_known = false;
@ -3266,6 +3274,7 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
[SERVICE_FAILURE_SIGNAL] = "signal",
[SERVICE_FAILURE_CORE_DUMP] = "core-dump",
[SERVICE_FAILURE_WATCHDOG] = "watchdog",
[SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);

View File

@ -86,6 +86,7 @@ typedef enum ServiceResult {
SERVICE_FAILURE_SIGNAL,
SERVICE_FAILURE_CORE_DUMP,
SERVICE_FAILURE_WATCHDOG,
SERVICE_FAILURE_START_LIMIT_HIT,
_SERVICE_RESULT_MAX,
_SERVICE_RESULT_INVALID = -1
} ServiceResult;

View File

@ -2057,6 +2057,7 @@ fail:
static int socket_start(Unit *u) {
Socket *s = SOCKET(u);
int r;
assert(s);
@ -2101,6 +2102,12 @@ static int socket_start(Unit *u) {
assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
r = unit_start_limit_test(u);
if (r < 0) {
socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
return r;
}
s->result = SOCKET_SUCCESS;
s->reset_cpu_usage = true;
@ -2735,17 +2742,26 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
assert(u);
assert(other);
/* Don't propagate state changes from the service if we are
already down or accepting connections */
if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept)
/* Filter out invocations with bogus state */
if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
return;
/* Don't propagate state changes from the service if we are already down */
if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING))
return;
/* We don't care for the service state if we are in Accept=yes mode */
if (s->accept)
return;
/* Propagate start limit hit state */
if (other->start_limit_hit) {
socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT);
return;
}
if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
/* Don't propagate anything if there's still a job queued */
if (other->job)
return;
if (IN_SET(SERVICE(other)->state,
@ -2818,6 +2834,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
[SOCKET_FAILURE_EXIT_CODE] = "exit-code",
[SOCKET_FAILURE_SIGNAL] = "signal",
[SOCKET_FAILURE_CORE_DUMP] = "core-dump",
[SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
[SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};

View File

@ -52,6 +52,7 @@ typedef enum SocketResult {
SOCKET_FAILURE_EXIT_CODE,
SOCKET_FAILURE_SIGNAL,
SOCKET_FAILURE_CORE_DUMP,
SOCKET_FAILURE_START_LIMIT_HIT,
SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
_SOCKET_RESULT_MAX,

View File

@ -814,6 +814,7 @@ fail:
static int swap_start(Unit *u) {
Swap *s = SWAP(u), *other;
int r;
assert(s);
@ -842,6 +843,12 @@ static int swap_start(Unit *u) {
if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
return -EAGAIN;
r = unit_start_limit_test(u);
if (r < 0) {
swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
return r;
}
s->result = SWAP_SUCCESS;
s->reset_cpu_usage = true;
@ -1447,7 +1454,8 @@ static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
[SWAP_FAILURE_TIMEOUT] = "timeout",
[SWAP_FAILURE_EXIT_CODE] = "exit-code",
[SWAP_FAILURE_SIGNAL] = "signal",
[SWAP_FAILURE_CORE_DUMP] = "core-dump"
[SWAP_FAILURE_CORE_DUMP] = "core-dump",
[SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);

View File

@ -38,6 +38,7 @@ typedef enum SwapResult {
SWAP_FAILURE_EXIT_CODE,
SWAP_FAILURE_SIGNAL,
SWAP_FAILURE_CORE_DUMP,
SWAP_FAILURE_START_LIMIT_HIT,
_SWAP_RESULT_MAX,
_SWAP_RESULT_INVALID = -1
} SwapResult;

View File

@ -599,6 +599,7 @@ static int timer_start(Unit *u) {
Timer *t = TIMER(u);
TimerValue *v;
Unit *trigger;
int r;
assert(t);
assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
@ -609,6 +610,12 @@ static int timer_start(Unit *u) {
return -ENOENT;
}
r = unit_start_limit_test(u);
if (r < 0) {
timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
return r;
}
t->last_trigger = DUAL_TIMESTAMP_NULL;
/* Reenable all timers that depend on unit activation time */
@ -808,7 +815,8 @@ DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
[TIMER_SUCCESS] = "success",
[TIMER_FAILURE_RESOURCES] = "resources"
[TIMER_FAILURE_RESOURCES] = "resources",
[TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);

View File

@ -48,6 +48,7 @@ typedef struct TimerValue {
typedef enum TimerResult {
TIMER_SUCCESS,
TIMER_FAILURE_RESOURCES,
TIMER_FAILURE_START_LIMIT_HIT,
_TIMER_RESULT_MAX,
_TIMER_RESULT_INVALID = -1
} TimerResult;

View File

@ -1462,7 +1462,7 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
unit_status_print_starting_stopping(u, t);
}
static int unit_start_limit_test(Unit *u) {
int unit_start_limit_test(Unit *u) {
assert(u);
if (ratelimit_test(&u->start_limit)) {
@ -1488,7 +1488,6 @@ static int unit_start_limit_test(Unit *u) {
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
int r;
assert(u);
@ -1541,11 +1540,6 @@ int unit_start(Unit *u) {
if (!UNIT_VTABLE(u)->start)
return -EBADR;
/* Make sure we don't enter a busy loop of some kind. */
r = unit_start_limit_test(u);
if (r < 0)
return r;
/* We don't suppress calls to ->start() here when we are
* already starting, to allow this request to be used as a
* "hurry up" call, for example when the unit is in some "auto
@ -2951,7 +2945,7 @@ int unit_coldplug(Unit *u) {
return 0;
}
static bool fragment_mtime_changed(const char *path, usec_t mtime) {
static bool fragment_mtime_newer(const char *path, usec_t mtime) {
struct stat st;
if (!path)
@ -2963,7 +2957,7 @@ static bool fragment_mtime_changed(const char *path, usec_t mtime) {
if (mtime > 0)
/* For non-empty files check the mtime */
return timespec_load(&st.st_mtim) != mtime;
return timespec_load(&st.st_mtim) > mtime;
else if (!null_or_empty(&st))
/* For masked files check if they are still so */
return true;
@ -2974,32 +2968,24 @@ static bool fragment_mtime_changed(const char *path, usec_t mtime) {
bool unit_need_daemon_reload(Unit *u) {
_cleanup_strv_free_ char **t = NULL;
char **path;
unsigned loaded_cnt, current_cnt;
assert(u);
if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) ||
fragment_mtime_changed(u->source_path, u->source_mtime))
if (fragment_mtime_newer(u->fragment_path, u->fragment_mtime))
return true;
if (fragment_mtime_newer(u->source_path, u->source_mtime))
return true;
(void) unit_find_dropin_paths(u, &t);
loaded_cnt = strv_length(t);
current_cnt = strv_length(u->dropin_paths);
if (!strv_equal(u->dropin_paths, t))
return true;
if (loaded_cnt == current_cnt) {
if (loaded_cnt == 0)
return false;
STRV_FOREACH(path, u->dropin_paths)
if (fragment_mtime_newer(*path, u->dropin_mtime))
return true;
if (strv_overlap(u->dropin_paths, t)) {
STRV_FOREACH(path, u->dropin_paths)
if (fragment_mtime_changed(*path, u->dropin_mtime))
return true;
return false;
}
}
return true;
return false;
}
void unit_reset_failed(Unit *u) {

View File

@ -611,6 +611,8 @@ static inline bool unit_supported(Unit *u) {
void unit_warn_if_dir_nonempty(Unit *u, const char* where);
int unit_fail_if_symlink(Unit *u, const char* where);
int unit_start_limit_test(Unit *u);
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \

View File

@ -379,6 +379,7 @@ static int add_mount(
}
fprintf(f,
"\n"
"[Automount]\n"
"Where=%s\n",
where);

View File

@ -2334,6 +2334,8 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
}
static void warn_unit_file_changed(const char *name) {
assert(name);
log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
ansi_highlight_red(),
ansi_normal(),