]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/remount-fs/remount-fs.c
Merge pull request #11681 from yuwata/network-link-enslaved-operstate
[thirdparty/systemd.git] / src / remount-fs / remount-fs.c
index b155f991bb6ad8c7f3dca74a73832eb4d9073343..0df29aa69ff0cb26f45b8fdbf9ebb6b55a8bedd4 100644 (file)
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  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/>.
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
 #include <mntent.h>
 #include <string.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "env-util.h"
 #include "exit-status.h"
 #include "log.h"
+#include "main-func.h"
 #include "mount-setup.h"
 #include "mount-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "signal-util.h"
+#include "strv.h"
 #include "util.h"
 
-/* Goes through /etc/fstab and remounts all API file systems, applying
- * options that are in /etc/fstab that systemd might not have
- * respected */
+/* Goes through /etc/fstab and remounts all API file systems, applying options that are in /etc/fstab that systemd
+ * might not have respected */
 
-int main(int argc, char *argv[]) {
-        int ret = EXIT_FAILURE;
-        _cleanup_endmntent_ FILE *f = NULL;
-        struct mntent* me;
-        Hashmap *pids = NULL;
+static int track_pid(Hashmap **h, const char *path, pid_t pid) {
+        _cleanup_free_ char *c = NULL;
+        int r;
 
-        if (argc > 1) {
-                log_error("This program takes no argument.");
-                return EXIT_FAILURE;
-        }
+        assert(h);
+        assert(path);
+        assert(pid_is_valid(pid));
 
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
+        r = hashmap_ensure_allocated(h, NULL);
+        if (r < 0)
+                return log_oom();
 
-        umask(0022);
+        c = strdup(path);
+        if (!c)
+                return log_oom();
 
-        f = setmntent("/etc/fstab", "r");
-        if (!f) {
-                if (errno == ENOENT)
-                        return EXIT_SUCCESS;
+        r = hashmap_put(*h, PID_TO_PTR(pid), c);
+        if (r < 0)
+                return log_oom();
 
-                log_error_errno(errno, "Failed to open /etc/fstab: %m");
-                return EXIT_FAILURE;
-        }
+        TAKE_PTR(c);
+        return 0;
+}
 
-        pids = hashmap_new(NULL);
-        if (!pids) {
-                log_error("Failed to allocate set");
-                goto finish;
+static int do_remount(const char *path, bool force_rw, Hashmap **pids) {
+        pid_t pid;
+        int r;
+
+        log_debug("Remounting %s...", path);
+
+        r = safe_fork(force_rw ? "(remount-rw)" : "(remount)",
+                      FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                /* Child */
+                execv(MOUNT_PATH,
+                      STRV_MAKE(MOUNT_PATH,
+                                path,
+                                "-o",
+                                force_rw ? "remount,rw" : "remount"));
+                log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
+                _exit(EXIT_FAILURE);
         }
 
-        ret = EXIT_SUCCESS;
-
-        while ((me = getmntent(f))) {
-                pid_t pid;
-                int k;
-                char *s;
-
-                /* Remount the root fs, /usr and all API VFS */
-                if (!mount_point_is_api(me->mnt_dir) &&
-                    !path_equal(me->mnt_dir, "/") &&
-                    !path_equal(me->mnt_dir, "/usr"))
-                        continue;
+        /* Parent */
+        return track_pid(pids, path, pid);
+}
 
-                log_debug("Remounting %s", me->mnt_dir);
+static int run(int argc, char *argv[]) {
+        _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
+        _cleanup_endmntent_ FILE *f = NULL;
+        bool has_root = false;
+        struct mntent* me;
+        int r;
 
-                pid = fork();
-                if (pid < 0) {
-                        log_error_errno(errno, "Failed to fork: %m");
-                        ret = EXIT_FAILURE;
-                        continue;
-                }
+        log_setup_service();
 
-                if (pid == 0) {
-                        const char *arguments[5];
-                        /* Child */
+        if (argc > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "This program takes no arguments.");
 
-                        (void) reset_all_signal_handlers();
-                        (void) reset_signal_mask();
+        umask(0022);
 
-                        arguments[0] = MOUNT_PATH;
-                        arguments[1] = me->mnt_dir;
-                        arguments[2] = "-o";
-                        arguments[3] = "remount";
-                        arguments[4] = NULL;
+        f = setmntent("/etc/fstab", "re");
+        if (!f) {
+                if (errno != ENOENT)
+                        return log_error_errno(errno, "Failed to open /etc/fstab: %m");
+        } else
+                while ((me = getmntent(f))) {
+                        /* Remount the root fs, /usr, and all API VFSs */
+                        if (!mount_point_is_api(me->mnt_dir) &&
+                            !PATH_IN_SET(me->mnt_dir, "/", "/usr"))
+                                continue;
 
-                        execv(MOUNT_PATH, (char **) arguments);
+                        if (path_equal(me->mnt_dir, "/"))
+                                has_root = true;
 
-                        log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
-                        _exit(EXIT_FAILURE);
+                        r = do_remount(me->mnt_dir, false, &pids);
+                        if (r < 0)
+                                return r;
                 }
 
-                /* Parent */
-
-                s = strdup(me->mnt_dir);
-                if (!s) {
-                        log_oom();
-                        ret = EXIT_FAILURE;
-                        continue;
-                }
+        if (!has_root) {
+                /* The $SYSTEMD_REMOUNT_ROOT_RW environment variable is set by systemd-gpt-auto-generator to tell us
+                 * whether to remount things. We honour it only if there's no explicit line in /etc/fstab configured
+                 * which takes precedence. */
 
+                r = getenv_bool("SYSTEMD_REMOUNT_ROOT_RW");
+                if (r < 0 && r != -ENXIO)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REMOUNT_ROOT_RW, ignoring: %m");
 
-                k = hashmap_put(pids, UINT_TO_PTR(pid), s);
-                if (k < 0) {
-                        log_error_errno(k, "Failed to add PID to set: %m");
-                        ret = EXIT_FAILURE;
-                        continue;
+                if (r > 0) {
+                        r = do_remount("/", true, &pids);
+                        if (r < 0)
+                                return r;
                 }
         }
 
+        r = 0;
         while (!hashmap_isempty(pids)) {
+                _cleanup_free_ char *s = NULL;
                 siginfo_t si = {};
-                char *s;
 
                 if (waitid(P_ALL, 0, &si, WEXITED) < 0) {
-
                         if (errno == EINTR)
                                 continue;
 
-                        log_error_errno(errno, "waitid() failed: %m");
-                        ret = EXIT_FAILURE;
-                        break;
+                        return log_error_errno(errno, "waitid() failed: %m");
                 }
 
-                s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid));
-                if (s) {
-                        if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
-                                if (si.si_code == CLD_EXITED)
-                                        log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status);
-                                else
-                                        log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status));
-
-                                ret = EXIT_FAILURE;
-                        }
+                s = hashmap_remove(pids, PID_TO_PTR(si.si_pid));
+                if (s &&
+                    !is_clean_exit(si.si_code, si.si_status, EXIT_CLEAN_COMMAND, NULL)) {
+                        if (si.si_code == CLD_EXITED)
+                                log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status);
+                        else
+                                log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status));
 
-                        free(s);
+                        r = -ENOEXEC;
                 }
         }
 
-finish:
-
-        if (pids)
-                hashmap_free_free(pids);
-
-        return ret;
+        return r;
 }
+
+DEFINE_MAIN_FUNCTION(run);