mount.c revision 514f4ef52f91edb3741cad88d34572d162459346
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering/*-*- Mode: C; c-basic-offset: 8 -*-*/
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering This file is part of systemd.
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering Copyright 2010 Lennart Poettering
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering systemd is free software; you can redistribute it and/or modify it
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering under the terms of the GNU General Public License as published by
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering the Free Software Foundation; either version 2 of the License, or
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering (at your option) any later version.
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering systemd is distributed in the hope that it will be useful, but
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering General Public License for more details.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU General Public License
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poetteringstatic const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_REMOUNTING] = UNIT_ACTIVE_RELOADING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_REMOUNTING_SIGTERM] = UNIT_ACTIVE_RELOADING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_REMOUNTING_SIGKILL] = UNIT_ACTIVE_RELOADING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering /* We need to make sure that /bin/mount is always called in
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering * the same process group as us, so that the autofs kernel
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering * side doesn't send us another mount request while we are
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering * already trying to comply its last one. */
4f755fc6ab8b75f89ed84c93cd5c3fac2a448b16Lennart Poettering m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
4f755fc6ab8b75f89ed84c93cd5c3fac2a448b16Lennart Poetteringstatic void mount_unwatch_control_pid(Mount *m) {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering unit_unwatch_pid(UNIT(m), m->control_pid);
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poetteringstatic void mount_parameters_done(MountParameters *p) {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering mount_parameters_done(&m->parameters_etc_fstab);
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering mount_parameters_done(&m->parameters_proc_self_mountinfo);
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
9980033377c105d2cd6539c9d73ee61d4c2263b0Lennart Poetteringstatic int mount_add_mount_links(Mount *m) {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering /* Adds in links to other mount points that might lie below or
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering * above us in the hierarchy */
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_MOUNT]) {
a41fe3a29372f8e6c4e7733bf85940a023811301Lennart Poettering if (path_startswith(m->where, n->where)) {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if (n->from_etc_fstab || n->from_fragment)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering } else if (path_startswith(n->where, m->where)) {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, UNIT(n), true)) < 0)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if (m->from_etc_fstab || m->from_fragment)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
0f0dbc46ccf5aaaf3131446d0a4d78bc97a37295Lennart Poetteringstatic int mount_add_swap_links(Mount *m) {
4f755fc6ab8b75f89ed84c93cd5c3fac2a448b16Lennart Poettering LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SWAP])
687d0825a4636b1841dc0c01fbcbf3160dddab74Michal Vyskocil if ((r = swap_add_one_mount_link((Swap*) other, m)) < 0)
144f0fc0c8a5e2f6b72179e2b5fb992474da24adLennart Poettering LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_PATH])
144f0fc0c8a5e2f6b72179e2b5fb992474da24adLennart Poettering if ((r = path_add_one_mount_link((Path*) other, m)) < 0)
144f0fc0c8a5e2f6b72179e2b5fb992474da24adLennart Poetteringstatic int mount_add_automount_links(Mount *m) {
40c32a4ad488256e934ce9ecc05ebfac04851711Léo Gillot-Lamure LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_AUTOMOUNT])
0cd1fd4369685b10953ada832a0b505f5732667dPierre Schmitz if ((r = automount_add_one_mount_link((Automount*) other, m)) < 0)
ff01d048b4c1455241c894cf7982662c9d28fd34Lennart Poetteringstatic int mount_add_socket_links(Mount *m) {
a41fe3a29372f8e6c4e7733bf85940a023811301Lennart Poettering LIST_FOREACH(units_per_type, other, m->meta.manager->units_per_type[UNIT_SOCKET])
a41fe3a29372f8e6c4e7733bf85940a023811301Lennart Poettering if ((r = socket_add_one_mount_link((Socket*) other, m)) < 0)
bc2f673ec24b59948fcfc35b3077fda0314e69d8Lennart Poetteringstatic char* mount_test_option(const char *haystack, const char *needle) {
5076f0ccfd36b67512d44fe355b80305ced7dcbaLennart Poettering /* Like glibc's hasmntopt(), but works on a string, not a
5076f0ccfd36b67512d44fe355b80305ced7dcbaLennart Poettering * struct mntent */
5076f0ccfd36b67512d44fe355b80305ced7dcbaLennart Poetteringstatic int mount_add_target_links(Mount *m) {
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO);
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering user = mount_test_option(p->options, "user") || mount_test_option(p->options, "users");
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering handle = !!mount_test_option(p->options, "comment=systemd.mount");
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering automount = !!mount_test_option(p->options, "comment=systemd.automount");
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering if (mount_test_option(p->options, "_netdev") ||
27407a01c6c115ed09ad938ab95dcb56ab963ba9Zbigniew Jędrzejewski-Szmek target = SPECIAL_LOCAL_FS_TARGET;
27407a01c6c115ed09ad938ab95dcb56ab963ba9Zbigniew Jędrzejewski-Szmek if ((r = manager_load_unit(UNIT(m)->meta.manager, target, NULL, &tu)) < 0)
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering if (automount && m->meta.manager->running_as != MANAGER_SESSION) {
27407a01c6c115ed09ad938ab95dcb56ab963ba9Zbigniew Jędrzejewski-Szmek if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0)
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(am), true)) < 0)
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering return unit_add_dependency(UNIT(am), UNIT_BEFORE, tu, true);
27407a01c6c115ed09ad938ab95dcb56ab963ba9Zbigniew Jędrzejewski-Szmek if (user || m->meta.manager->running_as != MANAGER_SESSION)
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0)
57fb9fb56db0584581ce33ee842dcbf5f1136856Lennart Poettering return unit_add_dependency(UNIT(m), UNIT_BEFORE, tu, true);
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if (!m->from_etc_fstab && !m->from_fragment && !m->from_proc_self_mountinfo)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if (!(e = unit_name_from_path(m->where, ".mount")))
25f5971b5e0b3ab5b91a7d0359cd7f5a5094c1d0Lennart Poettering log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->meta.id);
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if (m->meta.fragment_path && !m->parameters_fragment.what) {
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering log_error("%s's What setting is missing. Refusing.", UNIT(m)->meta.id);
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
8f7a3c1402a8de36b2c63935358a53510d2fe7c1Lennart Poettering /* This is a new unit? Then let's add in some extras */
25f5971b5e0b3ab5b91a7d0359cd7f5a5094c1d0Lennart Poettering if (!(m->where = unit_name_to_path(u->meta.id)))
if (what)
if ((r = mount_add_mount_links(m)) < 0)
if ((r = mount_add_socket_links(m)) < 0)
if ((r = mount_add_swap_links(m)) < 0)
if ((r = mount_add_path_links(m)) < 0)
if ((r = mount_add_automount_links(m)) < 0)
if ((r = mount_add_target_links(m)) < 0)
if ((r = unit_add_default_cgroup(u)) < 0)
return mount_verify(m);
Unit *p;
assert(m);
return r == -ENOENT ? 0 : r;
assert(m);
mount_notify_automount(m, 0);
assert(m);
else if (m->from_proc_self_mountinfo)
if (m->control_pid <= 0)
return -EBADMSG;
MountParameters *p;
assert(m);
assert(f);
if (m->from_proc_self_mountinfo)
p = &m->parameters_proc_self_mountinfo;
else if (m->from_fragment)
p = &m->parameters_fragment;
p = &m->parameters_etc_fstab;
fprintf(f,
if (m->control_pid > 0)
fprintf(f,
assert(m);
assert(c);
goto fail;
if ((r = exec_spawn(c,
NULL,
&m->exec_context,
NULL, 0,
&pid)) < 0)
goto fail;
goto fail;
fail:
assert(m);
if (!success)
m->failure = true;
assert(m);
if (!success)
m->failure = true;
bool sent = false;
assert(m);
if (!success)
m->failure = true;
goto fail;
sent = true;
if (kill(m->kill_mode == KILL_PROCESS ? m->control_pid : -m->control_pid, sig) < 0 && errno != ESRCH) {
r = -errno;
goto fail;
if (sent) {
goto fail;
mount_enter_mounted(m, true);
mount_enter_dead(m, true);
fail:
mount_enter_mounted(m, false);
mount_enter_dead(m, false);
assert(m);
if (!success)
m->failure = true;
if ((r = exec_command_set(
m->control_command,
m->where,
NULL)) < 0)
goto fail;
goto fail;
fail:
mount_enter_mounted(m, false);
assert(m);
if (m->from_fragment)
r = exec_command_set(
m->control_command,
m->where,
NULL);
else if (m->from_etc_fstab)
r = exec_command_set(
m->control_command,
m->where,
NULL);
r = -ENOENT;
goto fail;
goto fail;
fail:
mount_enter_dead(m, false);
assert(m);
assert(m);
if (!success)
m->failure = true;
if (m->from_fragment) {
r = -ENOMEM;
goto fail;
o = buf;
r = exec_command_set(
m->control_command,
m->where,
NULL);
} else if (m->from_etc_fstab)
r = exec_command_set(
m->control_command,
m->where,
NULL);
r = -ENOENT;
r = -ENOMEM;
goto fail;
goto fail;
fail:
mount_enter_mounted(m, false);
assert(m);
return -EAGAIN;
m->failure = false;
assert(m);
return -EAGAIN;
mount_enter_unmounting(m, true);
assert(m);
return -EAGAIN;
mount_enter_remounting(m, true);
assert(m);
assert(f);
if (m->control_pid > 0)
if (m->control_command_id >= 0)
assert(u);
assert(u);
assert(u);
assert(m);
bool success;
assert(m);
m->control_pid = 0;
if (m->control_command) {
log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
switch (m->state) {
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_MOUNTING_SIGTERM:
case MOUNT_REMOUNTING:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGTERM:
if (success)
mount_enter_mounted(m, true);
else if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, false);
mount_enter_dead(m, false);
case MOUNT_UNMOUNTING:
case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
if (success)
mount_enter_dead(m, true);
else if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, false);
mount_enter_dead(m, false);
assert(m);
switch (m->state) {
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
case MOUNT_REMOUNTING:
case MOUNT_UNMOUNTING:
case MOUNT_MOUNTING_SIGTERM:
case MOUNT_REMOUNTING_SIGTERM:
case MOUNT_UNMOUNTING_SIGTERM:
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGKILL:
if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, false);
mount_enter_dead(m, false);
static int mount_add_one(
Manager *m,
const char *what,
const char *where,
const char *options,
const char *fstype,
bool from_proc_self_mountinfo,
bool set_flags) {
Unit *u;
bool delete;
MountParameters *p;
assert(m);
return -ENOMEM;
if (!(u = manager_get_unit(m, e))) {
delete = true;
if (!(u = unit_new(m))) {
free(e);
return -ENOMEM;
r = unit_add_name(u, e);
free(e);
goto fail;
r = -ENOMEM;
goto fail;
delete = false;
free(e);
r = -ENOMEM;
goto fail;
if (from_proc_self_mountinfo) {
if (set_flags) {
p->what = w;
p->options = o;
p->fstype = f;
fail:
free(w);
free(o);
free(f);
if (delete && u)
unit_free(u);
static char *fstab_node_to_udev_node(char *p) {
char *dn, *t;
return NULL;
free(t);
return NULL;
return dn;
return NULL;
free(t);
return NULL;
return dn;
return strdup(p);
errno = 0;
if (errno != 0)
return -errno;
return -EINVAL;
FILE *f;
assert(m);
errno = 0;
return -errno;
r = -ENOMEM;
goto finish;
r = -ENOMEM;
goto finish;
int pri;
r = pri;
r = swap_add_one(m,
what,
pri,
goto finish;
endmntent(f);
assert(m);
&path,
&options,
&fstype,
&device,
if (k == EOF)
r = -EBADMSG;
goto finish;
r = -ENOMEM;
goto finish;
r = -ENOMEM;
goto finish;
goto finish;
free(d);
free(p);
free(o);
free(d);
free(p);
free(o);
assert(m);
if (m->proc_self_mountinfo) {
assert(m);
if (!m->proc_self_mountinfo) {
return -errno;
return -errno;
if ((r = mount_load_etc_fstab(m)) < 0)
goto fail;
if ((r = mount_load_proc_self_mountinfo(m, false)) < 0)
goto fail;
fail:
mount_shutdown(m);
assert(m);
if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) {
case MOUNT_MOUNTED:
case MOUNT_DEAD:
case MOUNT_MAINTENANCE:
case MOUNT_MOUNTING:
assert(m);
return -ENOMEM;
char *e, *slash;
Unit *u;
r = -ENOMEM;
goto finish;
u = manager_get_unit(m, e);
free(e);
goto finish;
if (slash == t) {
goto finish;
*slash = 0;
free(t);
.no_alias = true,
.no_instances = true,
.no_isolate = true,