]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
449ddb2d | 2 | |
449ddb2d | 3 | #include <errno.h> |
cf0fbc49 | 4 | #include <mntent.h> |
b16fee15 | 5 | #include <sys/prctl.h> |
449ddb2d LP |
6 | #include <sys/stat.h> |
7 | #include <sys/wait.h> | |
cf0fbc49 | 8 | #include <unistd.h> |
449ddb2d | 9 | |
59f13dd6 | 10 | #include "env-util.h" |
4349cd7c | 11 | #include "exit-status.h" |
ed4ad488 | 12 | #include "fstab-util.h" |
449ddb2d | 13 | #include "log.h" |
5e332028 | 14 | #include "main-func.h" |
4349cd7c LP |
15 | #include "mount-setup.h" |
16 | #include "mount-util.h" | |
9eb977db | 17 | #include "path-util.h" |
b16fee15 | 18 | #include "process-util.h" |
24882e06 | 19 | #include "signal-util.h" |
b16fee15 | 20 | #include "strv.h" |
449ddb2d | 21 | |
58b86fdf LP |
22 | /* Goes through /etc/fstab and remounts all API file systems, applying options that are in /etc/fstab that systemd |
23 | * might not have respected */ | |
24 | ||
25 | static int track_pid(Hashmap **h, const char *path, pid_t pid) { | |
26 | _cleanup_free_ char *c = NULL; | |
27 | int r; | |
28 | ||
29 | assert(h); | |
30 | assert(path); | |
31 | assert(pid_is_valid(pid)); | |
32 | ||
58b86fdf LP |
33 | c = strdup(path); |
34 | if (!c) | |
35 | return log_oom(); | |
36 | ||
b5bcd738 SS |
37 | r = hashmap_ensure_put(h, NULL, PID_TO_PTR(pid), c); |
38 | if (r == -ENOMEM) | |
58b86fdf | 39 | return log_oom(); |
b5bcd738 SS |
40 | if (r < 0) |
41 | return log_error_errno(r, "Failed to store pid " PID_FMT, pid); | |
58b86fdf LP |
42 | |
43 | TAKE_PTR(c); | |
44 | return 0; | |
45 | } | |
449ddb2d | 46 | |
becccb52 ZJS |
47 | static int do_remount(const char *path, bool force_rw, Hashmap **pids) { |
48 | pid_t pid; | |
49 | int r; | |
50 | ||
51 | log_debug("Remounting %s...", path); | |
52 | ||
53 | r = safe_fork(force_rw ? "(remount-rw)" : "(remount)", | |
e9ccae31 | 54 | FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid); |
becccb52 ZJS |
55 | if (r < 0) |
56 | return r; | |
57 | if (r == 0) { | |
58 | /* Child */ | |
59 | execv(MOUNT_PATH, | |
60 | STRV_MAKE(MOUNT_PATH, | |
61 | path, | |
62 | "-o", | |
63 | force_rw ? "remount,rw" : "remount")); | |
64 | log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m"); | |
65 | _exit(EXIT_FAILURE); | |
66 | } | |
67 | ||
68 | /* Parent */ | |
69 | return track_pid(pids, path, pid); | |
70 | } | |
71 | ||
1be6f213 | 72 | static int remount_by_fstab(Hashmap **ret_pids) { |
b16fee15 | 73 | _cleanup_hashmap_free_free_ Hashmap *pids = NULL; |
5862d652 | 74 | _cleanup_endmntent_ FILE *f = NULL; |
59f13dd6 | 75 | bool has_root = false; |
449ddb2d | 76 | struct mntent* me; |
b16fee15 | 77 | int r; |
449ddb2d | 78 | |
1be6f213 | 79 | assert(ret_pids); |
4c12626c | 80 | |
a38de31c YW |
81 | if (!fstab_enabled()) |
82 | return 0; | |
83 | ||
ed4ad488 | 84 | f = setmntent(fstab_path(), "re"); |
adb2ce5f | 85 | if (!f) { |
59f13dd6 | 86 | if (errno != ENOENT) |
ed4ad488 | 87 | return log_error_errno(errno, "Failed to open %s: %m", fstab_path()); |
449ddb2d | 88 | |
1be6f213 YW |
89 | return 0; |
90 | } | |
59f13dd6 | 91 | |
1be6f213 YW |
92 | while ((me = getmntent(f))) { |
93 | /* Remount the root fs, /usr, and all API VFSs */ | |
94 | if (!mount_point_is_api(me->mnt_dir) && | |
95 | !PATH_IN_SET(me->mnt_dir, "/", "/usr")) | |
96 | continue; | |
97 | ||
98 | if (path_equal(me->mnt_dir, "/")) | |
99 | has_root = true; | |
100 | ||
101 | r = do_remount(me->mnt_dir, false, &pids); | |
102 | if (r < 0) | |
103 | return r; | |
104 | } | |
105 | ||
106 | *ret_pids = TAKE_PTR(pids); | |
107 | return has_root; | |
108 | } | |
109 | ||
110 | static int run(int argc, char *argv[]) { | |
111 | _cleanup_hashmap_free_free_ Hashmap *pids = NULL; | |
112 | int r; | |
113 | ||
114 | log_setup(); | |
115 | ||
116 | if (argc > 1) | |
117 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
118 | "This program takes no arguments."); | |
119 | ||
120 | umask(0022); | |
449ddb2d | 121 | |
1be6f213 YW |
122 | r = remount_by_fstab(&pids); |
123 | if (r < 0) | |
124 | return r; | |
125 | if (r == 0) { | |
59f13dd6 LP |
126 | /* The $SYSTEMD_REMOUNT_ROOT_RW environment variable is set by systemd-gpt-auto-generator to tell us |
127 | * whether to remount things. We honour it only if there's no explicit line in /etc/fstab configured | |
128 | * which takes precedence. */ | |
129 | ||
130 | r = getenv_bool("SYSTEMD_REMOUNT_ROOT_RW"); | |
becccb52 ZJS |
131 | if (r < 0 && r != -ENXIO) |
132 | log_warning_errno(r, "Failed to parse $SYSTEMD_REMOUNT_ROOT_RW, ignoring: %m"); | |
59f13dd6 | 133 | |
becccb52 ZJS |
134 | if (r > 0) { |
135 | r = do_remount("/", true, &pids); | |
59f13dd6 LP |
136 | if (r < 0) |
137 | return r; | |
becccb52 | 138 | } |
449ddb2d LP |
139 | } |
140 | ||
b16fee15 | 141 | r = 0; |
449ddb2d | 142 | while (!hashmap_isempty(pids)) { |
6e61c701 | 143 | _cleanup_free_ char *s = NULL; |
59f13dd6 | 144 | siginfo_t si = {}; |
449ddb2d | 145 | |
449ddb2d | 146 | if (waitid(P_ALL, 0, &si, WEXITED) < 0) { |
449ddb2d LP |
147 | if (errno == EINTR) |
148 | continue; | |
149 | ||
6e61c701 | 150 | return log_error_errno(errno, "waitid() failed: %m"); |
449ddb2d LP |
151 | } |
152 | ||
4a0b58c4 | 153 | s = hashmap_remove(pids, PID_TO_PTR(si.si_pid)); |
6e61c701 ZJS |
154 | if (s && |
155 | !is_clean_exit(si.si_code, si.si_status, EXIT_CLEAN_COMMAND, NULL)) { | |
156 | if (si.si_code == CLD_EXITED) | |
157 | log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status); | |
158 | else | |
159 | log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status)); | |
160 | ||
161 | r = -ENOEXEC; | |
449ddb2d LP |
162 | } |
163 | } | |
164 | ||
6e61c701 | 165 | return r; |
449ddb2d | 166 | } |
6e61c701 ZJS |
167 | |
168 | DEFINE_MAIN_FUNCTION(run); |