Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/run-init/runinitlib.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (hide annotations) (download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5310 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
1 niro 532 /* ----------------------------------------------------------------------- *
2     *
3     * Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
4     *
5     * Permission is hereby granted, free of charge, to any person
6     * obtaining a copy of this software and associated documentation
7     * files (the "Software"), to deal in the Software without
8     * restriction, including without limitation the rights to use,
9     * copy, modify, merge, publish, distribute, sublicense, and/or
10     * sell copies of the Software, and to permit persons to whom
11     * the Software is furnished to do so, subject to the following
12     * conditions:
13     *
14     * The above copyright notice and this permission notice shall
15     * be included in all copies or substantial portions of the Software.
16     *
17     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20     * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21     * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22     * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24     * OTHER DEALINGS IN THE SOFTWARE.
25     *
26     * ----------------------------------------------------------------------- */
27    
28     /*
29     * run_init(consoledev, realroot, init, initargs)
30     *
31     * This function should be called as the last thing in kinit,
32     * from initramfs, it does the following:
33     *
34     * - Delete all files in the initramfs;
35     * - Remounts /real-root onto the root filesystem;
36     * - Chroots;
37     * - Opens /dev/console;
38     * - Spawns the specified init program (with arguments.)
39     *
40     * On failure, returns a human-readable error message.
41     */
42    
43     #include <assert.h>
44     #include <dirent.h>
45     #include <errno.h>
46     #include <fcntl.h>
47     #include <string.h>
48     #include <stdlib.h>
49     #include <stdio.h>
50     #include <unistd.h>
51     #include <sys/mount.h>
52     #include <sys/stat.h>
53     #include <sys/types.h>
54     #include <sys/vfs.h>
55     #include "run-init.h"
56    
57     /* Make it possible to compile on glibc by including constants that the
58     always-behind shipped glibc headers may not include. Classic example
59     on why the lack of ABI headers screw us up. */
60     #ifndef TMPFS_MAGIC
61     # define TMPFS_MAGIC 0x01021994
62     #endif
63     #ifndef RAMFS_MAGIC
64     # define RAMFS_MAGIC 0x858458f6
65     #endif
66     #ifndef MS_MOVE
67     # define MS_MOVE 8192
68     #endif
69    
70     static int nuke(const char *what);
71    
72     static int nuke_dirent(int len, const char *dir, const char *name, dev_t me)
73     {
74     int bytes = len + strlen(name) + 2;
75     char path[bytes];
76     int xlen;
77     struct stat st;
78    
79     xlen = snprintf(path, bytes, "%s/%s", dir, name);
80     assert(xlen < bytes);
81    
82     if (lstat(path, &st))
83     return ENOENT; /* Return 0 since already gone? */
84    
85     if (st.st_dev != me)
86     return 0; /* DO NOT recurse down mount points!!!!! */
87    
88     return nuke(path);
89     }
90    
91     /* Wipe the contents of a directory, but not the directory itself */
92     static int nuke_dir(const char *what)
93     {
94     int len = strlen(what);
95     DIR *dir;
96     struct dirent *d;
97     int err = 0;
98     struct stat st;
99    
100     if (lstat(what, &st))
101     return errno;
102    
103     if (!S_ISDIR(st.st_mode))
104     return ENOTDIR;
105    
106     if (!(dir = opendir(what))) {
107     /* EACCES means we can't read it. Might be empty and removable;
108     if not, the rmdir() in nuke() will trigger an error. */
109     return (errno == EACCES) ? 0 : errno;
110     }
111    
112     while ((d = readdir(dir))) {
113     /* Skip . and .. */
114     if (d->d_name[0] == '.' &&
115     (d->d_name[1] == '\0' ||
116     (d->d_name[1] == '.' && d->d_name[2] == '\0')))
117     continue;
118    
119     err = nuke_dirent(len, what, d->d_name, st.st_dev);
120     if (err) {
121     closedir(dir);
122     return err;
123     }
124     }
125    
126     closedir(dir);
127    
128     return 0;
129     }
130    
131     static int nuke(const char *what)
132     {
133     int rv;
134     int err = 0;
135    
136     rv = unlink(what);
137     if (rv < 0) {
138     if (errno == EISDIR) {
139     /* It's a directory. */
140     err = nuke_dir(what);
141     if (!err)
142     err = rmdir(what) ? errno : err;
143     } else {
144     err = errno;
145     }
146     }
147    
148     if (err) {
149     errno = err;
150     return err;
151     } else {
152     return 0;
153     }
154     }
155    
156     const char *run_init(const char *realroot, const char *console,
157     const char *init, char **initargs)
158     {
159 niro 1297 struct stat rst, cst;
160 niro 532 struct statfs sfs;
161     int confd;
162    
163     /* First, change to the new root directory */
164     if (chdir(realroot))
165     return "chdir to new root";
166    
167     /* This is a potentially highly destructive program. Take some
168     extra precautions. */
169    
170     /* Make sure the current directory is not on the same filesystem
171     as the root directory */
172     if (stat("/", &rst) || stat(".", &cst))
173     return "stat";
174    
175     if (rst.st_dev == cst.st_dev)
176     return "current directory on the same filesystem as the root";
177    
178     /* Make sure we're on a ramfs */
179     if (statfs("/", &sfs))
180     return "statfs /";
181     if (sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC)
182     return "rootfs not a ramfs or tmpfs";
183    
184     /* Okay, I think we should be safe... */
185    
186     /* Delete rootfs contents */
187     if (nuke_dir("/"))
188     return "nuking initramfs contents";
189    
190     /* Overmount the root */
191     if (mount(".", "/", NULL, MS_MOVE, NULL))
192     return "overmounting root";
193    
194     /* chroot, chdir */
195     if (chroot(".") || chdir("/"))
196     return "chroot";
197    
198     /* Open /dev/console */
199     if ((confd = open(console, O_RDWR)) < 0)
200     return "opening console";
201     dup2(confd, 0);
202     dup2(confd, 1);
203     dup2(confd, 2);
204     close(confd);
205    
206     /* Spawn init */
207     execv(init, initargs);
208     return init; /* Failed to spawn init */
209     }