mount.c revision 7dfbe2e3fc0215b49d8202a32beb6b1aae08c4e4
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
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>
#include <stdio.h>
#include <signal.h>
#include <libmount.h>
#include "manager.h"
#include "unit.h"
#include "mount.h"
#include "log.h"
#include "sd-messages.h"
#include "strv.h"
#include "mkdir.h"
#include "path-util.h"
#include "mount-setup.h"
#include "unit-name.h"
#include "dbus-mount.h"
#include "special.h"
#include "exit-status.h"
#include "fstab-util.h"
#include "formats-util.h"
#define RETRY_UMOUNT_MAX 32
[MOUNT_DEAD] = UNIT_INACTIVE,
[MOUNT_MOUNTED] = UNIT_ACTIVE,
};
return true;
return true;
return false;
}
static bool mount_is_network(const MountParameters *p) {
assert(p);
}
static bool mount_is_bind(const MountParameters *p) {
assert(p);
return true;
return true;
return false;
}
static bool mount_is_auto(const MountParameters *p) {
assert(p);
}
static bool needs_quota(const MountParameters *p) {
assert(p);
/* Quotas are not enabled on network filesystems,
* but we want them, for example, on storage connected via iscsi */
return false;
if (mount_is_bind(p))
return false;
return fstab_test_option(p->options,
"usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0");
}
static void mount_init(Unit *u) {
assert(u);
m->directory_mode = 0755;
if (unit_has_name(u, "-.mount")) {
u->refuse_manual_start = true;
u->refuse_manual_stop = true;
} else {
* dep loop, don't use kmsg logging for -.mount */
}
* the same process group as us, so that the autofs kernel
* side doesn't send us another mount request while we are
* already trying to comply its last one. */
m->exec_context.same_pgrp = true;
u->ignore_on_isolate = true;
}
static int mount_arm_timer(Mount *m) {
int r;
assert(m);
if (m->timeout_usec <= 0) {
return 0;
}
if (m->timer_event_source) {
if (r < 0)
return r;
}
r = sd_event_add_time(
&m->timer_event_source,
mount_dispatch_timer, m);
if (r < 0)
return r;
return 0;
}
static void mount_unwatch_control_pid(Mount *m) {
assert(m);
if (m->control_pid <= 0)
return;
m->control_pid = 0;
}
static void mount_parameters_done(MountParameters *p) {
assert(p);
}
static void mount_done(Unit *u) {
assert(m);
m->control_command = NULL;
}
assert(m);
if (m->from_fragment)
return &m->parameters_fragment;
return NULL;
}
assert(m);
if (m->from_proc_self_mountinfo)
return &m->parameters_proc_self_mountinfo;
return get_mount_parameters_fragment(m);
}
static int mount_add_mount_links(Mount *m) {
Iterator i;
Set *s;
int r;
assert(m);
/* Adds in links to other mount points that might lie further
* up in the hierarchy */
if (r < 0)
return r;
if (r < 0)
return r;
}
/* Adds in links to other mount points that might be needed
* for the source path (if this is a bind mount) to be
* available. */
!mount_is_network(pm)) {
if (r < 0)
return r;
}
/* Adds in links to other units that use this path or paths
* further down in the hierarchy */
SET_FOREACH(other, s, i) {
continue;
continue;
if (r < 0)
return r;
if (UNIT(m)->fragment_path) {
/* If we have fragment configuration, then make this dependency required */
if (r < 0)
return r;
}
}
return 0;
}
static int mount_add_device_links(Mount *m) {
MountParameters *p;
bool device_wants_mount = false;
int r;
assert(m);
p = get_mount_parameters(m);
if (!p)
return 0;
if (!p->what)
return 0;
if (mount_is_bind(p))
return 0;
if (!is_device_path(p->what))
return 0;
return 0;
device_wants_mount = true;
if (r < 0)
return r;
return 0;
}
static int mount_add_quota_links(Mount *m) {
int r;
MountParameters *p;
assert(m);
return 0;
p = get_mount_parameters_fragment(m);
if (!p)
return 0;
if (!needs_quota(p))
return 0;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
if (r < 0)
return r;
return 0;
}
static bool should_umount(Mount *m) {
MountParameters *p;
return false;
p = get_mount_parameters(m);
!in_initrd())
return false;
return true;
}
static int mount_add_default_dependencies(Mount *m) {
MountParameters *p;
int r;
assert(m);
return 0;
/* We do not add any default dependencies to / and /usr, since
* they are guaranteed to stay mounted the whole time, since
* our system is on it. Also, don't bother with anything
* mounted below virtual file systems, it's also going to be
* virtual, and hence not worth the effort. */
return 0;
p = get_mount_parameters(m);
if (!p)
return 0;
if (mount_is_network(p)) {
} else {
}
if (r < 0)
return r;
if (after2) {
if (r < 0)
return r;
}
if (online) {
if (r < 0)
return r;
}
if (should_umount(m)) {
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
if (r < 0)
return r;
}
return 0;
}
static int mount_verify(Mount *m) {
_cleanup_free_ char *e = NULL;
bool b;
assert(m);
return 0;
if (!m->from_fragment && !m->from_proc_self_mountinfo)
return -ENOENT;
if (!e)
return -ENOMEM;
b = unit_has_name(UNIT(m), e);
if (!b) {
return -EINVAL;
}
log_unit_error(UNIT(m)->id, "Cannot create mount unit for API file system %s. Refusing.", m->where);
return -EINVAL;
}
return -EBADMSG;
}
log_unit_error(UNIT(m)->id, "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.",UNIT(m)->id);
return -EINVAL;
}
return 0;
}
static int mount_add_extras(Mount *m) {
int r;
assert(m);
if (u->fragment_path)
m->from_fragment = true;
if (!m->where) {
if (!m->where)
return -ENOMEM;
}
path_kill_slashes(m->where);
if (!u->description) {
r = unit_set_description(u, m->where);
if (r < 0)
return r;
}
r = mount_add_device_links(m);
if (r < 0)
return r;
r = mount_add_mount_links(m);
if (r < 0)
return r;
r = mount_add_quota_links(m);
if (r < 0)
return r;
r = unit_patch_contexts(u);
if (r < 0)
return r;
r = unit_add_exec_dependencies(u, &m->exec_context);
if (r < 0)
return r;
r = unit_add_default_slice(u, &m->cgroup_context);
if (r < 0)
return r;
if (u->default_dependencies) {
r = mount_add_default_dependencies(m);
if (r < 0)
return r;
}
return 0;
}
static int mount_load(Unit *u) {
int r;
assert(u);
if (m->from_proc_self_mountinfo)
else
r = unit_load_fragment_and_dropin(u);
if (r < 0)
return r;
/* This is a new unit? Then let's add in some extras */
if (u->load_state == UNIT_LOADED) {
r = mount_add_extras(m);
if (r < 0)
return r;
}
return mount_verify(m);
}
Unit *p;
int r;
Iterator i;
assert(m);
if (p->type == UNIT_AUTOMOUNT) {
if (r < 0)
return r;
}
return 0;
}
assert(m);
if (state != MOUNT_MOUNTING &&
state != MOUNT_MOUNTING_DONE &&
state != MOUNT_REMOUNTING &&
state != MOUNT_UNMOUNTING &&
state != MOUNT_MOUNTING_SIGTERM &&
state != MOUNT_MOUNTING_SIGKILL &&
m->control_command = NULL;
}
"%s changed %s -> %s",
unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
m->reload_result = MOUNT_SUCCESS;
}
static int mount_coldplug(Unit *u) {
int r;
assert(m);
if (m->deserialized_state != m->state)
new_state = m->deserialized_state;
else if (m->from_proc_self_mountinfo)
return 0;
if (new_state == MOUNT_MOUNTING ||
new_state == MOUNT_MOUNTING_DONE ||
new_state == MOUNT_REMOUNTING ||
new_state == MOUNT_UNMOUNTING ||
if (m->control_pid <= 0)
return -EBADMSG;
if (r < 0)
return r;
r = mount_arm_timer(m);
if (r < 0)
return r;
}
mount_set_state(m, new_state);
return 0;
}
MountParameters *p;
assert(m);
assert(f);
p = get_mount_parameters(m);
fprintf(f,
"%sMount State: %s\n"
"%sResult: %s\n"
"%sWhere: %s\n"
"%sWhat: %s\n"
"%sFile System Type: %s\n"
"%sOptions: %s\n"
"%sFrom fragment: %s\n"
"%sDirectoryMode: %04o\n",
prefix, m->directory_mode);
if (m->control_pid > 0)
fprintf(f,
prefix, m->control_pid);
}
int r;
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
};
assert(m);
assert(c);
(void) unit_realize_cgroup(UNIT(m));
if (m->reset_cpu_usage) {
(void) unit_reset_cpu_usage(UNIT(m));
m->reset_cpu_usage = false;
}
r = unit_setup_exec_runtime(UNIT(m));
if (r < 0)
goto fail;
r = mount_arm_timer(m);
if (r < 0)
goto fail;
r = exec_spawn(c,
&m->exec_context,
m->exec_runtime,
&pid);
if (r < 0)
goto fail;
if (r < 0)
/* FIXME: we need to do something here */
goto fail;
return 0;
fail:
return r;
}
assert(m);
if (f != MOUNT_SUCCESS)
m->result = f;
exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager));
}
assert(m);
if (f != MOUNT_SUCCESS)
m->result = f;
}
int r;
assert(m);
if (f != MOUNT_SUCCESS)
m->result = f;
r = unit_kill_context(
UNIT(m),
&m->kill_context,
(state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM) ?
-1,
m->control_pid,
false);
if (r < 0)
goto fail;
if (r > 0) {
r = mount_arm_timer(m);
if (r < 0)
goto fail;
mount_set_state(m, state);
} else if (state == MOUNT_REMOUNTING_SIGTERM)
else if (state == MOUNT_REMOUNTING_SIGKILL)
else if (state == MOUNT_MOUNTING_SIGTERM)
else if (state == MOUNT_UNMOUNTING_SIGTERM)
else
return;
fail:
else
}
int r;
r = dir_is_empty(where);
if (r > 0)
return;
else if (r == 0)
LOG_MESSAGE("%s: Directory %s to mount over is not empty, mounting anyway.",
"WHERE=%s", where,
NULL);
else
"MESSAGE=Failed to check directory %s: %s",
}
if (is_symlink(where) > 0) {
LOG_MESSAGE("%s: Mount on symlink %s not allowed.",
"WHERE=%s", where,
NULL);
return -ELOOP;
}
return 0;
}
static void mount_enter_unmounting(Mount *m) {
int r;
assert(m);
/* Start counting our attempts */
m->n_retry_umount = 0;
if (r < 0)
goto fail;
if (r < 0)
goto fail;
return;
fail:
"%s failed to run 'umount' task: %s",
}
static void mount_enter_mounting(Mount *m) {
int r;
MountParameters *p;
assert(m);
/* Create the source directory for bind-mounts if needed */
p = get_mount_parameters_fragment(m);
if (p && mount_is_bind(p))
if (r < 0)
goto fail;
if (m->from_fragment) {
if (r < 0)
goto fail;
if (r >= 0 && m->sloppy_options)
if (r >= 0 && m->parameters_fragment.fstype)
} else
r = -ENOENT;
if (r < 0)
goto fail;
if (r < 0)
goto fail;
return;
fail:
"%s failed to run 'mount' task: %s",
}
static void mount_enter_remounting(Mount *m) {
int r;
assert(m);
if (m->from_fragment) {
const char *o;
if (m->parameters_fragment.options)
else
o = "remount";
"-o", o, NULL);
if (r >= 0 && m->sloppy_options)
if (r >= 0 && m->parameters_fragment.fstype)
} else
r = -ENOENT;
if (r < 0)
goto fail;
if (r < 0)
goto fail;
return;
fail:
"%s failed to run 'remount' task: %s",
}
static int mount_start(Unit *u) {
assert(m);
/* We cannot fulfill this request right now, try again later
* please! */
if (m->state == MOUNT_UNMOUNTING ||
m->state == MOUNT_UNMOUNTING_SIGTERM ||
m->state == MOUNT_UNMOUNTING_SIGKILL ||
m->state == MOUNT_MOUNTING_SIGTERM ||
m->state == MOUNT_MOUNTING_SIGKILL)
return -EAGAIN;
/* Already on it! */
if (m->state == MOUNT_MOUNTING)
return 0;
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
m->reset_cpu_usage = true;
return 1;
}
static int mount_stop(Unit *u) {
assert(m);
/* Already on it */
if (m->state == MOUNT_UNMOUNTING ||
m->state == MOUNT_UNMOUNTING_SIGKILL ||
m->state == MOUNT_UNMOUNTING_SIGTERM ||
m->state == MOUNT_MOUNTING_SIGTERM ||
m->state == MOUNT_MOUNTING_SIGKILL)
return 0;
m->state == MOUNT_MOUNTING_DONE ||
m->state == MOUNT_MOUNTED ||
m->state == MOUNT_REMOUNTING ||
m->state == MOUNT_REMOUNTING_SIGTERM ||
m->state == MOUNT_REMOUNTING_SIGKILL);
return 1;
}
static int mount_reload(Unit *u) {
assert(m);
if (m->state == MOUNT_MOUNTING_DONE)
return -EAGAIN;
return 0;
}
assert(m);
assert(f);
if (m->control_pid > 0)
if (m->control_command_id >= 0)
return 0;
}
assert(u);
else
m->deserialized_state = state;
MountResult f;
if (f < 0)
"Failed to parse result value %s", value);
else if (f != MOUNT_SUCCESS)
m->result = f;
MountResult f;
if (f < 0)
"Failed to parse reload result value %s", value);
else if (f != MOUNT_SUCCESS)
m->reload_result = f;
"Failed to parse control-pid value %s", value);
else
m->control_pid = pid;
"Failed to parse exec-command value %s", value);
else {
m->control_command_id = id;
}
} else
"Unknown serialization key '%s'", key);
return 0;
}
assert(u);
}
assert(u);
}
assert(m);
return m->from_proc_self_mountinfo;
}
MountResult f;
assert(m);
if (pid != m->control_pid)
return;
m->control_pid = 0;
f = MOUNT_SUCCESS;
else if (code == CLD_EXITED)
else if (code == CLD_KILLED)
f = MOUNT_FAILURE_SIGNAL;
else if (code == CLD_DUMPED)
else
assert_not_reached("Unknown code");
if (f != MOUNT_SUCCESS)
m->result = f;
if (m->control_command) {
m->control_command = NULL;
}
log_unit_full(u->id,
"%s mount process exited, code=%s status=%i",
/* Note that mount(8) returning and the kernel sending us a
* mount table change event might happen out-of-order. If an
* operation succeed we assume the kernel will follow soon too
* and already change into the resulting state. If it fails
* we check if the kernel still knows about the mount. and
* change state accordingly. */
switch (m->state) {
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_MOUNTING_SIGTERM:
if (f == MOUNT_SUCCESS)
mount_enter_mounted(m, f);
else if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, f);
else
mount_enter_dead(m, f);
break;
case MOUNT_REMOUNTING:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGTERM:
m->reload_result = f;
if (m->from_proc_self_mountinfo)
else
break;
case MOUNT_UNMOUNTING:
case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
if (f == MOUNT_SUCCESS) {
if (m->from_proc_self_mountinfo) {
/* Still a mount point? If so, let's
* try again. Most likely there were
* multiple mount points stacked on
* top of each other. Note that due to
* the io event priority logic we can
* be sure the new mountinfo is loaded
* before we process the SIGCHLD for
* the mount command. */
if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
m->n_retry_umount++;
} else {
log_unit_debug(u->id, "%s: mount still present after %u attempts to unmount, giving up.", u->id, m->n_retry_umount);
mount_enter_mounted(m, f);
}
} else
mount_enter_dead(m, f);
} else if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, f);
else
mount_enter_dead(m, f);
break;
default:
assert_not_reached("Uh, control process died at wrong time.");
}
/* Notify clients about changed exit status */
}
assert(m);
switch (m->state) {
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
break;
case MOUNT_REMOUNTING:
break;
case MOUNT_UNMOUNTING:
break;
case MOUNT_MOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
} else {
"%s mounting timed out. Skipping SIGKILL. Ignoring.",
if (m->from_proc_self_mountinfo)
else
}
break;
case MOUNT_REMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
} else {
"%s remounting timed out. Skipping SIGKILL. Ignoring.",
if (m->from_proc_self_mountinfo)
else
}
break;
case MOUNT_UNMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
} else {
"%s unmounting timed out. Skipping SIGKILL. Ignoring.",
if (m->from_proc_self_mountinfo)
else
}
break;
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGKILL:
"%s mount process still around after SIGKILL. Ignoring.",
if (m->from_proc_self_mountinfo)
else
break;
default:
assert_not_reached("Timeout at wrong time.");
}
return 0;
}
static int mount_setup_unit(
Manager *m,
const char *what,
const char *where,
const char *options,
const char *fstype,
bool set_flags) {
bool load_extras = false;
MountParameters *p;
Unit *u;
int r;
assert(m);
/* Ignore API mount points. They should never be referenced in
* dependencies ever. */
return 0;
return 0;
/* probably some kind of swap, ignore */
return 0;
if (!e)
return -ENOMEM;
u = manager_get_unit(m, e);
if (!u) {
delete = true;
if (!u)
return log_oom();
r = unit_add_name(u, e);
if (r < 0)
goto fail;
r = -ENOMEM;
goto fail;
}
if (!u->source_path) {
r = -ENOMEM;
goto fail;
}
if (m->running_as == SYSTEMD_SYSTEM) {
const char* target;
if (r < 0)
goto fail;
if (should_umount(MOUNT(u))) {
if (r < 0)
goto fail;
}
}
changed = true;
} else {
delete = false;
r = -ENOMEM;
goto fail;
}
}
if (m->running_as == SYSTEMD_SYSTEM &&
/* _netdev option may have shown up late, or on a
* remount. Add remote-fs dependencies, even though
* local-fs ones may already be there. */
load_extras = true;
}
if (u->load_state == UNIT_NOT_FOUND) {
u->load_state = UNIT_LOADED;
u->load_error = 0;
/* Load in the extras later on, after we
* finished initialization of the unit */
load_extras = true;
changed = true;
}
}
if (!w || !o || !f) {
r = -ENOMEM;
goto fail;
}
p = &MOUNT(u)->parameters_proc_self_mountinfo;
if (set_flags) {
MOUNT(u)->is_mounted = true;
}
MOUNT(u)->from_proc_self_mountinfo = true;
p->what = w;
w = NULL;
p->options = o;
o = NULL;
p->fstype = f;
f = NULL;
if (load_extras) {
r = mount_add_extras(MOUNT(u));
if (r < 0)
goto fail;
}
if (changed)
return 0;
fail:
log_warning_errno(r, "Failed to set up mount unit: %m");
if (delete && u)
unit_free(u);
return r;
}
int r = 0;
assert(m);
t = mnt_new_table();
if (!t)
return log_oom();
i = mnt_new_iter(MNT_ITER_FORWARD);
if (!i)
return log_oom();
r = mnt_table_parse_mtab(t, NULL);
if (r < 0)
return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
r = 0;
for (;;) {
int k;
k = mnt_table_next_fs(t, i, &fs);
if (k == 1)
break;
if (k < 0)
return log_error_errno(k, "Failed to get next entry from /proc/self/mountinfo: %m");
return log_oom();
return log_oom();
if (r == 0 && k < 0)
r = k;
}
return r;
}
static void mount_shutdown(Manager *m) {
assert(m);
if (m->proc_self_mountinfo) {
m->proc_self_mountinfo = NULL;
}
}
int r;
if (!m->timer_event_source)
return 0;
if (r < 0)
return r;
return 1;
}
static int mount_enumerate(Manager *m) {
int r;
assert(m);
mnt_init_debug(0);
if (!m->proc_self_mountinfo) {
if (!m->proc_self_mountinfo)
return -errno;
r = sd_event_add_io(m->event, &m->mount_event_source, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m);
if (r < 0)
goto fail;
/* Dispatch this before we dispatch SIGCHLD, so that
if (r < 0)
goto fail;
}
if (m->utab_inotify_fd < 0) {
if (m->utab_inotify_fd < 0) {
r = -errno;
goto fail;
}
if (r < 0) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m);
if (r < 0)
goto fail;
if (r < 0)
goto fail;
}
r = mount_load_proc_self_mountinfo(m, false);
if (r < 0)
goto fail;
return 0;
fail:
mount_shutdown(m);
return r;
}
Unit *u;
int r;
assert(m);
/* The manager calls this for every fd event happening on the
* for mount options. */
if (fd == m->utab_inotify_fd) {
bool rescan = false;
/* FIXME: We *really* need to replace this with
* libmount's own API for this, we should not hardcode
* internal behaviour of libmount here. */
for (;;) {
union inotify_event_buffer buffer;
struct inotify_event *e;
ssize_t l;
if (l < 0) {
break;
break;
}
FOREACH_INOTIFY_EVENT(e, buffer, l) {
/* Only care about changes to utab,
* but we have to monitor the
* directory to reliably get
* notifications about when utab is
* replaced using rename(2) */
rescan = true;
}
}
if (!rescan)
return 0;
}
r = mount_load_proc_self_mountinfo(m, true);
if (r < 0) {
/* Reset flags, just in case, for later calls */
}
return 0;
}
if (!mount->is_mounted) {
mount->from_proc_self_mountinfo = false;
case MOUNT_MOUNTED:
/* This has just been unmounted by
* somebody else, follow the state
* change. */
break;
default:
break;
}
(void) device_found_node(m, mount->parameters_proc_self_mountinfo.what, false, DEVICE_FOUND_MOUNT, true);
/* New or changed mount entry */
case MOUNT_DEAD:
case MOUNT_FAILED:
/* This has just been mounted by
* somebody else, follow the state
* change. */
break;
case MOUNT_MOUNTING:
break;
default:
/* Nothing really changed, but let's
* issue an notification call
* nonetheless, in case somebody is
* waiting for this. (e.g. file system
break;
}
}
/* Reset the flags for later calls */
}
return 0;
}
static void mount_reset_failed(Unit *u) {
assert(m);
if (m->state == MOUNT_FAILED)
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
}
}
static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
[MOUNT_DEAD] = "dead",
[MOUNT_MOUNTING] = "mounting",
[MOUNT_MOUNTING_DONE] = "mounting-done",
[MOUNT_MOUNTED] = "mounted",
[MOUNT_REMOUNTING] = "remounting",
[MOUNT_UNMOUNTING] = "unmounting",
[MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
[MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
[MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
[MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
[MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
[MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
[MOUNT_FAILED] = "failed"
};
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
[MOUNT_EXEC_REMOUNT] = "ExecRemount",
};
static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
[MOUNT_SUCCESS] = "success",
[MOUNT_FAILURE_RESOURCES] = "resources",
[MOUNT_FAILURE_TIMEOUT] = "timeout",
[MOUNT_FAILURE_EXIT_CODE] = "exit-code",
[MOUNT_FAILURE_SIGNAL] = "signal",
[MOUNT_FAILURE_CORE_DUMP] = "core-dump"
};
const UnitVTable mount_vtable = {
.object_size = sizeof(Mount),
.sections =
"Unit\0"
"Mount\0"
"Install\0",
.private_section = "Mount",
.no_alias = true,
.no_instances = true,
.init = mount_init,
.load = mount_load,
.done = mount_done,
.dump = mount_dump,
.start = mount_start,
.stop = mount_stop,
.reload = mount_reload,
.kill = mount_kill,
.bus_interface = "org.freedesktop.systemd1.Mount",
.can_transient = true,
.starting_stopping = {
[0] = "Mounting %s...",
[1] = "Unmounting %s...",
},
.finished_start_job = {
[JOB_DONE] = "Mounted %s.",
[JOB_FAILED] = "Failed to mount %s.",
[JOB_DEPENDENCY] = "Dependency failed for %s.",
[JOB_TIMEOUT] = "Timed out mounting %s.",
},
.finished_stop_job = {
[JOB_DONE] = "Unmounted %s.",
[JOB_FAILED] = "Failed unmounting %s.",
[JOB_TIMEOUT] = "Timed out unmounting %s.",
},
},
};