This file is part of systemd.
Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <stdio.h>
#include <sys/epoll.h>
+#include <libmount.h>
+
#include "sd-messages.h"
#include "alloc-util.h"
#include "dbus-mount.h"
+#include "device.h"
#include "escape.h"
#include "exit-status.h"
#include "format-util.h"
static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
[MOUNT_DEAD] = UNIT_INACTIVE,
[MOUNT_MOUNTING] = UNIT_ACTIVATING,
- [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE,
+ [MOUNT_MOUNTING_DONE] = UNIT_ACTIVATING,
[MOUNT_MOUNTED] = UNIT_ACTIVE,
[MOUNT_REMOUNTING] = UNIT_RELOADING,
[MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
assert(u->load_state == UNIT_STUB);
m->timeout_usec = u->manager->default_timeout_start_usec;
+
+ m->exec_context.std_output = u->manager->default_std_output;
+ m->exec_context.std_error = u->manager->default_std_error;
+
m->directory_mode = 0755;
/* We need to make sure that /usr/bin/mount is always called
mount_parameters_done(&m->parameters_proc_self_mountinfo);
mount_parameters_done(&m->parameters_fragment);
- m->exec_runtime = exec_runtime_unref(m->exec_runtime);
+ m->exec_runtime = exec_runtime_unref(m->exec_runtime, false);
exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
m->control_command = NULL;
return r;
}
- path_kill_slashes(m->where);
+ path_simplify(m->where, false);
if (!u->description) {
r = unit_set_description(u, m->where);
return r;
}
- if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED))
+ if (!IN_SET(new_state, MOUNT_DEAD, MOUNT_FAILED)) {
(void) unit_setup_dynamic_creds(u);
+ (void) unit_setup_exec_runtime(u);
+ }
mount_set_state(m, new_state);
return 0;
}
static void mount_dump(Unit *u, FILE *f, const char *prefix) {
+ char buf[FORMAT_TIMESPAN_MAX];
Mount *m = MOUNT(u);
MountParameters *p;
"%sDirectoryMode: %04o\n"
"%sSloppyOptions: %s\n"
"%sLazyUnmount: %s\n"
- "%sForceUnmount: %s\n",
+ "%sForceUnmount: %s\n"
+ "%sTimoutSec: %s\n",
prefix, mount_state_to_string(m->state),
prefix, mount_result_to_string(m->result),
prefix, m->where,
prefix, m->directory_mode,
prefix, yes_no(m->sloppy_options),
prefix, yes_no(m->lazy_unmount),
- prefix, yes_no(m->force_unmount));
+ prefix, yes_no(m->force_unmount),
+ prefix, format_timespan(buf, sizeof(buf), m->timeout_usec, USEC_PER_SEC));
if (m->control_pid > 0)
fprintf(f,
}
static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
- pid_t pid;
- int r;
+
ExecParameters exec_params = {
.flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
};
+ pid_t pid;
+ int r;
assert(m);
assert(c);
assert(_pid);
- (void) unit_realize_cgroup(UNIT(m));
- if (m->reset_accounting) {
- (void) unit_reset_cpu_accounting(UNIT(m));
- (void) unit_reset_ip_accounting(UNIT(m));
- m->reset_accounting = false;
- }
-
- unit_export_state_files(UNIT(m));
-
- r = unit_setup_exec_runtime(UNIT(m));
- if (r < 0)
- return r;
-
- r = unit_setup_dynamic_creds(UNIT(m));
+ r = unit_prepare_exec(UNIT(m));
if (r < 0)
return r;
if (r < 0)
return r;
- manager_set_exec_params(UNIT(m)->manager, &exec_params);
unit_set_exec_params(UNIT(m), &exec_params);
r = exec_spawn(UNIT(m),
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
- exec_runtime_destroy(m->exec_runtime);
- m->exec_runtime = exec_runtime_unref(m->exec_runtime);
+ m->exec_runtime = exec_runtime_unref(m->exec_runtime, true);
exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
assert(m);
- m->control_command_id = MOUNT_EXEC_MOUNT;
- m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
-
- r = unit_fail_if_symlink(UNIT(m), m->where);
+ r = unit_fail_if_noncanonical(UNIT(m), m->where);
if (r < 0)
goto fail;
unit_warn_if_dir_nonempty(UNIT(m), m->where);
+ unit_warn_leftover_processes(UNIT(m));
+
+ m->control_command_id = MOUNT_EXEC_MOUNT;
+ m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
+
/* Create the source directory for bind-mounts if needed */
p = get_mount_parameters_fragment(m);
if (p && mount_is_bind(p))
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
- m->reset_accounting = true;
+
+ u->reset_accounting = true;
mount_enter_mounting(m);
return 1;
Mount *m = MOUNT(u);
assert(m);
-
- if (m->state == MOUNT_MOUNTING_DONE) /* not yet ready to reload, try again */
- return -EAGAIN;
-
assert(m->state == MOUNT_MOUNTED);
mount_enter_remounting(m);
return mount_state_to_string(MOUNT(u)->state);
}
-_pure_ static bool mount_check_gc(Unit *u) {
+_pure_ static bool mount_may_gc(Unit *u) {
Mount *m = MOUNT(u);
assert(m);
- return m->from_proc_self_mountinfo;
+ if (m->from_proc_self_mountinfo)
+ return false;
+
+ return true;
}
static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
log_unit_full(u, f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
"Mount process exited, code=%s status=%i", sigchld_code_to_string(code), status);
- /* 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. */
+ /* 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. */
switch (m->state) {
case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
+ /* Our mount point has not appeared in mountinfo. Something went wrong. */
- if (f == MOUNT_SUCCESS || m->from_proc_self_mountinfo)
- /* If /bin/mount returned success, or if we see the mount point in /proc/self/mountinfo we are
- * happy. If we see the first condition first, we should see the second condition
- * immediately after – or /bin/mount lies to us and is broken. */
- mount_enter_mounted(m, f);
- else
- mount_enter_dead(m, f);
+ if (f == MOUNT_SUCCESS) {
+ /* Either /bin/mount has an unexpected definition of success,
+ * or someone raced us and we lost. */
+ log_unit_warning(UNIT(m), "Mount process finished, but there is no mount.");
+ f = MOUNT_FAILURE_PROTOCOL;
+ }
+ mount_enter_dead(m, f);
+ break;
+
+ case MOUNT_MOUNTING_DONE:
+ mount_enter_mounted(m, f);
break;
case MOUNT_REMOUNTING:
break;
case MOUNT_UNMOUNTING:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- if (m->from_proc_self_mountinfo) {
+ if (f == MOUNT_SUCCESS && 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. */
+ * stacked on top of each other. We might exceed the timeout specified by the user overall,
+ * but we will stop as soon as any one umount times out. */
if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
log_unit_debug(u, "Mount still present, trying again.");
m->n_retry_umount++;
mount_enter_unmounting(m);
} else {
- log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
+ log_unit_warning(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
mount_enter_mounted(m, f);
}
} else
- mount_enter_dead(m, f);
+ mount_enter_dead_or_mounted(m, f);
+
+ break;
+ case MOUNT_UNMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ mount_enter_dead_or_mounted(m, f);
break;
default:
flags->just_changed = r1 > 0 || r2 > 0 || r3 > 0;
flags->is_mounted = true;
- flags->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
+ flags->just_mounted = !MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->just_mounted;
MOUNT(u)->from_proc_self_mountinfo = true;
assert(m);
t = mnt_new_table();
- if (!t)
- return log_oom();
-
i = mnt_new_iter(MNT_ITER_FORWARD);
- if (!i)
+ if (!t || !i)
return log_oom();
r = mnt_table_parse_mtab(t, NULL);
r = 0;
for (;;) {
+ struct libmnt_fs *fs;
const char *device, *path, *options, *fstype;
_cleanup_free_ char *d = NULL, *p = NULL;
- struct libmnt_fs *fs;
int k;
k = mnt_table_next_fs(t, i, &fs);
goto fail;
}
- r = sd_event_source_set_priority(m->mount_event_source, -10);
+ r = sd_event_source_set_priority(m->mount_event_source, SD_EVENT_PRIORITY_NORMAL-10);
if (r < 0) {
log_error_errno(r, "Failed to adjust mount watch priority: %m");
goto fail;
mount->parameters_proc_self_mountinfo.what) {
/* Remember that this device might just have disappeared */
- if (set_ensure_allocated(&gone, &string_hash_ops) < 0 ||
+ if (set_ensure_allocated(&gone, &path_hash_ops) < 0 ||
set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0)
log_oom(); /* we don't care too much about OOM here... */
}
mount->from_proc_self_mountinfo &&
mount->parameters_proc_self_mountinfo.what) {
- if (set_ensure_allocated(&around, &string_hash_ops) < 0 ||
+ if (set_ensure_allocated(&around, &path_hash_ops) < 0 ||
set_put(around, mount->parameters_proc_self_mountinfo.what) < 0)
log_oom();
}
[MOUNT_FAILURE_SIGNAL] = "signal",
[MOUNT_FAILURE_CORE_DUMP] = "core-dump",
[MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [MOUNT_FAILURE_PROTOCOL] = "protocol",
};
DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
.active_state = mount_active_state,
.sub_state_to_string = mount_sub_state_to_string,
- .check_gc = mount_check_gc,
+ .may_gc = mount_may_gc,
.sigchld_event = mount_sigchld_event,