automount.c revision 3dbadf9ef96e76f1bc472660ba5435dc0fa27a66
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering/***
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering This file is part of systemd.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Copyright 2010 Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering systemd is free software; you can redistribute it and/or modify it
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering under the terms of the GNU Lesser General Public License as published by
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering (at your option) any later version.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering systemd is distributed in the hope that it will be useful, but
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Lesser General Public License for more details.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering You should have received a copy of the GNU Lesser General Public License
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering***/
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
b4bbcaa9c44260e88402cb8f9a5fb8ac7f35e123Thomas Hindoe Paaboel Andersen#include <errno.h>
b4bbcaa9c44260e88402cb8f9a5fb8ac7f35e123Thomas Hindoe Paaboel Andersen#include <limits.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <sys/mount.h>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include <unistd.h>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include <fcntl.h>
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering#include <sys/epoll.h>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include <sys/stat.h>
4e731273edfe852a3eee2949cd20f49fd5b4f6d7Lennart Poettering#include <linux/auto_fs4.h>
4e731273edfe852a3eee2949cd20f49fd5b4f6d7Lennart Poettering#include <linux/auto_dev-ioctl.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek#include "unit.h"
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include "automount.h"
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering#include "mount.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "unit-name.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "special.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "label.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "mkdir.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "path-util.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "dbus-automount.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "bus-util.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "bus-error.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "formats-util.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "process-util.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering#include "async.h"
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering [AUTOMOUNT_FAILED] = UNIT_FAILED
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering};
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstruct expire_data {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int dev_autofs_fd;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int ioctl_fd;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering};
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic inline void expire_data_free(struct expire_data *data) {
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (!data)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering safe_close(data->dev_autofs_fd);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering safe_close(data->ioctl_fd);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(data);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int open_dev_autofs(Manager *m);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic void automount_init(Unit *u) {
39883f622f392d8579f4428fc5a789a102efbb10Lennart Poettering Automount *a = AUTOMOUNT(u);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(u);
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek assert(u->load_state == UNIT_STUB);
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->pipe_fd = -1;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->directory_mode = 0755;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering UNIT(a)->ignore_on_isolate = true;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic void repeat_unmount(const char *path) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(path);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering for (;;) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* If there are multiple mounts on a mount point, this
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * removes them all */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (umount2(path, MNT_DETACH) >= 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering continue;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (errno != EINVAL)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering log_error_errno(errno, "Failed to unmount: %m");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering break;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int automount_send_ready(Automount *a, Set *tokens, int status);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic void unmount_autofs(Automount *a) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (a->pipe_fd < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering automount_send_ready(a, a->tokens, -EHOSTDOWN);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->pipe_fd = safe_close(a->pipe_fd);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* If we reload/reexecute things we keep the mount point
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering * around */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (a->where &&
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering (UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering repeat_unmount(a->where);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic void automount_done(Unit *u) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering Automount *a = AUTOMOUNT(u);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering unmount_autofs(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering free(a->where);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->where = NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering set_free(a->tokens);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->tokens = NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering set_free(a->expire_tokens);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->expire_tokens = NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->expire_event_source = sd_event_source_unref(a->expire_event_source);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int automount_add_mount_links(Automount *a) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering _cleanup_free_ char *parent = NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = path_get_parent(a->where, &parent);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return unit_require_mounts_for(UNIT(a), parent);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int automount_add_default_dependencies(Automount *a) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int automount_verify(Automount *a) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering _cleanup_free_ char *e = NULL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering int r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (UNIT(a)->load_state != UNIT_LOADED)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (path_equal(a->where, "/")) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing.");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return -EINVAL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = unit_name_from_path(a->where, ".automount", &e);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m");
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (!unit_has_name(UNIT(a), e)) {
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return -EINVAL;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering }
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return 0;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int automount_load(Unit *u) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering Automount *a = AUTOMOUNT(u);
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek int r;
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek assert(u);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(u->load_state == UNIT_STUB);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering /* Load a .automount file */
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering r = unit_load_fragment_and_dropin_optional(u);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (r < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return r;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler if (u->load_state == UNIT_LOADED) {
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett Unit *x;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler if (!a->where) {
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett r = unit_name_to_path(u->id, &a->where);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (r < 0)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return r;
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering }
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett path_kill_slashes(a->where);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler r = unit_load_related_unit(u, ".mount", &x);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (r < 0)
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt return r;
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering if (r < 0)
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering return r;
c7fdf44d08e1217d40dc092fb90a65978a0f541fLennart Poettering
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler r = automount_add_mount_links(a);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (r < 0)
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett return r;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler if (UNIT(a)->default_dependencies) {
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler r = automount_add_default_dependencies(a);
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler if (r < 0)
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return r;
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov }
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov }
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return automount_verify(a);
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler}
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirovstatic void automount_set_state(Automount *a, AutomountState state) {
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler AutomountState old_state;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler assert(a);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt old_state = a->state;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett a->state = state;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (state != AUTOMOUNT_WAITING &&
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov state != AUTOMOUNT_RUNNING)
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov unmount_autofs(a);
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov if (state != old_state)
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));
4cd2b2cf8ca585d15ebc859701b346658262b5bbDenis Tikhomirov
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett}
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplettstatic int automount_coldplug(Unit *u) {
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett Automount *a = AUTOMOUNT(u);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett int r;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett assert(a);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett assert(a->state == AUTOMOUNT_DEAD);
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula if (a->deserialized_state != a->state) {
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula r = open_dev_autofs(u->manager);
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula if (r < 0)
0c9d8f1d4b5018199cb5a9b57580dc1480a7f915Jani Nikula return r;
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett if (a->deserialized_state == AUTOMOUNT_WAITING ||
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett a->deserialized_state == AUTOMOUNT_RUNNING) {
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett assert(a->pipe_fd >= 0);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (r < 0)
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return r;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering }
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering automount_set_state(a, a->deserialized_state);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering }
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return 0;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering}
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringstatic void automount_dump(Unit *u, FILE *f, const char *prefix) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering char time_string[FORMAT_TIMESPAN_MAX];
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering Automount *a = AUTOMOUNT(u);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering assert(a);
ef5bfcf668e6029faa78534dfeb2591df854cdefLennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering fprintf(f,
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt "%sAutomount State: %s\n"
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek "%sResult: %s\n"
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering "%sWhere: %s\n"
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering "%sDirectoryMode: %04o\n"
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering "%sTimeoutIdleUSec: %s\n",
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering prefix, automount_state_to_string(a->state),
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek prefix, automount_result_to_string(a->result),
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek prefix, a->where,
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering prefix, a->directory_mode,
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmekstatic void automount_enter_dead(Automount *a, AutomountResult f) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(a);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (f != AUTOMOUNT_SUCCESS)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering a->result = f;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering}
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poetteringstatic int open_dev_autofs(Manager *m) {
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering struct autofs_dev_ioctl param;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(m);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (m->dev_autofs_fd >= 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return m->dev_autofs_fd;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
875c6e1b48f37a07dfbb80d6653c73f205e94260Lennart Poettering label_fix("/dev/autofs", false, false);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (m->dev_autofs_fd < 0)
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt return log_error_errno(errno, "Failed to open /dev/autofs: %m");
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering init_autofs_dev_ioctl(&param);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return -errno;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering }
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler return m->dev_autofs_fd;
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler}
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächlerstatic int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
3cadce7d33e263ec7a6a83c00c11144930258b22Thomas Bächler struct autofs_dev_ioctl *param;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering size_t l;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering assert(dev_autofs_fd >= 0);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering assert(where);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering param = alloca(l);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering init_autofs_dev_ioctl(param);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering param->size = l;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering param->ioctlfd = -1;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering param->openmount.devid = devid;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering strcpy(param->path, where);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0)
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return -errno;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering if (param->ioctlfd < 0)
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return -EIO;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering (void) fd_cloexec(param->ioctlfd, true);
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering return param->ioctlfd;
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering}
be3f52f4ed02a9256b1577719677b32a17b525acLennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringstatic int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek uint32_t major, minor;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek struct autofs_dev_ioctl param;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering assert(dev_autofs_fd >= 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(ioctl_fd >= 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering init_autofs_dev_ioctl(&param);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering param.ioctlfd = ioctl_fd;
73e231abde39f22097df50542c745e01de879836Jan Engelhardt
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering return -errno;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering major = param.protover.version;
b76388e123e8d73ded1fd53937d816b314948517Michael Biebl
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering init_autofs_dev_ioctl(&param);
bca81be7755d15e7369d764bfa94a7ca6c595c76Topi Miettinen param.ioctlfd = ioctl_fd;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
934ae16baf543af03f3f521277d14524ca772d17Lennart Poettering if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
b76388e123e8d73ded1fd53937d816b314948517Michael Biebl return -errno;
b76388e123e8d73ded1fd53937d816b314948517Michael Biebl
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering minor = param.protosubver.sub_version;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering log_debug("Autofs protocol version %i.%i", major, minor);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return 0;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering}
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmekstatic int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek struct autofs_dev_ioctl param;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt assert(dev_autofs_fd >= 0);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek assert(ioctl_fd >= 0);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering init_autofs_dev_ioctl(&param);
bca81be7755d15e7369d764bfa94a7ca6c595c76Topi Miettinen param.ioctlfd = ioctl_fd;
bca81be7755d15e7369d764bfa94a7ca6c595c76Topi Miettinen
bca81be7755d15e7369d764bfa94a7ca6c595c76Topi Miettinen /* Convert to seconds, rounding up. */
7b909d7407965c03caaba30daae7aee113627a83Josh Triplett param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt return -errno;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return 0;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering}
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poetteringstatic int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering struct autofs_dev_ioctl param;
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(dev_autofs_fd >= 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering assert(ioctl_fd >= 0);
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering
0f4ba83c397e807939a4eb0b2cbd04ad4ab548ccLennart Poettering init_autofs_dev_ioctl(&param);
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering param.ioctlfd = ioctl_fd;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
938d2699d2e818bd996614e89ea3d668200ad2a8Zbigniew Jędrzejewski-Szmek if (status) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek param.fail.token = token;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering param.fail.status = status;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering } else
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack param.ready.token = token;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek return -errno;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering return 0;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering}
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmekstatic int automount_send_ready(Automount *a, Set *tokens, int status) {
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering _cleanup_close_ int ioctl_fd = -1;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering unsigned token;
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek int r;
3731acf1acfb4a6eb68374a5b137f3b368f63381Lennart Poettering
assert(a);
assert(status <= 0);
if (set_isempty(tokens))
return 0;
ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
if (ioctl_fd < 0)
return ioctl_fd;
if (status)
log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
else
log_unit_debug(UNIT(a), "Sending success.");
r = 0;
/* Autofs thankfully does not hand out 0 as a token */
while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
int k;
/* Autofs fun fact II:
*
* if you pass a positive status code here, the kernel will
* freeze! Yay! */
k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
ioctl_fd,
token,
status);
if (k < 0)
r = k;
}
return r;
}
static int automount_start_expire(Automount *a);
int automount_update_mount(Automount *a, MountState old_state, MountState state) {
int r;
assert(a);
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;
}
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;
}
return 0;
}
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
+ DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1];
bool mounted = false;
int r, dev_autofs_fd;
struct stat st;
assert(a);
assert(a->pipe_fd < 0);
assert(a->where);
set_clear(a->tokens);
r = unit_fail_if_symlink(UNIT(a), a->where);
if (r < 0)
goto fail;
(void) mkdir_p_label(a->where, 0555);
unit_warn_if_dir_nonempty(UNIT(a), a->where);
dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
if (dev_autofs_fd < 0) {
r = dev_autofs_fd;
goto fail;
}
if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
r = -errno;
goto fail;
}
xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
xsprintf(name, "systemd-"PID_FMT, getpid());
if (mount(name, a->where, "autofs", 0, options) < 0) {
r = -errno;
goto fail;
}
mounted = true;
p[1] = safe_close(p[1]);
if (stat(a->where, &st) < 0) {
r = -errno;
goto fail;
}
ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev);
if (ioctl_fd < 0) {
r = ioctl_fd;
goto fail;
}
r = autofs_protocol(dev_autofs_fd, ioctl_fd);
if (r < 0)
goto fail;
r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec);
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_description(a->pipe_event_source, "automount-io");
a->pipe_fd = p[0];
a->dev_id = st.st_dev;
automount_set_state(a, AUTOMOUNT_WAITING);
return;
fail:
safe_close_pair(p);
if (mounted)
repeat_unmount(a->where);
log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
static void *expire_thread(void *p) {
struct autofs_dev_ioctl param;
_cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p;
int r;
assert(data->dev_autofs_fd >= 0);
assert(data->ioctl_fd >= 0);
init_autofs_dev_ioctl(&param);
param.ioctlfd = data->ioctl_fd;
do {
r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, &param);
} while (r >= 0);
if (errno != EAGAIN)
log_warning_errno(errno, "Failed to expire automount, ignoring: %m");
return NULL;
}
static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
Automount *a = AUTOMOUNT(userdata);
_cleanup_(expire_data_freep) struct expire_data *data = NULL;
int r;
assert(a);
assert(source == a->expire_event_source);
data = new0(struct expire_data, 1);
if (!data)
return log_oom();
data->ioctl_fd = -1;
data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3);
if (data->dev_autofs_fd < 0)
return log_unit_error_errno(UNIT(a), errno, "Failed to duplicate autofs fd: %m");
data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
if (data->ioctl_fd < 0)
return log_unit_error_errno(UNIT(a), data->ioctl_fd, "Couldn't open autofs ioctl fd: %m");
r = asynchronous_job(expire_thread, data);
if (r < 0)
return log_unit_error_errno(UNIT(a), r, "Failed to start expire job: %m");
data = NULL;
return automount_start_expire(a);
}
static int automount_start_expire(Automount *a) {
int r;
usec_t timeout;
assert(a);
if (a->timeout_idle_usec == 0)
return 0;
timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC);
if (a->expire_event_source) {
r = sd_event_source_set_time(a->expire_event_source, timeout);
if (r < 0)
return r;
return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
}
r = sd_event_add_time(
UNIT(a)->manager->event,
&a->expire_event_source,
CLOCK_MONOTONIC, timeout, 0,
automount_dispatch_expire, a);
if (r < 0)
return r;
(void) sd_event_source_set_description(a->expire_event_source, "automount-expire");
return 0;
}
static void automount_enter_runnning(Automount *a) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
struct stat st;
int r;
assert(a);
/* We don't take mount requests anymore if we are supposed to
* shut down anyway */
if (unit_stop_pending(UNIT(a))) {
log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
automount_send_ready(a, a->tokens, -EHOSTDOWN);
automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
return;
}
mkdir_p_label(a->where, a->directory_mode);
/* 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 active?");
else {
r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
JOB_REPLACE, true, &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);
return;
fail:
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
static int automount_start(Unit *u) {
Automount *a = AUTOMOUNT(u);
assert(a);
assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
if (path_is_mount_point(a->where, 0) > 0) {
log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
return -EEXIST;
}
if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
return -ENOENT;
a->result = AUTOMOUNT_SUCCESS;
automount_enter_waiting(a);
return 1;
}
static int automount_stop(Unit *u) {
Automount *a = AUTOMOUNT(u);
assert(a);
assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
automount_enter_dead(a, AUTOMOUNT_SUCCESS);
return 1;
}
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
Automount *a = AUTOMOUNT(u);
void *p;
Iterator i;
assert(a);
assert(f);
assert(fds);
unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
unit_serialize_item(u, f, "result", automount_result_to_string(a->result));
unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
SET_FOREACH(p, a->tokens, i)
unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
SET_FOREACH(p, a->expire_tokens, i)
unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
if (a->pipe_fd >= 0) {
int copy;
copy = fdset_put_dup(fds, a->pipe_fd);
if (copy < 0)
return copy;
unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
}
return 0;
}
static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
Automount *a = AUTOMOUNT(u);
int r;
assert(a);
assert(fds);
if (streq(key, "state")) {
AutomountState state;
state = automount_state_from_string(value);
if (state < 0)
log_unit_debug(u, "Failed to parse state value: %s", value);
else
a->deserialized_state = state;
} else if (streq(key, "result")) {
AutomountResult f;
f = automount_result_from_string(value);
if (f < 0)
log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != AUTOMOUNT_SUCCESS)
a->result = f;
} else if (streq(key, "dev-id")) {
unsigned d;
if (safe_atou(value, &d) < 0)
log_unit_debug(u, "Failed to parse dev-id value: %s", value);
else
a->dev_id = (unsigned) d;
} else if (streq(key, "token")) {
unsigned token;
if (safe_atou(value, &token) < 0)
log_unit_debug(u, "Failed to parse token value: %s", value);
else {
r = set_ensure_allocated(&a->tokens, NULL);
if (r < 0) {
log_oom();
return 0;
}
r = set_put(a->tokens, UINT_TO_PTR(token));
if (r < 0)
log_unit_error_errno(u, r, "Failed to add token to set: %m");
}
} else if (streq(key, "expire-token")) {
unsigned token;
if (safe_atou(value, &token) < 0)
log_unit_debug(u, "Failed to parse token value: %s", value);
else {
r = set_ensure_allocated(&a->expire_tokens, NULL);
if (r < 0) {
log_oom();
return 0;
}
r = set_put(a->expire_tokens, UINT_TO_PTR(token));
if (r < 0)
log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
}
} else if (streq(key, "pipe-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse pipe-fd value: %s", value);
else {
safe_close(a->pipe_fd);
a->pipe_fd = fdset_remove(fds, fd);
}
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
static UnitActiveState automount_active_state(Unit *u) {
assert(u);
return state_translation_table[AUTOMOUNT(u)->state];
}
static const char *automount_sub_state_to_string(Unit *u) {
assert(u);
return automount_state_to_string(AUTOMOUNT(u)->state);
}
static bool automount_check_gc(Unit *u) {
assert(u);
if (!UNIT_TRIGGER(u))
return false;
return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u));
}
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
union autofs_v5_packet_union packet;
Automount *a = AUTOMOUNT(userdata);
struct stat st;
int r;
assert(a);
assert(fd == a->pipe_fd);
if (events != EPOLLIN) {
log_unit_error(UNIT(a), "Got invalid poll event %"PRIu32" on pipe (fd=%d)", events, fd);
goto fail;
}
r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
if (r < 0) {
log_unit_error_errno(UNIT(a), r, "Invalid read from pipe: %m");
goto fail;
}
switch (packet.hdr.type) {
case autofs_ptype_missing_direct:
if (packet.v5_packet.pid > 0) {
_cleanup_free_ char *p = NULL;
get_process_comm(packet.v5_packet.pid, &p);
log_unit_info(UNIT(a), "Got automount request for %s, triggered by %"PRIu32" (%s)", a->where, packet.v5_packet.pid, strna(p));
} else
log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);
r = set_ensure_allocated(&a->tokens, NULL);
if (r < 0) {
log_unit_error(UNIT(a), "Failed to allocate token set.");
goto fail;
}
r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
if (r < 0) {
log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
goto fail;
}
automount_enter_runnning(a);
break;
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);
r = set_ensure_allocated(&a->expire_tokens, NULL);
if (r < 0) {
log_unit_error(UNIT(a), "Failed to allocate token set.");
goto fail;
}
r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
if (r < 0) {
log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
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;
}
r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
if (r < 0) {
log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
goto fail;
}
break;
default:
log_unit_error(UNIT(a), "Received unknown automount request %i", packet.hdr.type);
break;
}
return 0;
fail:
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
return 0;
}
static void automount_shutdown(Manager *m) {
assert(m);
m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
}
static void automount_reset_failed(Unit *u) {
Automount *a = AUTOMOUNT(u);
assert(a);
if (a->state == AUTOMOUNT_FAILED)
automount_set_state(a, AUTOMOUNT_DEAD);
a->result = AUTOMOUNT_SUCCESS;
}
static bool automount_supported(void) {
static int supported = -1;
if (supported < 0)
supported = access("/dev/autofs", F_OK) >= 0;
return supported;
}
static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
[AUTOMOUNT_DEAD] = "dead",
[AUTOMOUNT_WAITING] = "waiting",
[AUTOMOUNT_RUNNING] = "running",
[AUTOMOUNT_FAILED] = "failed"
};
DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
[AUTOMOUNT_FAILURE_RESOURCES] = "resources"
};
DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
const UnitVTable automount_vtable = {
.object_size = sizeof(Automount),
.sections =
"Unit\0"
"Automount\0"
"Install\0",
.no_alias = true,
.no_instances = true,
.init = automount_init,
.load = automount_load,
.done = automount_done,
.coldplug = automount_coldplug,
.dump = automount_dump,
.start = automount_start,
.stop = automount_stop,
.serialize = automount_serialize,
.deserialize_item = automount_deserialize_item,
.active_state = automount_active_state,
.sub_state_to_string = automount_sub_state_to_string,
.check_gc = automount_check_gc,
.reset_failed = automount_reset_failed,
.bus_interface = "org.freedesktop.systemd1.Automount",
.bus_vtable = bus_automount_vtable,
.shutdown = automount_shutdown,
.supported = automount_supported,
.status_message_formats = {
.finished_start_job = {
[JOB_DONE] = "Set up automount %s.",
[JOB_FAILED] = "Failed to set up automount %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Unset automount %s.",
[JOB_FAILED] = "Failed to unset automount %s.",
},
},
};