]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/mount.c
path-util: introduce path_simplify()
[thirdparty/systemd.git] / src / core / mount.c
index b25bb9cb403f73e70cbe6aa22b38d1a9b41835c8..d9bc4abb20b868a02623a552a0279cdf379a991e 100644 (file)
@@ -3,19 +3,6 @@
   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"
@@ -55,7 +45,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
 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,
@@ -164,6 +154,10 @@ static void mount_init(Unit *u) {
         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
@@ -237,7 +231,7 @@ static void mount_done(Unit *u) {
         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;
 
@@ -560,7 +554,7 @@ static int mount_add_extras(Mount *m) {
                         return r;
         }
 
-        path_kill_slashes(m->where);
+        path_simplify(m->where, false);
 
         if (!u->description) {
                 r = unit_set_description(u, m->where);
@@ -695,14 +689,17 @@ static int mount_coldplug(Unit *u) {
                         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;
 
@@ -724,7 +721,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 "%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,
@@ -737,7 +735,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 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,
@@ -772,7 +771,6 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
         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),
@@ -806,8 +804,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
 
         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]);
 
@@ -938,7 +935,7 @@ static void mount_enter_mounting(Mount *m) {
 
         assert(m);
 
-        r = unit_fail_if_symlink(UNIT(m), m->where);
+        r = unit_fail_if_noncanonical(UNIT(m), m->where);
         if (r < 0)
                 goto fail;
 
@@ -1131,10 +1128,6 @@ static int mount_reload(Unit *u) {
         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);
@@ -1230,12 +1223,15 @@ _pure_ static const char *mount_sub_state_to_string(Unit *u) {
         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) {
@@ -1276,23 +1272,25 @@ 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:
@@ -1302,28 +1300,31 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 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:
                 assert_not_reached("Uh, control process died at wrong time.");
         }
@@ -1486,7 +1487,7 @@ static int mount_setup_existing_unit(
 
         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;
 
@@ -1597,11 +1598,8 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
         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);
@@ -1610,9 +1608,9 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
 
         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);
@@ -1748,7 +1746,7 @@ static void mount_enumerate(Manager *m) {
                         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;
@@ -1828,7 +1826,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                             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... */
                         }
@@ -1883,7 +1881,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                     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();
                 }
@@ -1947,6 +1945,7 @@ static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
         [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);
@@ -1985,7 +1984,7 @@ const UnitVTable mount_vtable = {
         .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,