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