+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
a->expire_event_source = sd_event_source_unref(a->expire_event_source);
}
-static int automount_add_mount_links(Automount *a) {
+static int automount_add_trigger_dependencies(Automount *a) {
+ Unit *x;
+ int r;
+
+ assert(a);
+
+ r = unit_load_related_unit(UNIT(a), ".mount", &x);
+ if (r < 0)
+ return r;
+
+ return unit_add_two_dependencies(UNIT(a), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
+}
+
+static int automount_add_mount_dependencies(Automount *a) {
_cleanup_free_ char *parent = NULL;
assert(a);
if (!parent)
return -ENOMEM;
- return unit_require_mounts_for(UNIT(a), parent);
+ return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT);
}
static int automount_add_default_dependencies(Automount *a) {
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
- r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
assert(u->load_state == UNIT_STUB);
/* Load a .automount file */
- r = unit_load_fragment_and_dropin_optional(u);
+ r = unit_load_fragment_and_dropin(u);
if (r < 0)
return r;
if (u->load_state == UNIT_LOADED) {
- Unit *x;
-
r = automount_set_where(a);
if (r < 0)
return r;
- r = unit_load_related_unit(u, ".mount", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
+ r = automount_add_trigger_dependencies(a);
if (r < 0)
return r;
- r = automount_add_mount_links(a);
+ r = automount_add_mount_dependencies(a);
if (r < 0)
return r;
if (state != AUTOMOUNT_RUNNING)
automount_stop_expire(a);
- if (state != AUTOMOUNT_WAITING &&
- state != AUTOMOUNT_RUNNING)
+ if (!IN_SET(state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
unmount_autofs(a);
if (state != old_state)
if (a->result == AUTOMOUNT_SUCCESS)
a->result = f;
+ if (a->result != AUTOMOUNT_SUCCESS)
+ log_unit_warning(UNIT(a), "Failed with result '%s'.", automount_result_to_string(a->result));
+
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
}
if (m->dev_autofs_fd >= 0)
return m->dev_autofs_fd;
- label_fix("/dev/autofs", false, false);
+ (void) label_fix("/dev/autofs", 0);
m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
if (m->dev_autofs_fd < 0)
init_autofs_dev_ioctl(¶m);
param.ioctlfd = ioctl_fd;
- /* Convert to seconds, rounding up. */
- param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC;
+ if (usec == USEC_INFINITY)
+ param.timeout.timeout = 0;
+ else
+ /* Convert to seconds, rounding up. */
+ param.timeout.timeout = DIV_ROUND_UP(usec, USEC_PER_SEC);
if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, ¶m) < 0)
return -errno;
while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
int k;
- /* Autofs fun fact II:
+ /* Autofs fun fact:
*
- * if you pass a positive status code here, the kernel will
- * freeze! Yay! */
+ * if you pass a positive status code here, kernels
+ * prior to 4.12 will freeze! Yay! */
k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
ioctl_fd,
if (IN_SET(MOUNT(other)->state,
MOUNT_MOUNTING, MOUNT_MOUNTING_DONE,
MOUNT_MOUNTED, MOUNT_REMOUNTING,
- MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
MOUNT_FAILED)) {
/* 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)) {
static void automount_enter_waiting(Automount *a) {
_cleanup_close_ int ioctl_fd = -1;
int p[2] = { -1, -1 };
- char name[sizeof("systemd-")-1 + DECIMAL_STR_MAX(pid_t) + 1];
- char options[sizeof("fd=,pgrp=,minproto=5,maxproto=5,direct")-1
+ char name[STRLEN("systemd-") + DECIMAL_STR_MAX(pid_t) + 1];
+ char options[STRLEN("fd=,pgrp=,minproto=5,maxproto=5,direct")
+ DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1];
bool mounted = false;
int r, dev_autofs_fd;
set_clear(a->tokens);
- r = unit_fail_if_symlink(UNIT(a), a->where);
+ r = unit_fail_if_noncanonical(UNIT(a), a->where);
if (r < 0)
goto fail;
}
xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
- xsprintf(name, "systemd-"PID_FMT, getpid());
+ xsprintf(name, "systemd-"PID_FMT, getpid_cached());
if (mount(name, a->where, "autofs", 0, options) < 0) {
r = -errno;
goto fail;
if (r < 0)
goto fail;
- /* Autofs fun fact:
- *
- * Unless we close the ioctl fd here, for some weird reason
- * the direct mount will not receive events from the
- * kernel. */
-
r = sd_event_add_io(UNIT(a)->manager->event, &a->pipe_event_source, p[0], EPOLLIN, automount_dispatch_io, a);
if (r < 0)
goto fail;
(void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
}
-static void automount_enter_runnning(Automount *a) {
+static void automount_enter_running(Automount *a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ Unit *trigger;
struct stat st;
int r;
goto fail;
}
- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
+ /* The mount unit may have been explicitly started before we got the
+ * autofs request. Ack it to unblock anything waiting on the mount point. */
+ if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) {
log_unit_info(UNIT(a), "Automount point already active?");
- else {
- Unit *trigger;
+ automount_send_ready(a, a->tokens, 0);
+ return;
+ }
- trigger = UNIT_TRIGGER(UNIT(a));
- if (!trigger) {
- log_unit_error(UNIT(a), "Unit to trigger vanished.");
- goto fail;
- }
+ trigger = UNIT_TRIGGER(UNIT(a));
+ if (!trigger) {
+ log_unit_error(UNIT(a), "Unit to trigger vanished.");
+ goto fail;
+ }
- r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
- if (r < 0) {
- log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
- goto fail;
- }
+ r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+ if (r < 0) {
+ log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
+ goto fail;
}
automount_set_state(a, AUTOMOUNT_RUNNING);
int r;
assert(a);
- assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
+ assert(IN_SET(a->state, AUTOMOUNT_DEAD, AUTOMOUNT_FAILED));
if (path_is_mount_point(a->where, NULL, 0) > 0) {
log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
Automount *a = AUTOMOUNT(u);
assert(a);
- assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
+ assert(IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING));
automount_enter_dead(a, AUTOMOUNT_SUCCESS);
return 1;
return automount_state_to_string(AUTOMOUNT(u)->state);
}
-static bool automount_check_gc(Unit *u) {
+static bool automount_may_gc(Unit *u) {
+ Unit *t;
+
assert(u);
- if (!UNIT_TRIGGER(u))
- return false;
+ t = UNIT_TRIGGER(u);
+ if (!t)
+ return true;
- return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u));
+ return UNIT_VTABLE(t)->may_gc(t);
}
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
union autofs_v5_packet_union packet;
Automount *a = AUTOMOUNT(userdata);
- struct stat st;
Unit *trigger;
int r;
goto fail;
}
- automount_enter_runnning(a);
+ automount_enter_running(a);
break;
case autofs_ptype_expire_direct:
goto fail;
}
- /* Before we do anything, let's see if somebody is playing games with us? */
- if (lstat(a->where, &st) < 0) {
- log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
- goto fail;
- }
-
- if (!S_ISDIR(st.st_mode) || st.st_dev == a->dev_id) {
- log_unit_info(UNIT(a), "Automount point already unmounted?");
- automount_send_ready(a, a->expire_tokens, 0);
- break;
- }
-
trigger = UNIT_TRIGGER(UNIT(a));
if (!trigger) {
log_unit_error(UNIT(a), "Unit to trigger vanished.");
.active_state = automount_active_state,
.sub_state_to_string = automount_sub_state_to_string,
- .check_gc = automount_check_gc,
+ .may_gc = automount_may_gc,
.trigger_notify = automount_trigger_notify,