X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=helper%2Finit.c;h=34a84507598e58ec303cf4316b69673dc07cc1df;hb=57b3004bde579b986523c43e3a0e6693fd49dd21;hp=5dd05cfc544258ae5bde4f26c2a336275e540044;hpb=89e336ee166be538e376d288fb2b3fbbffd66d4c;p=febootstrap.git diff --git a/helper/init.c b/helper/init.c index 5dd05cf..34a8450 100644 --- a/helper/init.c +++ b/helper/init.c @@ -19,8 +19,7 @@ /* This very minimal init "script" goes in the mini-initrd used to * boot the ext2-based appliance. Note we have no shell, so we cannot * use system(3) to run external commands. In fact, we don't have - * very much at all, except this program, insmod.static, and some - * kernel modules. + * very much at all, except this program, and some kernel modules. */ #include @@ -30,24 +29,51 @@ #include #include #include +#include +#include #include #include #include #include +#include + +extern long init_module (void *, unsigned long, const char *); + +/* translation taken from module-init-tools/insmod.c */ +static const char *moderror(int err) +{ + switch (err) { + case ENOEXEC: + return "Invalid module format"; + case ENOENT: + return "Unknown symbol in module"; + case ESRCH: + return "Module has wrong symbol version"; + case EINVAL: + return "Invalid parameters"; + default: + return strerror(err); + } +} + /* Leave this enabled for now. When we get more confident in the boot * process we can turn this off or make it configurable. */ #define verbose 1 +static void mount_proc (void); static void print_uptime (void); static void insmod (const char *filename); +static void show_directory (const char *dir); static char line[1024]; -void +int main () { + mount_proc (); + print_uptime (); fprintf (stderr, "febootstrap: ext2 mini initrd starting up\n"); @@ -73,7 +99,16 @@ main () size_t n = strlen (line); if (n > 0 && line[n-1] == '\n') line[--n] = '\0'; - insmod (line); + + /* XXX Because of the way we construct the module list, the + * "modules" file can contain non-existent modules. Ignore those + * for now. Really we should add them as missing dependencies. + * See ext2initrd.c:ext2_make_initrd(). + */ + if (access (line, R_OK) == 0) + insmod (line); + else + fprintf (stderr, "skipped %s, module is missing\n", line); } fclose (fp); @@ -149,6 +184,17 @@ main () print_uptime (); execl ("/init", "init", NULL); perror ("execl: /init"); + + /* /init failed to execute, but why? Before we ditch, print some + * debug. Although we have a full appliance, the fact that /init + * failed to run means we may not be able to run any commands. + */ + show_directory ("/"); + show_directory ("/bin"); + show_directory ("/lib"); + show_directory ("/lib64"); + fflush (stderr); + exit (EXIT_FAILURE); } @@ -156,26 +202,53 @@ static void insmod (const char *filename) { if (verbose) - fprintf (stderr, "febootstrap: insmod %s\n", filename); + fprintf (stderr, "febootstrap: internal insmod %s\n", filename); - pid_t pid = fork (); - if (pid == -1) { - perror ("insmod: fork"); + int fd = open (filename, O_RDONLY); + if (fd == -1) { + fprintf (stderr, "insmod: open: %s: %m\n", filename); exit (EXIT_FAILURE); } + struct stat st; + if (fstat (fd, &st) == -1) { + perror ("insmod: fstat"); + exit (EXIT_FAILURE); + } + char buf[st.st_size]; + long offset = 0; + do { + long rc = read (fd, buf + offset, st.st_size - offset); + if (rc == -1) { + perror ("insmod: read"); + exit (EXIT_FAILURE); + } + offset += rc; + } while (offset < st.st_size); + close (fd); - if (pid == 0) { /* Child. */ - execl ("/insmod.static", "insmod.static", filename, NULL); - perror ("insmod: execl"); - _exit (EXIT_FAILURE); + if (init_module (buf, st.st_size, "") != 0) { + fprintf (stderr, "insmod: init_module: %s: %s\n", filename, moderror (errno)); + /* However ignore the error because this can just happen because + * of a missing device. + */ } +} + +/* Mount /proc unless it's mounted already. */ +static void +mount_proc (void) +{ + if (access ("/proc/uptime", R_OK) == -1) { + mkdir ("/proc", 0755); + + if (verbose) + fprintf (stderr, "febootstrap: mounting /proc\n"); - /* Parent. */ - int status; - if (wait (&status) == -1 || - WEXITSTATUS (status) != 0) - perror ("insmod: wait"); - /* but ignore the error, some will be because the device is not found */ + if (mount ("proc", "/proc", "proc", 0, "") == -1) { + perror ("mount: /proc"); + /* Non-fatal. */ + } + } } /* Print contents of /proc/uptime. */ @@ -193,3 +266,64 @@ print_uptime (void) fprintf (stderr, "febootstrap: uptime: %s", line); } + +/* Display a directory on stderr. This is used for debugging only. */ +static char +dirtype (int dt) +{ + switch (dt) { + case DT_BLK: return 'b'; + case DT_CHR: return 'c'; + case DT_DIR: return 'd'; + case DT_FIFO: return 'p'; + case DT_LNK: return 'l'; + case DT_REG: return '-'; + case DT_SOCK: return 's'; + case DT_UNKNOWN: return 'u'; + default: return '?'; + } +} + +static void +show_directory (const char *dirname) +{ + DIR *dir; + struct dirent *d; + struct stat statbuf; + char link[PATH_MAX+1]; + ssize_t n; + + fprintf (stderr, "febootstrap: debug: listing directory %s\n", dirname); + + if (chdir (dirname) == -1) { + perror (dirname); + return; + } + + dir = opendir ("."); + if (!dir) { + perror (dirname); + chdir ("/"); + return; + } + + while ((d = readdir (dir)) != NULL) { + fprintf (stderr, "%5lu %c %-16s", d->d_ino, dirtype (d->d_type), d->d_name); + if (lstat (d->d_name, &statbuf) >= 0) { + fprintf (stderr, " %06o %ld %d:%d", + statbuf.st_mode, statbuf.st_size, + statbuf.st_uid, statbuf.st_gid); + if (S_ISLNK (statbuf.st_mode)) { + n = readlink (d->d_name, link, PATH_MAX); + if (n >= 0) { + link[n] = '\0'; + fprintf (stderr, " -> %s", link); + } + } + } + fprintf (stderr, "\n"); + } + + closedir (dir); + chdir ("/"); +}