forked from gcwnow/mininit
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathinitramfs.c
107 lines (86 loc) · 2.15 KB
/
initramfs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* SPDX-License-Identifier: BSD-2-Clause */
#define _DEFAULT_SOURCE
#define _GNU_SOURCE
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef MS_MOVE
#define MS_MOVE 8192
#endif
#ifndef O_PATH
#define O_PATH 010000000
#endif
#include "debug.h"
#include "mininit.h"
#define BOOTFS_TYPE "vfat"
static const char *boot_mount = "/boot";
static int multi_mount(
char *source,
const char *target,
const char *type,
unsigned long flags,
int retries)
{
for (int try = 0; try < retries; usleep(100000), try++) {
for (char c = ',', *s = source; c == ','; *s++ = c) {
char *t;
for (t = s; *s != ',' && *s != '\0'; s++);
c = *s;
*s = '\0';
if (!mount(t, target, type, flags, NULL)) {
INFO("%s mounted on %s\n", t, target);
*s = c;
return 0;
}
}
}
ERROR("Cannot mount %s on %s\n", source, target);
return -1;
}
const char *mount_boot(void)
{
/* Create boot mount.
* Failure is most likely fatal, but perhaps mkdir on a usable mount point
* could return something other than EEXIST when trying to recreate it. */
create_mount_point(boot_mount);
/* Process "boot" parameter (comma-separated list).
* Note that we specify 20 retries (2 seconds), just in case it is
* a hotplug device which takes some time to detect and initialize. */
char *boot_dev = getenv("boot");
if (boot_dev) {
if (multi_mount(boot_dev, boot_mount, BOOTFS_TYPE, MS_RDONLY, 20)) {
return NULL;
}
} else {
ERROR("'boot' parameter not found\n");
return NULL;
}
return boot_mount;
}
int open_dir_to_clean(void)
{
int fd = open("/", O_PATH | O_DIRECTORY);
if (fd < 0) {
DEBUG("Failed to open '/' before switch: %d\n", errno);
}
return fd;
}
int switch_root(void)
{
DEBUG("Switching root\n");
/* Move the boot mount to inside the rootfs tree. */
if (mount(boot_mount, "boot", NULL, MS_MOVE, NULL)) {
ERROR("Unable to move the '%s' mount: %d\n", boot_mount, errno);
return -1;
}
/* Do the root switch */
if (mount(".", "/", NULL, MS_MOVE, NULL)) {
ERROR("Unable to switch to the new root: %d\n", errno);
return -1;
}
return 0;
}