spawn udevd & Co from 1st stage init
This commit is contained in:
parent
85b34d353b
commit
419b4c1201
285
init.c
285
init.c
@ -19,11 +19,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INIT_HEADERS
|
||||
#include "init-libc-headers.h"
|
||||
#else
|
||||
#include INIT_HEADERS
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#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"
|
||||
|
||||
@ -31,9 +38,13 @@
|
||||
#define TIOCSCTTY 0x540
|
||||
#endif
|
||||
|
||||
#define MKDEV(ma,mi) ((ma)<<8 | (mi))
|
||||
#define RAMFS_MAGIC 0x858458f6
|
||||
#define TMPFS_MAGIC 0x01021994
|
||||
|
||||
char * env[] = {
|
||||
"PATH=/usr/bin:/bin:/sbin:/usr/sbin:/usr/X11R6/bin",
|
||||
"LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib",
|
||||
"PATH=/usr/bin:/bin:/sbin:/usr/sbin",
|
||||
"LD_LIBRARY_PATH=/lib:/usr/lib",
|
||||
"HOME=/",
|
||||
"TERM=linux",
|
||||
"TERMINFO=/etc/terminfo",
|
||||
@ -42,6 +53,11 @@ char * env[] = {
|
||||
|
||||
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:
|
||||
*
|
||||
@ -51,21 +67,14 @@ char ** myenv = NULL;
|
||||
* 4) run from a floppy that's been loaded into a ramdisk
|
||||
*/
|
||||
|
||||
int klog_pid;
|
||||
|
||||
|
||||
void fatal_error(const char *msg)
|
||||
void fatal(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);
|
||||
}
|
||||
|
||||
void print_error(char *msg)
|
||||
{
|
||||
printf("E: %s\n", msg);
|
||||
}
|
||||
|
||||
void print_warning(char *msg)
|
||||
void warn(char *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
|
||||
* (2) listens to /dev/log and copy also this stuff (log from programs)
|
||||
*/
|
||||
void doklog()
|
||||
pid_t doklog()
|
||||
{
|
||||
int in, out, i, ii;
|
||||
int log;
|
||||
pid_t pid;
|
||||
char buf[1024];
|
||||
|
||||
/* open kernel message logger */
|
||||
in = open("/proc/kmsg", O_RDONLY,0);
|
||||
if (in < 0) {
|
||||
print_error("could not open /proc/kmsg");
|
||||
return;
|
||||
}
|
||||
if ((in = open("/proc/kmsg", O_RDONLY, 0)) < 0)
|
||||
fatal("failed to open /proc/kmsg");
|
||||
|
||||
if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644)) < 0) {
|
||||
perror("/tmp/syslog");
|
||||
print_error("error opening /tmp/syslog");
|
||||
sleep(5);
|
||||
return;
|
||||
}
|
||||
if (mknod("/dev/tty4", S_IFCHR, MKDEV(4, 4)) < 0 ||
|
||||
(out = open("/dev/tty4", O_WRONLY, 0)) < 0)
|
||||
fatal("failed to open /dev/tty4");
|
||||
|
||||
if ((klog_pid = fork())) {
|
||||
if ((pid = fork())) {
|
||||
if (pid < 0) fatal("doklog");
|
||||
close(in);
|
||||
close(log);
|
||||
return;
|
||||
} else {
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
}
|
||||
|
||||
out = open("/dev/tty4", O_WRONLY, 0);
|
||||
if (out < 0) {
|
||||
perror("can't open /dev/tty4");
|
||||
print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n");
|
||||
close(out);
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* child */
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
/* disable on-console syslog output */
|
||||
syslog(8, NULL, 1);
|
||||
klogctl(8, NULL, 1);
|
||||
|
||||
while (1) {
|
||||
i = read(in, buf, sizeof(buf));
|
||||
if (i > 0) {
|
||||
if (out >= 0)
|
||||
ii = write(out, buf, i);
|
||||
ii = write(log, buf, i);
|
||||
}
|
||||
while (1)
|
||||
if ((i = read(in, buf, sizeof(buf))) > 0)
|
||||
ii = write(out, 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;
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
@ -140,11 +147,11 @@ void grab_env(int fd)
|
||||
buf[i] = '\0';
|
||||
|
||||
if ((ep = myenv = malloc(sizeof(char *) * 32)) == NULL) {
|
||||
print_error("can't malloc env");
|
||||
warn("can't malloc env");
|
||||
myenv = env;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
*ep++ = p;
|
||||
p += strlen(p);
|
||||
@ -252,7 +259,7 @@ static int nuke(const char *what)
|
||||
|
||||
if ( err ) {
|
||||
errno = err;
|
||||
fatal_error(what);
|
||||
fatal(what);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -279,7 +286,7 @@ void unmount_filesystems(void)
|
||||
|
||||
fd = open("/proc/mounts", O_RDONLY, 0);
|
||||
if (fd < 1) {
|
||||
print_error("failed to open /proc/mounts");
|
||||
warn("failed to open /proc/mounts");
|
||||
sleep(2);
|
||||
return;
|
||||
}
|
||||
@ -332,66 +339,89 @@ void unmount_filesystems(void)
|
||||
}
|
||||
|
||||
if (nb) {
|
||||
printf("failed to umount some filesystems\n");
|
||||
while (1);
|
||||
fatal("failed to umount some filesystems\n");
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
struct stat rst, cst, ist;
|
||||
struct statfs sfs;
|
||||
pid_t installpid, childpid;
|
||||
pid_t pid, klogpid, udevpid;
|
||||
int wait_status;
|
||||
int fd;
|
||||
int fd = -1;
|
||||
int fds[2];
|
||||
int end_stage1 = 0;
|
||||
|
||||
|
||||
if (mount("/proc", "/proc", "proc", 0, NULL))
|
||||
fatal_error("Unable to mount proc filesystem");
|
||||
if (mount("/sysfs", "/sys", "sysfs", 0, NULL))
|
||||
fatal_error("Unable to mount sysfs filesystem");
|
||||
|
||||
fatal("failed to mount proc filesystem");
|
||||
if (mount("sysfs", "/sys", "sysfs", 0, NULL))
|
||||
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 */
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
|
||||
fd = open("/dev/console", O_RDWR, 0);
|
||||
if (fd < 0)
|
||||
fatal_error("failed to open /dev/console");
|
||||
|
||||
if (mknod("/dev/console", S_IFCHR, MKDEV(5, 1)) < 0 ||
|
||||
(fd = open("/dev/console", O_RDWR, 0)) < 0) {
|
||||
fatal("failed to open /dev/console");
|
||||
}
|
||||
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
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?) */
|
||||
setsid();
|
||||
if (ioctl(0, TIOCSCTTY, NULL)) {
|
||||
perror("TIOCSCTTY");
|
||||
print_error("could not set new controlling tty");
|
||||
warn("could not set new controlling tty");
|
||||
}
|
||||
|
||||
char my_hostname[] = "localhost.localdomain";
|
||||
if (sethostname(my_hostname, sizeof(my_hostname)) < 0)
|
||||
print_error("could not set hostname");
|
||||
if (sethostname("localhost.localdomain", sizeof("localhost.localdomain")) < 0)
|
||||
warn("could not set hostname");
|
||||
|
||||
/* the default domainname (as of 2.0.35) is "(none)", which confuses glibc */
|
||||
if (setdomainname("", 0) < 0)
|
||||
print_error("could not set domainname");
|
||||
warn("could not set domainname");
|
||||
|
||||
if (mkdir("/dev/.initramfs", 0755) < 0 ||
|
||||
mkdir("/dev/pts", 0755) < 0 ||
|
||||
mkdir("/dev/shm", 0755) < 0)
|
||||
fatal("mkdir\n");
|
||||
|
||||
doklog();
|
||||
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
|
||||
when:
|
||||
@ -404,33 +434,19 @@ int main(int argc, char **argv)
|
||||
|
||||
/* create a pipe for env passing */
|
||||
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[1], F_SETFD, 0);
|
||||
|
||||
if (!(installpid = fork())) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
pid = spawn(stage);
|
||||
close(fds[1]);
|
||||
|
||||
while (!end_stage1) {
|
||||
childpid = wait4(-1, &wait_status, 0, NULL);
|
||||
if (childpid == installpid)
|
||||
end_stage1 = 1;
|
||||
}
|
||||
while (pid != wait(&wait_status));
|
||||
|
||||
if (!(WIFEXITED(wait_status))) {
|
||||
/* 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))
|
||||
printf("-- received signal %d", WTERMSIG(wait_status));
|
||||
printf("\n");
|
||||
@ -455,15 +471,23 @@ int main(int argc, char **argv)
|
||||
|
||||
grab_env(fds[0]);
|
||||
|
||||
kill(klog_pid, 9);
|
||||
waitpid(klog_pid, &wait_status, 0);
|
||||
if (waitpid(spawn(udevsettle), &wait_status, 0) < 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 ...");
|
||||
|
||||
/* rest was seamlessy stolen from klibc */
|
||||
/* First, change to the new root directory */
|
||||
if (chdir(STAGE2_LOCATION))
|
||||
fatal_error("chdir to new root");
|
||||
fatal("chdir to new root");
|
||||
|
||||
/* This is a potentially highly destructive program. Take some
|
||||
extra precautions. */
|
||||
@ -471,71 +495,66 @@ int main(int argc, char **argv)
|
||||
/* Make sure the current directory is not on the same filesystem
|
||||
as the root directory */
|
||||
if ( stat("/", &rst) || stat(".", &cst) )
|
||||
fatal_error("stat");
|
||||
fatal("stat");
|
||||
|
||||
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 */
|
||||
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 */
|
||||
if ( statfs("/", &sfs) )
|
||||
fatal_error("statfs /");
|
||||
fatal("statfs /");
|
||||
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... */
|
||||
|
||||
/* overmount image under new root if needed */
|
||||
if ( statfs(IMAGE_LOCATION, &sfs) )
|
||||
fatal_error("statfs "IMAGE_LOCATION);
|
||||
fatal("statfs "IMAGE_LOCATION);
|
||||
/* if something is mounted under IMAGE_LOCATION ? */
|
||||
if ( sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC ) {
|
||||
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 */
|
||||
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 ( mount(IMAGE_LOCATION, "." IMAGE_LOCATION "/isolinux", NULL, MS_MOVE, NULL) )
|
||||
fatal_error("overmounting nested image location");
|
||||
fatal("overmounting nested image location");
|
||||
}
|
||||
|
||||
umount("/sys");
|
||||
umount("/proc/bus/usb");
|
||||
umount("/proc");
|
||||
|
||||
if (mount("/dev", "./dev", NULL, MS_MOVE, NULL))
|
||||
fatal("overmounting /dev");
|
||||
|
||||
/* Delete rootfs contents */
|
||||
if ( nuke_dir("/") )
|
||||
fatal_error("nuking initramfs contents");
|
||||
if (nuke_dir("/"))
|
||||
fatal("nuking initramfs contents");
|
||||
|
||||
/* Overmount the root */
|
||||
if ( mount(".", "/", NULL, MS_MOVE, NULL) )
|
||||
fatal_error("overmounting root");
|
||||
if (mount(".", "/", NULL, MS_MOVE, NULL))
|
||||
fatal("overmounting root");
|
||||
|
||||
/* chroot, chdir */
|
||||
if (chroot(".") || chdir("/"))
|
||||
fatal_error("chroot");
|
||||
|
||||
/* Open /dev/console */
|
||||
if ((fd = open("/dev/console", O_RDWR)) != -1) {
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
close(fd);
|
||||
}
|
||||
fatal("chroot");
|
||||
|
||||
/* Check for given init */
|
||||
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 */
|
||||
printf(" done.\n");
|
||||
|
||||
argv[0] = STAGE2_BINNAME;
|
||||
execve(argv[0], argv, myenv);
|
||||
fatal_error("stage2"); /* Failed to spawn init */
|
||||
fatal("stage2"); /* Failed to spawn init */
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user