Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 5468 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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 <alloca.h>
44     #include <assert.h>
45     #include <dirent.h>
46     #include <errno.h>
47     #include <fcntl.h>
48     #include <string.h>
49     #include <stdlib.h>
50     #include <stdio.h>
51     #include <unistd.h>
52     #include <sys/mount.h>
53     #include <sys/stat.h>
54     #include <sys/types.h>
55     #include <sys/vfs.h>
56     #include "run-init.h"
57    
58     /* Make it possible to compile on glibc by including constants that the
59     always-behind shipped glibc headers may not include. Classic example
60     on why the lack of ABI headers screw us up. */
61     #ifndef TMPFS_MAGIC
62     # define TMPFS_MAGIC 0x01021994
63     #endif
64     #ifndef RAMFS_MAGIC
65     # define RAMFS_MAGIC 0x858458f6
66     #endif
67     #ifndef MS_MOVE
68     # define MS_MOVE 8192
69     #endif
70    
71     static int nuke(const char *what);
72    
73     static int nuke_dirent(int len, const char *dir, const char *name, dev_t me)
74     {
75     int bytes = len + strlen(name) + 2;
76     char path[bytes];
77     int xlen;
78     struct stat st;
79    
80     xlen = snprintf(path, bytes, "%s/%s", dir, name);
81     assert(xlen < bytes);
82    
83     if (lstat(path, &st))
84     return ENOENT; /* Return 0 since already gone? */
85    
86     if (st.st_dev != me)
87     return 0; /* DO NOT recurse down mount points!!!!! */
88    
89     return nuke(path);
90     }
91    
92     /* Wipe the contents of a directory, but not the directory itself */
93     static int nuke_dir(const char *what)
94     {
95     int len = strlen(what);
96     DIR *dir;
97     struct dirent *d;
98     int err = 0;
99     struct stat st;
100    
101     if (lstat(what, &st))
102     return errno;
103    
104     if (!S_ISDIR(st.st_mode))
105     return ENOTDIR;
106    
107     if (!(dir = opendir(what))) {
108     /* EACCES means we can't read it. Might be empty and removable;
109     if not, the rmdir() in nuke() will trigger an error. */
110     return (errno == EACCES) ? 0 : errno;
111     }
112    
113     while ((d = readdir(dir))) {
114     /* Skip . and .. */
115     if (d->d_name[0] == '.' &&
116     (d->d_name[1] == '\0' ||
117     (d->d_name[1] == '.' && d->d_name[2] == '\0')))
118     continue;
119    
120     err = nuke_dirent(len, what, d->d_name, st.st_dev);
121     if (err) {
122     closedir(dir);
123     return err;
124     }
125     }
126    
127     closedir(dir);
128    
129     return 0;
130     }
131    
132     static int nuke(const char *what)
133     {
134     int rv;
135     int err = 0;
136    
137     rv = unlink(what);
138     if (rv < 0) {
139     if (errno == EISDIR) {
140     /* It's a directory. */
141     err = nuke_dir(what);
142     if (!err)
143     err = rmdir(what) ? errno : err;
144     } else {
145     err = errno;
146     }
147     }
148    
149     if (err) {
150     errno = err;
151     return err;
152     } else {
153     return 0;
154     }
155     }
156    
157     const char *run_init(const char *realroot, const char *console,
158     const char *init, char **initargs)
159     {
160     struct stat rst, cst, ist;
161     struct statfs sfs;
162     int confd;
163    
164     /* First, change to the new root directory */
165     if (chdir(realroot))
166     return "chdir to new root";
167    
168     /* This is a potentially highly destructive program. Take some
169     extra precautions. */
170    
171     /* Make sure the current directory is not on the same filesystem
172     as the root directory */
173     if (stat("/", &rst) || stat(".", &cst))
174     return "stat";
175    
176     if (rst.st_dev == cst.st_dev)
177     return "current directory on the same filesystem as the root";
178    
179     /* The initramfs should have /init */
180     if (stat("/init", &ist) || !S_ISREG(ist.st_mode))
181     return "can't find /init on initramfs";
182    
183     /* Make sure we're on a ramfs */
184     if (statfs("/", &sfs))
185     return "statfs /";
186     if (sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC)
187     return "rootfs not a ramfs or tmpfs";
188    
189     /* Okay, I think we should be safe... */
190    
191     /* Delete rootfs contents */
192     if (nuke_dir("/"))
193     return "nuking initramfs contents";
194    
195     /* Overmount the root */
196     if (mount(".", "/", NULL, MS_MOVE, NULL))
197     return "overmounting root";
198    
199     /* chroot, chdir */
200     if (chroot(".") || chdir("/"))
201     return "chroot";
202    
203     /* Open /dev/console */
204     if ((confd = open(console, O_RDWR)) < 0)
205     return "opening console";
206     dup2(confd, 0);
207     dup2(confd, 1);
208     dup2(confd, 2);
209     close(confd);
210    
211     /* Spawn init */
212     execv(init, initargs);
213     return init; /* Failed to spawn init */
214     }