Introduction
Introduction Statistics Contact Development Disclaimer Help
switch_root.c - ubase - suckless linux base utils
git clone git://git.suckless.org/ubase
Log
Files
Refs
README
LICENSE
---
switch_root.c (2867B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <sys/mount.h>
3 #include <sys/stat.h>
4 #include <sys/vfs.h>
5
6 #include <dirent.h>
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include "util.h"
15
16 #define RAMFS_MAGIC 0x858458f6 /* some random numb…
17 #define TMPFS_MAGIC 0x01021994
18
19 static void
20 delete_content(const char *dir, dev_t curdevice)
21 {
22 char path[PATH_MAX];
23 DIR *d;
24 struct stat st;
25 struct dirent *dent;
26
27 /* don't dive into other filesystems */
28 if (lstat(dir, &st) < 0 || st.st_dev != curdevice)
29 return;
30 if (!(d = opendir(dir)))
31 return;
32 while ((dent = readdir(d))) {
33 if (strcmp(dent->d_name, ".") == 0 ||
34 strcmp(dent->d_name, "..") == 0)
35 continue;
36
37 /* build path and dive deeper */
38 if (strlcpy(path, dir, sizeof(path)) >= sizeof(path))
39 eprintf("path too long\n");
40 if (path[strlen(path) - 1] != '/')
41 if (strlcat(path, "/", sizeof(path)) >= sizeof(p…
42 eprintf("path too long\n");
43 if (strlcat(path, dent->d_name, sizeof(path)) >= sizeof(…
44 eprintf("path too long\n");
45
46 if (lstat(path, &st) < 0)
47 weprintf("lstat %s:", path);
48
49 if (S_ISDIR(st.st_mode)) {
50 delete_content(path, curdevice);
51 if (rmdir(path) < 0)
52 weprintf("rmdir %s:", path);
53 } else {
54 if (unlink(path) < 0)
55 weprintf("unlink %s:", path);
56 }
57 }
58 closedir(d);
59 }
60
61 static void
62 usage(void)
63 {
64 eprintf("usage: %s [-c console] [newroot] [init] (PID 1)\n", arg…
65 }
66
67 int
68 main(int argc, char *argv[])
69 {
70 char *console = NULL;
71 dev_t curdev;
72 struct stat st;
73 struct statfs stfs;
74
75 ARGBEGIN {
76 case 'c':
77 console = EARGF(usage());
78 break;
79 default:
80 usage();
81 } ARGEND;
82
83 /* check number of args and if we are PID 1 */
84 if (argc != 2 || getpid() != 1)
85 usage();
86
87 /* chdir to newroot and make sure it's a different fs */
88 if (chdir(argv[0]))
89 eprintf("chdir %s:", argv[0]);
90
91 if (stat("/", &st))
92 eprintf("stat %s:", "/");
93
94 curdev = st.st_dev;
95 if (stat(".", &st))
96 eprintf("stat %s:", ".");
97 if (st.st_dev == curdev)
98 usage();
99
100 /* avoids trouble with real filesystems */
101 if (stat("/init", &st) || !S_ISREG(st.st_mode))
102 eprintf("/init is not a regular file\n");
103
104 statfs("/", &stfs);
105 if ((unsigned)stfs.f_type != RAMFS_MAGIC && (unsigned)stfs.f_typ…
106 eprintf("current filesystem is not a RAMFS or TMPFS\n");
107
108 /* wipe / */
109 delete_content("/", curdev);
110
111 /* overmount / with newroot and chroot into it */
112 if (mount(".", "/", NULL, MS_MOVE, NULL))
113 eprintf("mount %s:", ".");
114
115 if (chroot("."))
116 eprintf("chroot failed\n");
117
118 /* if -c is set, redirect stdin/stdout/stderr to console */
119 if (console) {
120 close(0);
121 if (open(console, O_RDWR) == -1)
122 eprintf("open %s:", console);
123 dup2(0, 1);
124 dup2(0, 2);
125 }
126
127 /* execute init */
128 execv(argv[1], argv);
129 eprintf("can't execute '%s':", argv[1]);
130 return 1;
131 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.