]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/mount-setup.c
units: don't enforce a holdoff time for journald, logind, udevd
[thirdparty/systemd.git] / src / core / mount-setup.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8e274523
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
8e274523
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
8e274523 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
8e274523
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/mount.h>
23#include <errno.h>
24#include <sys/stat.h>
25#include <stdlib.h>
26#include <string.h>
27#include <libgen.h>
28#include <assert.h>
5c0532d1 29#include <unistd.h>
1829dc9d 30#include <ftw.h>
8e274523
LP
31
32#include "mount-setup.h"
5ba2dc25 33#include "dev-setup.h"
8e274523 34#include "log.h"
c9af1080
LP
35#include "macro.h"
36#include "util.h"
5275d3c1 37#include "label.h"
0c85a4f3
LP
38#include "set.h"
39#include "strv.h"
49e942b2 40#include "mkdir.h"
9eb977db 41#include "path-util.h"
48ac500b 42#include "missing.h"
8e274523 43
bef2733f
LP
44#ifndef TTY_GID
45#define TTY_GID 5
46#endif
47
ca714c0e
LP
48typedef struct MountPoint {
49 const char *what;
50 const char *where;
51 const char *type;
52 const char *options;
53 unsigned long flags;
2076ca54 54 bool fatal;
ca714c0e
LP
55} MountPoint;
56
4ef31082 57/* The first three entries we might need before SELinux is up. The
160481f6
RS
58 * fourth (securityfs) is needed by IMA to load a custom policy. The
59 * other ones we can delay until SELinux and IMA are loaded. */
60#define N_EARLY_MOUNT 4
4ef31082 61
ca714c0e 62static const MountPoint mount_table[] = {
77d5f105
LP
63 { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
64 { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
635f7d8c 65 { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true },
160481f6 66 { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
635f7d8c 67 { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
bef2733f 68 { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false },
635f7d8c
KS
69 { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
70 { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, false },
e5a53dc7 71 { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
8e274523
LP
72};
73
949c6510 74/* These are API file systems that might be mounted by other software,
46ff0ed7 75 * we just list them here so that we know that we should ignore them */
949c6510 76
eaeb18db
LP
77static const char ignore_paths[] =
78 /* SELinux file systems */
79 "/sys/fs/selinux\0"
80 "/selinux\0"
81 /* Legacy cgroup mount points */
82 "/dev/cgroup\0"
83 "/cgroup\0"
84 /* Legacy kernel file system */
85 "/proc/bus/usb\0"
86 /* Container bind mounts */
87 "/proc/sys\0"
88 "/dev/console\0"
89 "/proc/kmsg\0"
90 "/etc/localtime\0"
91 "/etc/timezone\0"
92 "/etc/machine-id\0";
949c6510 93
dad08730
LP
94bool mount_point_is_api(const char *path) {
95 unsigned i;
96
97 /* Checks if this mount point is considered "API", and hence
98 * should be ignored */
99
ca714c0e 100 for (i = 0; i < ELEMENTSOF(mount_table); i ++)
449ddb2d 101 if (path_equal(path, mount_table[i].where))
dad08730
LP
102 return true;
103
57f2a956
KS
104 return path_startswith(path, "/sys/fs/cgroup/");
105}
106
107bool mount_point_ignore(const char *path) {
eaeb18db 108 const char *i;
57f2a956 109
eaeb18db
LP
110 NULSTR_FOREACH(i, ignore_paths)
111 if (path_equal(path, i))
949c6510
LP
112 return true;
113
57f2a956 114 return false;
dad08730
LP
115}
116
4ef31082 117static int mount_one(const MountPoint *p, bool relabel) {
8e274523
LP
118 int r;
119
ca714c0e 120 assert(p);
8e274523 121
51b4af2c 122 /* Relabel first, just in case */
4ef31082 123 if (relabel)
c9bc0764 124 label_fix(p->where, true, true);
51b4af2c 125
0c85a4f3 126 if ((r = path_is_mount_point(p->where, true)) < 0)
8e274523
LP
127 return r;
128
129 if (r > 0)
51b4af2c 130 return 0;
8e274523 131
a04f58d6
LP
132 /* The access mode here doesn't really matter too much, since
133 * the mounted file system will take precedence anyway. */
d2e54fae 134 mkdir_p_label(p->where, 0755);
a04f58d6 135
8e274523 136 log_debug("Mounting %s to %s of type %s with options %s.",
ca714c0e
LP
137 p->what,
138 p->where,
139 p->type,
140 strna(p->options));
141
142 if (mount(p->what,
143 p->where,
144 p->type,
145 p->flags,
146 p->options) < 0) {
71f737d2 147 log_full(p->fatal ? LOG_ERR : LOG_DEBUG, "Failed to mount %s: %s", p->where, strerror(errno));
2076ca54 148 return p->fatal ? -errno : 0;
8e274523
LP
149 }
150
51b4af2c 151 /* Relabel again, since we now mounted something fresh here */
4ef31082 152 if (relabel)
c9bc0764 153 label_fix(p->where, false, false);
5275d3c1 154
0c85a4f3 155 return 1;
8e274523
LP
156}
157
4ef31082
LP
158int mount_setup_early(void) {
159 unsigned i;
160 int r = 0;
161
162 assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
163
164 /* Do a minimal mount of /proc and friends to enable the most
165 * basic stuff, such as SELinux */
166 for (i = 0; i < N_EARLY_MOUNT; i ++) {
167 int j;
168
169 j = mount_one(mount_table + i, false);
170 if (r == 0)
171 r = j;
172 }
173
174 return r;
175}
176
0c85a4f3 177int mount_cgroup_controllers(char ***join_controllers) {
2076ca54
LP
178 int r;
179 FILE *f;
20c03b7b 180 char buf[LINE_MAX];
0c85a4f3 181 Set *controllers;
2076ca54 182
670802d4 183 /* Mount all available cgroup controllers that are built into the kernel. */
2076ca54 184
0c85a4f3
LP
185 f = fopen("/proc/cgroups", "re");
186 if (!f) {
016e9849
LP
187 log_error("Failed to enumerate cgroup controllers: %m");
188 return 0;
189 }
2076ca54 190
0c85a4f3
LP
191 controllers = set_new(string_hash_func, string_compare_func);
192 if (!controllers) {
193 r = -ENOMEM;
194 log_error("Failed to allocate controller set.");
195 goto finish;
196 }
197
2076ca54 198 /* Ignore the header line */
bab45044 199 (void) fgets(buf, sizeof(buf), f);
2076ca54
LP
200
201 for (;;) {
0c85a4f3
LP
202 char *controller;
203 int enabled = 0;
2076ca54 204
16f6682d 205 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
2076ca54
LP
206
207 if (feof(f))
208 break;
209
210 log_error("Failed to parse /proc/cgroups.");
211 r = -EIO;
212 goto finish;
213 }
214
600a328f
LP
215 if (!enabled) {
216 free(controller);
217 continue;
218 }
219
0c85a4f3
LP
220 r = set_put(controllers, controller);
221 if (r < 0) {
222 log_error("Failed to add controller to set.");
2076ca54 223 free(controller);
0c85a4f3
LP
224 goto finish;
225 }
226 }
227
228 for (;;) {
229 MountPoint p;
230 char *controller, *where, *options;
231 char ***k = NULL;
232
233 controller = set_steal_first(controllers);
234 if (!controller)
235 break;
236
237 if (join_controllers)
238 for (k = join_controllers; *k; k++)
239 if (strv_find(*k, controller))
240 break;
241
242 if (k && *k) {
243 char **i, **j;
244
245 for (i = *k, j = *k; *i; i++) {
246
247 if (!streq(*i, controller)) {
248 char *t;
249
250 t = set_remove(controllers, *i);
251 if (!t) {
252 free(*i);
253 continue;
254 }
255 free(t);
256 }
257
258 *(j++) = *i;
259 }
260
261 *j = NULL;
262
263 options = strv_join(*k, ",");
264 if (!options) {
265 log_error("Failed to join options");
266 free(controller);
267 r = -ENOMEM;
268 goto finish;
269 }
270
271 } else {
272 options = controller;
273 controller = NULL;
274 }
275
276 where = strappend("/sys/fs/cgroup/", options);
277 if (!where) {
278 log_error("Failed to build path");
279 free(options);
2076ca54
LP
280 r = -ENOMEM;
281 goto finish;
282 }
283
284 zero(p);
285 p.what = "cgroup";
286 p.where = where;
287 p.type = "cgroup";
0c85a4f3 288 p.options = options;
2076ca54
LP
289 p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
290 p.fatal = false;
291
4ef31082 292 r = mount_one(&p, true);
2076ca54
LP
293 free(controller);
294 free(where);
295
0c85a4f3
LP
296 if (r < 0) {
297 free(options);
2076ca54 298 goto finish;
0c85a4f3
LP
299 }
300
301 if (r > 0 && k && *k) {
302 char **i;
303
304 for (i = *k; *i; i++) {
305 char *t;
306
307 t = strappend("/sys/fs/cgroup/", *i);
308 if (!t) {
309 log_error("Failed to build path");
310 r = -ENOMEM;
311 free(options);
312 goto finish;
313 }
314
315 r = symlink(options, t);
316 free(t);
317
318 if (r < 0 && errno != EEXIST) {
319 log_error("Failed to create symlink: %m");
320 r = -errno;
321 free(options);
322 goto finish;
323 }
324 }
325 }
326
327 free(options);
2076ca54
LP
328 }
329
330 r = 0;
331
332finish:
0c85a4f3
LP
333 set_free_free(controllers);
334
2076ca54
LP
335 fclose(f);
336
337 return r;
338}
339
1829dc9d
LP
340static int nftw_cb(
341 const char *fpath,
342 const struct stat *sb,
343 int tflag,
344 struct FTW *ftwbuf) {
345
9fe117ea 346 /* No need to label /dev twice in a row... */
edb49778
LP
347 if (_unlikely_(ftwbuf->level == 0))
348 return FTW_CONTINUE;
349
c9bc0764 350 label_fix(fpath, false, false);
af65c248 351
edb49778 352 /* /run/initramfs is static data and big, no need to
af65c248 353 * dynamically relabel its contents at boot... */
edb49778
LP
354 if (_unlikely_(ftwbuf->level == 1 &&
355 tflag == FTW_D &&
356 streq(fpath, "/run/initramfs")))
357 return FTW_SKIP_SUBTREE;
9fe117ea 358
edb49778 359 return FTW_CONTINUE;
1829dc9d
LP
360};
361
0b3325e7 362int mount_setup(bool loaded_policy) {
5c0532d1 363
af65c248
LP
364 static const char relabel[] =
365 "/run/initramfs/root-fsck\0"
366 "/run/initramfs/shutdown\0";
367
8e274523 368 int r;
dad08730 369 unsigned i;
5ba2dc25 370 const char *j;
8e274523 371
4ef31082
LP
372 for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
373 r = mount_one(mount_table + i, true);
374
375 if (r < 0)
8e274523 376 return r;
4ef31082 377 }
8e274523 378
f1d19aa4
LP
379 /* Nodes in devtmpfs and /run need to be manually updated for
380 * the appropriate labels, after mounting. The other virtual
381 * API file systems like /sys and /proc do not need that, they
382 * use the same label for all their files. */
0b3325e7
LP
383 if (loaded_policy) {
384 usec_t before_relabel, after_relabel;
385 char timespan[FORMAT_TIMESPAN_MAX];
386
387 before_relabel = now(CLOCK_MONOTONIC);
388
edb49778
LP
389 nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
390 nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
0b3325e7 391
af65c248
LP
392 /* Explicitly relabel these */
393 NULSTR_FOREACH(j, relabel)
c9bc0764 394 label_fix(j, true, false);
af65c248 395
0b3325e7
LP
396 after_relabel = now(CLOCK_MONOTONIC);
397
398 log_info("Relabelled /dev and /run in %s.",
399 format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel));
3bbecb2f 400 }
1829dc9d 401
5c0532d1 402 /* Create a few default symlinks, which are normally created
f1d19aa4 403 * by udevd, but some scripts might need them before we start
5c0532d1 404 * udevd. */
5ba2dc25 405 dev_setup();
5c0532d1 406
b925e726 407 /* Create a few directories we always want around */
d2e54fae
KS
408 mkdir_label("/run/systemd", 0755);
409 mkdir_label("/run/systemd/system", 0755);
b925e726 410
0c85a4f3 411 return 0;
8e274523 412}