mount.c revision 9d05dd2e1ef814a714214004f927ce82c9890fa6
/*-*- 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 <mntent.h>
#include <signal.h>
#include <libmount.h>
#include "manager.h"
#include "unit.h"
#include "mount.h"
#include "load-fragment.h"
#include "load-dropin.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 "bus-errors.h"
#include "exit-status.h"
#include "def.h"
[MOUNT_DEAD] = UNIT_INACTIVE,
[MOUNT_MOUNTED] = UNIT_ACTIVE,
};
return true;
return true;
return false;
}
static bool mount_is_network(MountParameters *p) {
assert(p);
}
static bool mount_is_bind(MountParameters *p) {
assert(p);
return true;
return true;
return true;
return true;
return false;
}
static bool mount_is_auto(MountParameters *p) {
assert(p);
}
static bool needs_quota(MountParameters *p) {
assert(p);
if (mount_is_network(p))
return false;
if (mount_is_bind(p))
return false;
}
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;
}
return sd_event_add_time(
&m->timer_event_source,
mount_dispatch_timer, m);
}
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_fragment(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;
p = get_mount_parameters(m);
if (!p)
return 0;
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;
}
if (state == MOUNT_MOUNTED ||
mount_notify_automount(m, 0);
else if (state == MOUNT_DEAD ||
state == MOUNT_UNMOUNTING ||
state == MOUNT_MOUNTING_SIGTERM ||
state == MOUNT_MOUNTING_SIGKILL ||
state == MOUNT_FAILED) {
mount_notify_automount(m, -ENODEV);
}
"%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);
unit_realize_cgroup(UNIT(m));
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);
if ((r = exec_command_set(
m->control_command,
"-n",
m->where,
NULL)) < 0)
goto fail;
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)
r = exec_command_set(
m->control_command,
m->where,
NULL);
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";
r = exec_command_set(
m->control_command,
m->where,
"-o", o,
NULL);
} 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;
return 0;
}
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 0;
}
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)
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_add_one(
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 -ENOMEM;
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:
if (delete && u)
unit_free(u);
return r;
}
mnt_free_table(*tb);
}
mnt_free_iter(*itr);
}
int r = 0;
assert(m);
tb = mnt_new_table();
return log_oom();
if (r)
return r;
int k;
if (!d || !p)
return log_oom();
if (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)
goto fail_with_errno;
if (r < 0)
goto fail_with_errno;
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;
r = -errno;
fail:
mount_shutdown(m);
return r;
}
Unit *u;
int r;
assert(m);
/* The manager calls this for every fd event happening on the
* table changes
if (fd == m->utab_inotify_fd) {
struct inotify_event *event;
char *p;
int rescan = 0;
for (p = inotify_buffer; p < inotify_buffer + r; ) {
event = (struct inotify_event *) p;
/* 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 = 1;
}
}
if (!rescan)
return 0;
}
r = mount_load_proc_self_mountinfo(m, true);
if (r < 0) {
log_error_errno(r, "Failed to reread /proc/self/mountinfo: %m");
/* 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;
}
/* 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.",
},
},
};