Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <sys/mount.h>
4 : :
5 : : #include "alloc-util.h"
6 : : #include "blockdev-util.h"
7 : : #include "escape.h"
8 : : #include "fs-util.h"
9 : : #include "main-func.h"
10 : : #include "mkdir.h"
11 : : #include "mount-util.h"
12 : : #include "mountpoint-util.h"
13 : : #include "path-util.h"
14 : : #include "stat-util.h"
15 : : #include "string-util.h"
16 : : #include "volatile-util.h"
17 : :
18 : 0 : static int make_volatile(const char *path) {
19 : 0 : _cleanup_free_ char *old_usr = NULL;
20 : : int r;
21 : :
22 [ # # ]: 0 : assert(path);
23 : :
24 : 0 : r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr);
25 [ # # ]: 0 : if (r < 0)
26 [ # # ]: 0 : return log_error_errno(r, "/usr not available in old root: %m");
27 : :
28 : 0 : r = mkdir_p("/run/systemd/volatile-sysroot", 0700);
29 [ # # ]: 0 : if (r < 0)
30 [ # # ]: 0 : return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m");
31 : :
32 : 0 : r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
33 [ # # ]: 0 : if (r < 0)
34 : 0 : goto finish_rmdir;
35 : :
36 [ # # ]: 0 : if (mkdir("/run/systemd/volatile-sysroot/usr", 0755) < 0) {
37 [ # # ]: 0 : r = log_error_errno(errno, "Failed to create /usr directory: %m");
38 : 0 : goto finish_umount;
39 : : }
40 : :
41 : 0 : r = mount_verbose(LOG_ERR, old_usr, "/run/systemd/volatile-sysroot/usr", NULL, MS_BIND|MS_REC, NULL);
42 [ # # ]: 0 : if (r < 0)
43 : 0 : goto finish_umount;
44 : :
45 : 0 : r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", MS_RDONLY, MS_RDONLY, NULL);
46 [ # # ]: 0 : if (r < 0) {
47 [ # # ]: 0 : log_error_errno(r, "Failed to remount /usr read-only: %m");
48 : 0 : goto finish_umount;
49 : : }
50 : :
51 : 0 : r = umount_recursive(path, 0);
52 [ # # ]: 0 : if (r < 0) {
53 [ # # ]: 0 : log_error_errno(r, "Failed to unmount %s: %m", path);
54 : 0 : goto finish_umount;
55 : : }
56 : :
57 [ # # ]: 0 : if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
58 [ # # ]: 0 : log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC, ignoring: %m", path);
59 : :
60 : 0 : r = mount_verbose(LOG_ERR, "/run/systemd/volatile-sysroot", path, NULL, MS_MOVE, NULL);
61 : :
62 : 0 : finish_umount:
63 : 0 : (void) umount_recursive("/run/systemd/volatile-sysroot", 0);
64 : :
65 : 0 : finish_rmdir:
66 : 0 : (void) rmdir("/run/systemd/volatile-sysroot");
67 : :
68 : 0 : return r;
69 : : }
70 : :
71 : 0 : static int make_overlay(const char *path) {
72 : 0 : _cleanup_free_ char *escaped_path = NULL;
73 : 0 : bool tmpfs_mounted = false;
74 : 0 : const char *options = NULL;
75 : : int r;
76 : :
77 [ # # ]: 0 : assert(path);
78 : :
79 : 0 : r = mkdir_p("/run/systemd/overlay-sysroot", 0700);
80 [ # # ]: 0 : if (r < 0)
81 [ # # ]: 0 : return log_error_errno(r, "Couldn't create overlay sysroot directory: %m");
82 : :
83 : 0 : r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
84 [ # # ]: 0 : if (r < 0)
85 : 0 : goto finish;
86 : :
87 : 0 : tmpfs_mounted = true;
88 : :
89 [ # # ]: 0 : if (mkdir("/run/systemd/overlay-sysroot/upper", 0755) < 0) {
90 [ # # ]: 0 : r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/upper: %m");
91 : 0 : goto finish;
92 : : }
93 : :
94 [ # # ]: 0 : if (mkdir("/run/systemd/overlay-sysroot/work", 0755) < 0) {
95 [ # # ]: 0 : r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/work: %m");
96 : 0 : goto finish;
97 : : }
98 : :
99 : 0 : escaped_path = shell_escape(path, ",:");
100 [ # # ]: 0 : if (!escaped_path) {
101 : 0 : r = log_oom();
102 : 0 : goto finish;
103 : : }
104 : :
105 [ # # # # : 0 : options = strjoina("lowerdir=", escaped_path, ",upperdir=/run/systemd/overlay-sysroot/upper,workdir=/run/systemd/overlay-sysroot/work");
# # # # #
# # # ]
106 : 0 : r = mount_verbose(LOG_ERR, "overlay", path, "overlay", 0, options);
107 : :
108 : 0 : finish:
109 [ # # ]: 0 : if (tmpfs_mounted)
110 : 0 : (void) umount_verbose("/run/systemd/overlay-sysroot");
111 : :
112 : 0 : (void) rmdir("/run/systemd/overlay-sysroot");
113 : 0 : return r;
114 : : }
115 : :
116 : 0 : static int run(int argc, char *argv[]) {
117 : 0 : VolatileMode m = _VOLATILE_MODE_INVALID;
118 : : const char *path;
119 : : dev_t devt;
120 : : int r;
121 : :
122 : 0 : log_setup_service();
123 : :
124 [ # # ]: 0 : if (argc > 3)
125 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
126 : : "Too many arguments. Expected directory and mode.");
127 : :
128 : 0 : r = query_volatile_mode(&m);
129 [ # # ]: 0 : if (r < 0)
130 [ # # ]: 0 : return log_error_errno(r, "Failed to determine volatile mode from kernel command line.");
131 [ # # # # ]: 0 : if (r == 0 && argc >= 2) {
132 : : /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
133 : 0 : m = volatile_mode_from_string(argv[1]);
134 [ # # ]: 0 : if (m < 0)
135 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Couldn't parse volatile mode: %s", argv[1]);
136 : : }
137 : :
138 [ # # ]: 0 : if (argc < 3)
139 : 0 : path = "/sysroot";
140 : : else {
141 : 0 : path = argv[2];
142 : :
143 [ # # ]: 0 : if (isempty(path))
144 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
145 : : "Directory name cannot be empty.");
146 [ # # ]: 0 : if (!path_is_absolute(path))
147 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
148 : : "Directory must be specified as absolute path.");
149 [ # # ]: 0 : if (path_equal(path, "/"))
150 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
151 : : "Directory cannot be the root directory.");
152 : : }
153 : :
154 [ # # # # ]: 0 : if (!IN_SET(m, VOLATILE_YES, VOLATILE_OVERLAY))
155 : 0 : return 0;
156 : :
157 : 0 : r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW);
158 [ # # ]: 0 : if (r < 0)
159 [ # # ]: 0 : return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path);
160 [ # # ]: 0 : if (r == 0)
161 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a mount point.", path);
162 : :
163 : 0 : r = path_is_temporary_fs(path);
164 [ # # ]: 0 : if (r < 0)
165 [ # # ]: 0 : return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path);
166 [ # # ]: 0 : if (r > 0) {
167 [ # # ]: 0 : log_info("%s already is a temporary file system.", path);
168 : 0 : return 0;
169 : : }
170 : :
171 : : /* We are about to replace the root directory with something else. Later code might want to know what we
172 : : * replaced here, hence let's save that information as a symlink we can later use. (This is particularly
173 : : * relevant for the overlayfs case where we'll fully obstruct the view onto the underlying device, hence
174 : : * querying the backing device node from the file system directly is no longer possible. */
175 : 0 : r = get_block_device_harder(path, &devt);
176 [ # # ]: 0 : if (r < 0)
177 [ # # ]: 0 : return log_error_errno(r, "Failed to determine device major/minor of %s: %m", path);
178 [ # # ]: 0 : else if (r > 0) {
179 [ # # ]: 0 : _cleanup_free_ char *dn = NULL;
180 : :
181 : 0 : r = device_path_make_major_minor(S_IFBLK, devt, &dn);
182 [ # # ]: 0 : if (r < 0)
183 [ # # ]: 0 : return log_error_errno(r, "Failed to format device node path: %m");
184 : :
185 [ # # ]: 0 : if (symlink(dn, "/run/systemd/volatile-root") < 0)
186 [ # # ]: 0 : log_warning_errno(errno, "Failed to create symlink /run/systemd/volatile-root: %m");
187 : : }
188 : :
189 [ # # ]: 0 : if (m == VOLATILE_YES)
190 : 0 : return make_volatile(path);
191 : : else {
192 [ # # ]: 0 : assert(m == VOLATILE_OVERLAY);
193 : 0 : return make_overlay(path);
194 : : }
195 : : }
196 : :
197 : 0 : DEFINE_MAIN_FUNCTION(run);
|