1 /* febootstrap-supermin-helper reimplementation in C.
2 * Copyright (C) 2009-2010 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* This very minimal init "script" goes in the mini-initrd used to
20 * boot the ext2-based appliance. Note we have no shell, so we cannot
21 * use system(3) to run external commands. In fact, we don't have
22 * very much at all, except this program, and some kernel modules.
34 #include <sys/types.h>
35 #include <sys/mount.h>
39 #include <asm/unistd.h>
45 extern long init_module (void *, unsigned long, const char *);
47 /* translation taken from module-init-tools/insmod.c */
48 static const char *moderror(int err)
52 return "Invalid module format";
54 return "Unknown symbol in module";
56 return "Module has wrong symbol version";
58 return "Invalid parameters";
64 /* Leave this enabled for now. When we get more confident in the boot
65 * process we can turn this off or make it configurable.
69 static void mount_proc (void);
70 static void print_uptime (void);
71 static void insmod (const char *filename);
72 static void show_directory (const char *dir);
74 static char line[1024];
82 fprintf (stderr, "febootstrap: ext2 mini initrd starting up\n");
84 /* Create some fixed directories. */
86 mkdir ("/root", 0755);
91 fprintf (stderr, "febootstrap: mounting /sys\n");
92 if (mount ("sysfs", "/sys", "sysfs", 0, "") == -1) {
93 perror ("mount: /sys");
97 FILE *fp = fopen ("/modules", "r");
99 perror ("fopen: /modules");
102 while (fgets (line, sizeof line, fp)) {
103 size_t n = strlen (line);
104 if (n > 0 && line[n-1] == '\n')
107 /* XXX Because of the way we construct the module list, the
108 * "modules" file can contain non-existent modules. Ignore those
109 * for now. Really we should add them as missing dependencies.
110 * See ext2initrd.c:ext2_make_initrd().
112 if (access (line, R_OK) == 0)
115 fprintf (stderr, "skipped %s, module is missing\n", line);
119 /* Look for the ext2 filesystem device. It's always the last
120 * one that was added.
121 * XXX More than 25 devices?
123 char path[] = "/sys/block/xdx/dev";
124 char class[3] = { 'v', 's', 'h' };
127 for (i = 0; i < sizeof class; ++i) {
128 for (j = 'z'; j >= 'a'; --j) {
131 fp = fopen (path, "r");
137 "febootstrap: no ext2 root device found\n"
138 "Please include FULL verbose output in your bug report.\n");
143 fprintf (stderr, "febootstrap: picked %s as root device\n", path);
145 fgets (line, sizeof line, fp);
146 int major = atoi (line);
147 char *p = line + strcspn (line, ":") + 1;
148 int minor = atoi (p);
151 if (umount ("/sys") == -1) {
152 perror ("umount: /sys");
157 fprintf (stderr, "febootstrap: creating /dev/root as block special %d:%d\n",
160 if (mknod ("/dev/root", S_IFBLK|0700, makedev (major, minor)) == -1) {
161 perror ("mknod: /dev/root");
165 /* Mount new root and chroot to it. */
167 fprintf (stderr, "febootstrap: mounting new root on /root\n");
168 if (mount ("/dev/root", "/root", "ext2", MS_NOATIME, "") == -1) {
169 perror ("mount: /root");
173 /* Note that pivot_root won't work. See the note in
174 * Documentation/filesystems/ramfs-rootfs-initramfs.txt
175 * We could remove the old initramfs files, but let's not bother.
178 fprintf (stderr, "febootstrap: chroot\n");
180 if (chroot ("/root") == -1) {
181 perror ("chroot: /root");
187 /* Run /init from ext2 filesystem. */
189 execl ("/init", "init", NULL);
190 perror ("execl: /init");
192 /* /init failed to execute, but why? Before we ditch, print some
193 * debug. Although we have a full appliance, the fact that /init
194 * failed to run means we may not be able to run any commands.
196 show_directory ("/");
197 show_directory ("/bin");
198 show_directory ("/lib");
199 show_directory ("/lib64");
206 insmod (const char *filename)
211 fprintf (stderr, "febootstrap: internal insmod %s\n", filename);
214 gzFile gzfp = gzopen (filename, "rb");
215 int capacity = 64*1024;
216 char *buf = (char *) malloc (capacity);
217 int tmpsize = 8 * 1024;
224 fprintf (stderr, "insmod: gzopen failed: %s", filename);
227 while ((num = gzread (gzfp, tmp, tmpsize)) > 0) {
228 if (num > capacity) {
229 buf = (char*) realloc (buf, size*2);
232 memcpy (buf+size, tmp, num);
237 perror ("insmod: gzread");
242 int fd = open (filename, O_RDONLY);
244 fprintf (stderr, "insmod: open: %s: %m\n", filename);
248 if (fstat (fd, &st) == -1) {
249 perror ("insmod: fstat");
256 ssize_t rc = read (fd, buf + offset, size - offset);
258 perror ("insmod: read");
262 } while (offset < size);
266 if (init_module (buf, size, "") != 0) {
267 fprintf (stderr, "insmod: init_module: %s: %s\n", filename, moderror (errno));
268 /* However ignore the error because this can just happen because
269 * of a missing device.
278 /* Mount /proc unless it's mounted already. */
282 if (access ("/proc/uptime", R_OK) == -1) {
283 mkdir ("/proc", 0755);
286 fprintf (stderr, "febootstrap: mounting /proc\n");
288 if (mount ("proc", "/proc", "proc", 0, "") == -1) {
289 perror ("mount: /proc");
295 /* Print contents of /proc/uptime. */
299 FILE *fp = fopen ("/proc/uptime", "r");
301 perror ("/proc/uptime");
305 fgets (line, sizeof line, fp);
308 fprintf (stderr, "febootstrap: uptime: %s", line);
311 /* Display a directory on stderr. This is used for debugging only. */
316 case DT_BLK: return 'b';
317 case DT_CHR: return 'c';
318 case DT_DIR: return 'd';
319 case DT_FIFO: return 'p';
320 case DT_LNK: return 'l';
321 case DT_REG: return '-';
322 case DT_SOCK: return 's';
323 case DT_UNKNOWN: return 'u';
329 show_directory (const char *dirname)
334 char link[PATH_MAX+1];
337 fprintf (stderr, "febootstrap: debug: listing directory %s\n", dirname);
339 if (chdir (dirname) == -1) {
351 while ((d = readdir (dir)) != NULL) {
352 fprintf (stderr, "%5lu %c %-16s", d->d_ino, dirtype (d->d_type), d->d_name);
353 if (lstat (d->d_name, &statbuf) >= 0) {
354 fprintf (stderr, " %06o %ld %d:%d",
355 statbuf.st_mode, statbuf.st_size,
356 statbuf.st_uid, statbuf.st_gid);
357 if (S_ISLNK (statbuf.st_mode)) {
358 n = readlink (d->d_name, link, PATH_MAX);
361 fprintf (stderr, " -> %s", link);
365 fprintf (stderr, "\n");