spawn udevd & Co from 1st stage init

This commit is contained in:
Sergey Bolshakov 2008-02-29 17:37:40 +03:00
parent 85b34d353b
commit 419b4c1201

275
init.c
View File

@ -19,11 +19,18 @@
* *
*/ */
#ifndef INIT_HEADERS #include <errno.h>
#include "init-libc-headers.h" #include <string.h>
#else #include <stdlib.h>
#include INIT_HEADERS #include <stdio.h>
#endif #include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/klog.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <sys/wait.h>
#include "config-stage1.h" #include "config-stage1.h"
@ -31,9 +38,13 @@
#define TIOCSCTTY 0x540 #define TIOCSCTTY 0x540
#endif #endif
#define MKDEV(ma,mi) ((ma)<<8 | (mi))
#define RAMFS_MAGIC 0x858458f6
#define TMPFS_MAGIC 0x01021994
char * env[] = { char * env[] = {
"PATH=/usr/bin:/bin:/sbin:/usr/sbin:/usr/X11R6/bin", "PATH=/usr/bin:/bin:/sbin:/usr/sbin",
"LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib", "LD_LIBRARY_PATH=/lib:/usr/lib",
"HOME=/", "HOME=/",
"TERM=linux", "TERM=linux",
"TERMINFO=/etc/terminfo", "TERMINFO=/etc/terminfo",
@ -42,6 +53,11 @@ char * env[] = {
char ** myenv = NULL; char ** myenv = NULL;
char *stage[] = {"/sbin/stage1", NULL};
char *udevd[] = {"/sbin/udevd", NULL};
char *udevtrigger[] = {"/sbin/udevtrigger", NULL};
char *udevsettle[] = {"/sbin/udevsettle", NULL};
/* /*
* this needs to handle the following cases: * this needs to handle the following cases:
* *
@ -51,21 +67,14 @@ char ** myenv = NULL;
* 4) run from a floppy that's been loaded into a ramdisk * 4) run from a floppy that's been loaded into a ramdisk
*/ */
int klog_pid; void fatal(const char *msg)
void fatal_error(const char *msg)
{ {
printf("FATAL ERROR IN INIT: %s : %s\n\nI can't recover from this, please reboot manually and send bugreport.\n", msg,strerror(errno)); printf("FATAL ERROR IN INIT: %s\nI can't recover from this,"
"please reboot manually and send bugreport.\n", msg);
while (1); while (1);
} }
void print_error(char *msg) void warn(char *msg)
{
printf("E: %s\n", msg);
}
void print_warning(char *msg)
{ {
printf("W: %s\n", msg); printf("W: %s\n", msg);
} }
@ -74,52 +83,50 @@ void print_warning(char *msg)
* (1) watch /proc/kmsg and copy the stuff to /dev/tty4 * (1) watch /proc/kmsg and copy the stuff to /dev/tty4
* (2) listens to /dev/log and copy also this stuff (log from programs) * (2) listens to /dev/log and copy also this stuff (log from programs)
*/ */
void doklog() pid_t doklog()
{ {
int in, out, i, ii; int in, out, i, ii;
int log; pid_t pid;
char buf[1024]; char buf[1024];
/* open kernel message logger */ /* open kernel message logger */
in = open("/proc/kmsg", O_RDONLY,0); if ((in = open("/proc/kmsg", O_RDONLY, 0)) < 0)
if (in < 0) { fatal("failed to open /proc/kmsg");
print_error("could not open /proc/kmsg");
return;
}
if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644)) < 0) { if (mknod("/dev/tty4", S_IFCHR, MKDEV(4, 4)) < 0 ||
perror("/tmp/syslog"); (out = open("/dev/tty4", O_WRONLY, 0)) < 0)
print_error("error opening /tmp/syslog"); fatal("failed to open /dev/tty4");
sleep(5);
return;
}
if ((klog_pid = fork())) { if ((pid = fork())) {
if (pid < 0) fatal("doklog");
close(in); close(in);
close(log); close(out);
return; return pid;
} else {
close(0);
close(1);
close(2);
} }
out = open("/dev/tty4", O_WRONLY, 0); /* child */
if (out < 0) { close(0);
perror("can't open /dev/tty4"); close(1);
print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n"); close(2);
}
/* disable on-console syslog output */ /* disable on-console syslog output */
syslog(8, NULL, 1); klogctl(8, NULL, 1);
while (1) { while (1)
i = read(in, buf, sizeof(buf)); if ((i = read(in, buf, sizeof(buf))) > 0)
if (i > 0) { ii = write(out, buf, i);
if (out >= 0) }
ii = write(out, buf, i);
ii = write(log, buf, i); pid_t spawn(char *av[])
} {
pid_t pid;
if ((pid = fork())) {
if (pid < 0) fatal(av[0]);
return pid;
} else {
execve(av[0], av, env);
perror(av[0]);
exit(1);
} }
} }
@ -131,7 +138,7 @@ void grab_env(int fd)
int i; int i;
if ((i = read(fd, buf, sizeof(buf))) < 0) { if ((i = read(fd, buf, sizeof(buf))) < 0) {
print_error("failed to read env from pipe"); warn("failed to read env from pipe");
myenv = env; myenv = env;
return; return;
} }
@ -140,7 +147,7 @@ void grab_env(int fd)
buf[i] = '\0'; buf[i] = '\0';
if ((ep = myenv = malloc(sizeof(char *) * 32)) == NULL) { if ((ep = myenv = malloc(sizeof(char *) * 32)) == NULL) {
print_error("can't malloc env"); warn("can't malloc env");
myenv = env; myenv = env;
return; return;
} }
@ -252,7 +259,7 @@ static int nuke(const char *what)
if ( err ) { if ( err ) {
errno = err; errno = err;
fatal_error(what); fatal(what);
} }
return 0; return 0;
} }
@ -279,7 +286,7 @@ void unmount_filesystems(void)
fd = open("/proc/mounts", O_RDONLY, 0); fd = open("/proc/mounts", O_RDONLY, 0);
if (fd < 1) { if (fd < 1) {
print_error("failed to open /proc/mounts"); warn("failed to open /proc/mounts");
sleep(2); sleep(2);
return; return;
} }
@ -332,66 +339,89 @@ void unmount_filesystems(void)
} }
if (nb) { if (nb) {
printf("failed to umount some filesystems\n"); fatal("failed to umount some filesystems\n");
while (1);
} }
} }
#define MAJOR(dev) ((dev)>>8)
#define MINOR(dev) ((dev) & 0xff)
#define MKDEV(ma,mi) ((ma)<<8 | (mi))
#define DEV_PERM 00400|00200|00040|00020
#define CHR_DEV 0020000|DEV_PERM
#define BLK_DEV 0060000|DEV_PERM
#define RAMFS_MAGIC 0x858458f6
#define TMPFS_MAGIC 0x01021994
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct stat rst, cst, ist; struct stat rst, cst, ist;
struct statfs sfs; struct statfs sfs;
pid_t installpid, childpid; pid_t pid, klogpid, udevpid;
int wait_status; int wait_status;
int fd; int fd = -1;
int fds[2]; int fds[2];
int end_stage1 = 0;
if (mount("/proc", "/proc", "proc", 0, NULL)) if (mount("/proc", "/proc", "proc", 0, NULL))
fatal_error("Unable to mount proc filesystem"); fatal("failed to mount proc filesystem");
if (mount("/sysfs", "/sys", "sysfs", 0, NULL)) if (mount("sysfs", "/sys", "sysfs", 0, NULL))
fatal_error("Unable to mount sysfs filesystem"); fatal("failed to mount sysfs filesystem");
if (mount("udev", "/dev", "tmpfs", 0, "size=10M,mode=0755"))
fatal("failed to mount tmpfs filesystem");
/* ignore Control-C and keyboard stop signals */ /* ignore Control-C and keyboard stop signals */
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN); signal(SIGTSTP, SIG_IGN);
fd = open("/dev/console", O_RDWR, 0); if (mknod("/dev/console", S_IFCHR, MKDEV(5, 1)) < 0 ||
if (fd < 0) (fd = open("/dev/console", O_RDWR, 0)) < 0) {
fatal_error("failed to open /dev/console"); fatal("failed to open /dev/console");
}
dup2(fd, 0); dup2(fd, 0);
dup2(fd, 1); dup2(fd, 1);
dup2(fd, 2); dup2(fd, 2);
close(fd); close(fd);
if (mknod("/dev/null", S_IFCHR, MKDEV(1, 3)) < 0)
fatal("failed to create /dev/null");
/* I set me up as session leader (probably not necessary?) */ /* I set me up as session leader (probably not necessary?) */
setsid(); setsid();
if (ioctl(0, TIOCSCTTY, NULL)) { if (ioctl(0, TIOCSCTTY, NULL)) {
perror("TIOCSCTTY"); perror("TIOCSCTTY");
print_error("could not set new controlling tty"); warn("could not set new controlling tty");
} }
char my_hostname[] = "localhost.localdomain"; if (sethostname("localhost.localdomain", sizeof("localhost.localdomain")) < 0)
if (sethostname(my_hostname, sizeof(my_hostname)) < 0) warn("could not set hostname");
print_error("could not set hostname");
/* the default domainname (as of 2.0.35) is "(none)", which confuses glibc */ /* the default domainname (as of 2.0.35) is "(none)", which confuses glibc */
if (setdomainname("", 0) < 0) if (setdomainname("", 0) < 0)
print_error("could not set domainname"); warn("could not set domainname");
doklog(); if (mkdir("/dev/.initramfs", 0755) < 0 ||
mkdir("/dev/pts", 0755) < 0 ||
mkdir("/dev/shm", 0755) < 0)
fatal("mkdir\n");
if ((fd = open("/proc/sys/kernel/hotplug", O_WRONLY, 0)) < 0 ||
write(fd, "\n", sizeof("\n")) < sizeof("\n"))
fatal("/proc/sys/kernel/hotplug\n");
close(fd);
klogpid = doklog();
if (mkdir("/dev/.udev", 0755) < 0 ||
mkdir("/dev/.udev/db", 0755) < 0)
fatal("/dev/.udev/db");
printf("Spawning udevd...");
udevpid = spawn(udevd);
if (mkdir("/dev/.udev/queue", 0755) < 0 && errno != EEXIST)
fatal("cannot create /dev/.udev/queue");
if (waitpid(spawn(udevtrigger), &wait_status, 0) < 0 ||
!(WIFEXITED(wait_status)))
warn("udevtrigger");
if (waitpid(spawn(udevsettle), &wait_status, 0) < 0 ||
!(WIFEXITED(wait_status)))
warn("udevsettle");
printf("done\n");
/* Go into normal init mode - keep going, and then do a orderly shutdown /* Go into normal init mode - keep going, and then do a orderly shutdown
when: when:
@ -404,33 +434,19 @@ int main(int argc, char **argv)
/* create a pipe for env passing */ /* create a pipe for env passing */
if (pipe(fds) < 0) if (pipe(fds) < 0)
fatal_error("failed to create env pipe"); fatal("failed to create env pipe");
fcntl(fds[0], F_SETFD, 1); fcntl(fds[0], F_SETFD, 1);
fcntl(fds[1], F_SETFD, 0); fcntl(fds[1], F_SETFD, 0);
if (!(installpid = fork())) { pid = spawn(stage);
/* child */
char * child_argv[2];
child_argv[0] = "/sbin/stage1";
child_argv[1] = NULL;
execve(child_argv[0], child_argv, env);
printf("error in exec of stage1 :-(\n");
return 0;
}
close(fds[1]); close(fds[1]);
while (pid != wait(&wait_status));
while (!end_stage1) {
childpid = wait4(-1, &wait_status, 0, NULL);
if (childpid == installpid)
end_stage1 = 1;
}
if (!(WIFEXITED(wait_status))) { if (!(WIFEXITED(wait_status))) {
/* something went wrong */ /* something went wrong */
printf("wait_status: %i, install exited abnormally :-( ", wait_status); printf("wait_status: %i, install exited abnormally ", wait_status);
if (WIFSIGNALED(wait_status)) if (WIFSIGNALED(wait_status))
printf("-- received signal %d", WTERMSIG(wait_status)); printf("-- received signal %d", WTERMSIG(wait_status));
printf("\n"); printf("\n");
@ -455,15 +471,23 @@ int main(int argc, char **argv)
grab_env(fds[0]); grab_env(fds[0]);
kill(klog_pid, 9); if (waitpid(spawn(udevsettle), &wait_status, 0) < 0 ||
waitpid(klog_pid, &wait_status, 0); !(WIFEXITED(wait_status)))
warn("udevsettle");
kill(udevpid, 9);
waitpid(udevpid, &wait_status, 0);
nuke_dir("/dev/.udev/queue");
kill(klogpid, 9);
waitpid(klogpid, &wait_status, 0);
printf("Spawning init ..."); printf("Spawning init ...");
/* rest was seamlessy stolen from klibc */ /* rest was seamlessy stolen from klibc */
/* First, change to the new root directory */ /* First, change to the new root directory */
if (chdir(STAGE2_LOCATION)) if (chdir(STAGE2_LOCATION))
fatal_error("chdir to new root"); fatal("chdir to new root");
/* This is a potentially highly destructive program. Take some /* This is a potentially highly destructive program. Take some
extra precautions. */ extra precautions. */
@ -471,71 +495,66 @@ int main(int argc, char **argv)
/* Make sure the current directory is not on the same filesystem /* Make sure the current directory is not on the same filesystem
as the root directory */ as the root directory */
if ( stat("/", &rst) || stat(".", &cst) ) if ( stat("/", &rst) || stat(".", &cst) )
fatal_error("stat"); fatal("stat");
if ( rst.st_dev == cst.st_dev ) if ( rst.st_dev == cst.st_dev )
fatal_error("current directory on the same filesystem as the root"); fatal("current directory on the same filesystem as the root");
/* The initramfs should have /init */ /* The initramfs should have /init */
if ( stat("/init", &ist) || !S_ISREG(ist.st_mode) ) if ( stat("/init", &ist) || !S_ISREG(ist.st_mode) )
fatal_error("can't find /init on initramfs"); fatal("can't find /init on initramfs");
/* Make sure we're on a ramfs */ /* Make sure we're on a ramfs */
if ( statfs("/", &sfs) ) if ( statfs("/", &sfs) )
fatal_error("statfs /"); fatal("statfs /");
if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC ) if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC )
fatal_error("rootfs not a ramfs or tmpfs"); fatal("rootfs not a ramfs or tmpfs");
/* Okay, I think we should be safe... */ /* Okay, I think we should be safe... */
/* overmount image under new root if needed */ /* overmount image under new root if needed */
if ( statfs(IMAGE_LOCATION, &sfs) ) if ( statfs(IMAGE_LOCATION, &sfs) )
fatal_error("statfs "IMAGE_LOCATION); fatal("statfs "IMAGE_LOCATION);
/* if something is mounted under IMAGE_LOCATION ? */ /* if something is mounted under IMAGE_LOCATION ? */
if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC ) { if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC ) {
if ( mount(IMAGE_LOCATION, "." IMAGE_LOCATION, NULL, MS_MOVE, NULL) ) if ( mount(IMAGE_LOCATION, "." IMAGE_LOCATION, NULL, MS_MOVE, NULL) )
fatal_error("overmounting image location"); fatal("overmounting image location");
/* test for nested mount: disk or nfs with iso image */ /* test for nested mount: disk or nfs with iso image */
if ( statfs(IMAGE_LOCATION, &sfs) ) if ( statfs(IMAGE_LOCATION, &sfs) )
fatal_error("nested statfs "IMAGE_LOCATION); fatal("nested statfs "IMAGE_LOCATION);
if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC ) if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC )
if ( mount(IMAGE_LOCATION, "." IMAGE_LOCATION "/isolinux", NULL, MS_MOVE, NULL) ) if ( mount(IMAGE_LOCATION, "." IMAGE_LOCATION "/isolinux", NULL, MS_MOVE, NULL) )
fatal_error("overmounting nested image location"); fatal("overmounting nested image location");
} }
umount("/sys"); umount("/sys");
umount("/proc/bus/usb"); umount("/proc/bus/usb");
umount("/proc"); umount("/proc");
if (mount("/dev", "./dev", NULL, MS_MOVE, NULL))
fatal("overmounting /dev");
/* Delete rootfs contents */ /* Delete rootfs contents */
if ( nuke_dir("/") ) if (nuke_dir("/"))
fatal_error("nuking initramfs contents"); fatal("nuking initramfs contents");
/* Overmount the root */ /* Overmount the root */
if ( mount(".", "/", NULL, MS_MOVE, NULL) ) if (mount(".", "/", NULL, MS_MOVE, NULL))
fatal_error("overmounting root"); fatal("overmounting root");
/* chroot, chdir */ /* chroot, chdir */
if (chroot(".") || chdir("/")) if (chroot(".") || chdir("/"))
fatal_error("chroot"); fatal("chroot");
/* Open /dev/console */
if ((fd = open("/dev/console", O_RDWR)) != -1) {
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
/* Check for given init */ /* Check for given init */
if (stat(STAGE2_BINNAME, &ist) || !S_ISREG(ist.st_mode)) if (stat(STAGE2_BINNAME, &ist) || !S_ISREG(ist.st_mode))
fatal_error("can't find init on root fs"); fatal("can't find init on root fs");
/* Spawn init */ /* Spawn init */
printf(" done.\n"); printf(" done.\n");
argv[0] = STAGE2_BINNAME; argv[0] = STAGE2_BINNAME;
execve(argv[0], argv, myenv); execve(argv[0], argv, myenv);
fatal_error("stage2"); /* Failed to spawn init */ fatal("stage2"); /* Failed to spawn init */
return 0; return 0;
} }