]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/volatile-root/volatile-root.c
volatile-root: add overlay mode for host boots, too
[thirdparty/systemd.git] / src / volatile-root / volatile-root.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
91214a37
LP
2
3#include <sys/mount.h>
4
5#include "alloc-util.h"
1de7f825 6#include "escape.h"
91214a37 7#include "fs-util.h"
5e332028 8#include "main-func.h"
91214a37
LP
9#include "mkdir.h"
10#include "mount-util.h"
049af8ad 11#include "mountpoint-util.h"
5e332028 12#include "path-util.h"
91214a37 13#include "stat-util.h"
91214a37 14#include "string-util.h"
5e332028 15#include "volatile-util.h"
91214a37
LP
16
17static int make_volatile(const char *path) {
18 _cleanup_free_ char *old_usr = NULL;
19 int r;
20
1de7f825 21 assert(path);
91214a37
LP
22
23 r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr);
24 if (r < 0)
25 return log_error_errno(r, "/usr not available in old root: %m");
26
27 r = mkdir_p("/run/systemd/volatile-sysroot", 0700);
28 if (r < 0)
29 return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m");
30
31 r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
32 if (r < 0)
33 goto finish_rmdir;
34
35 if (mkdir("/run/systemd/volatile-sysroot/usr", 0755) < 0) {
85fb5bb2 36 r = log_error_errno(errno, "Failed to create /usr directory: %m");
91214a37
LP
37 goto finish_umount;
38 }
39
40 r = mount_verbose(LOG_ERR, old_usr, "/run/systemd/volatile-sysroot/usr", NULL, MS_BIND|MS_REC, NULL);
41 if (r < 0)
42 goto finish_umount;
43
44 r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", true, NULL);
85fb5bb2
LP
45 if (r < 0) {
46 log_error_errno(r, "Failed to remount /usr read-only: %m");
91214a37 47 goto finish_umount;
85fb5bb2 48 }
91214a37
LP
49
50 r = umount_recursive(path, 0);
51 if (r < 0) {
52 log_error_errno(r, "Failed to unmount %s: %m", path);
53 goto finish_umount;
54 }
55
56 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
85fb5bb2 57 log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC, ignoring: %m", path);
91214a37
LP
58
59 r = mount_verbose(LOG_ERR, "/run/systemd/volatile-sysroot", path, NULL, MS_MOVE, NULL);
60
61finish_umount:
62 (void) umount_recursive("/run/systemd/volatile-sysroot", 0);
63
64finish_rmdir:
65 (void) rmdir("/run/systemd/volatile-sysroot");
66
67 return r;
68}
69
1de7f825
LP
70static int make_overlay(const char *path) {
71 _cleanup_free_ char *escaped_path = NULL;
72 bool tmpfs_mounted = false;
73 const char *options = NULL;
74 int r;
75
76 assert(path);
77
78 r = mkdir_p("/run/systemd/overlay-sysroot", 0700);
79 if (r < 0)
80 return log_error_errno(r, "Couldn't create overlay sysroot directory: %m");
81
82 r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
83 if (r < 0)
84 goto finish;
85
86 tmpfs_mounted = true;
87
88 if (mkdir("/run/systemd/overlay-sysroot/upper", 0755) < 0) {
89 r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/upper: %m");
90 goto finish;
91 }
92
93 if (mkdir("/run/systemd/overlay-sysroot/work", 0755) < 0) {
94 r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/work: %m");
95 goto finish;
96 }
97
98 escaped_path = shell_escape(path, ",:");
99 if (!escaped_path) {
100 r = log_oom();
101 goto finish;
102 }
103
104 options = strjoina("lowerdir=", escaped_path, ",upperdir=/run/systemd/overlay-sysroot/upper,workdir=/run/systemd/overlay-sysroot/work");
105 r = mount_verbose(LOG_ERR, "overlay", path, "overlay", 0, options);
106
107finish:
108 if (tmpfs_mounted)
109 (void) umount_verbose("/run/systemd/overlay-sysroot");
110
111 (void) rmdir("/run/systemd/overlay-sysroot");
112 return r;
113}
114
51e23786 115static int run(int argc, char *argv[]) {
91214a37
LP
116 VolatileMode m = _VOLATILE_MODE_INVALID;
117 const char *path;
118 int r;
119
6bf3c61c 120 log_setup_service();
91214a37 121
baaa35ad
ZJS
122 if (argc > 3)
123 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
124 "Too many arguments. Expected directory and mode.");
91214a37
LP
125
126 r = query_volatile_mode(&m);
51e23786
ZJS
127 if (r < 0)
128 return log_error_errno(r, "Failed to determine volatile mode from kernel command line.");
91214a37
LP
129 if (r == 0 && argc >= 2) {
130 /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
131 m = volatile_mode_from_string(argv[1]);
26945d18
LP
132 if (m < 0)
133 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Couldn't parse volatile mode: %s", argv[1]);
91214a37
LP
134 }
135
136 if (argc < 3)
137 path = "/sysroot";
138 else {
139 path = argv[2];
140
baaa35ad
ZJS
141 if (isempty(path))
142 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
143 "Directory name cannot be empty.");
144 if (!path_is_absolute(path))
145 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
146 "Directory must be specified as absolute path.");
147 if (path_equal(path, "/"))
148 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
149 "Directory cannot be the root directory.");
91214a37
LP
150 }
151
1de7f825 152 if (!IN_SET(m, VOLATILE_YES, VOLATILE_OVERLAY))
51e23786 153 return 0;
91214a37 154
1de7f825
LP
155 r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW);
156 if (r < 0)
157 return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path);
158 if (r == 0)
159 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a mount point.", path);
160
161 r = path_is_temporary_fs(path);
162 if (r < 0)
163 return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path);
164 if (r > 0) {
165 log_info("%s already is a temporary file system.", path);
166 return 0;
167 }
168
169 if (m == VOLATILE_YES)
170 return make_volatile(path);
171 else {
172 assert(m == VOLATILE_OVERLAY);
173 return make_overlay(path);
174 }
91214a37 175}
51e23786
ZJS
176
177DEFINE_MAIN_FUNCTION(run);