[Libguestfs] [PATCH supermin v2 2/4] init: Move init program into separate init directory.

Richard W.M. Jones rjones at redhat.com
Wed Feb 17 14:22:32 UTC 2016


This is just code motion.
---
 .gitignore       |   6 +-
 Makefile.am      |   6 +-
 configure.ac     |   1 +
 init/Makefile.am |  25 ++++
 init/init.c      | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am  |  12 +-
 src/bin2s.pl     |  11 +-
 src/init.c       | 428 -------------------------------------------------------
 8 files changed, 466 insertions(+), 451 deletions(-)
 create mode 100644 init/Makefile.am
 create mode 100644 init/init.c
 delete mode 100644 src/init.c

diff --git a/.gitignore b/.gitignore
index 2163b37..ff3680e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,12 +29,9 @@ pod2htm?.tmp
 /depcomp
 /examples/basic-full-appliance
 /examples/basic-supermin.d
-/helper/ext2init.S
-/helper/supermin-helper
-/helper/supermin-helper.1
-/helper/init
 /html/supermin-helper.1.html
 /html/supermin.1.html
+/init/init
 /local*
 /INSTALL
 /install-sh
@@ -43,7 +40,6 @@ pod2htm?.tmp
 /src/.depend
 /src/config.ml
 /src/ext2init-bin.S
-/src/init
 /src/supermin
 /src/supermin.1
 /src/supermin-link.sh
diff --git a/Makefile.am b/Makefile.am
index 9679da9..681c52a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
 # supermin Makefile.am
-# (C) Copyright 2009-2013 Red Hat Inc.
+# (C) Copyright 2009-2016 Red Hat Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -14,12 +14,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# Written by Richard W.M. Jones <rjones at redhat.com>
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = lib src examples tests
+SUBDIRS = lib init src examples tests
 
 EXTRA_DIST = \
 	.gitignore \
diff --git a/configure.ac b/configure.ac
index 0fe88c7..15f6537 100644
--- a/configure.ac
+++ b/configure.ac
@@ -192,6 +192,7 @@ AC_CONFIG_FILES([src/supermin-link.sh],
 		[chmod +x,-w src/supermin-link.sh])
 AC_CONFIG_FILES([Makefile
         examples/Makefile
+        init/Makefile
         lib/Makefile
         src/config.ml
         src/Makefile
diff --git a/init/Makefile.am b/init/Makefile.am
new file mode 100644
index 0000000..075cf46
--- /dev/null
+++ b/init/Makefile.am
@@ -0,0 +1,25 @@
+# supermin Makefile.am
+# (C) Copyright 2009-2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# init "script" used by ext2 initrd.
+
+CLEANFILES = *~
+
+noinst_PROGRAMS = init
+init_SOURCES = init.c
+init_CFLAGS = -static
+init_LDFLAGS = -static
diff --git a/init/init.c b/init/init.c
new file mode 100644
index 0000000..25d6bc6
--- /dev/null
+++ b/init/init.c
@@ -0,0 +1,428 @@
+/* supermin-helper reimplementation in C.
+ * Copyright (C) 2009-2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* 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, and some kernel modules.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <time.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <asm/unistd.h>
+
+/* Maximum time to wait for the root device to appear (seconds).
+ *
+ * On slow machines with lots of disks (Koji running the 255 disk test
+ * in libguestfs) this really can take several minutes.
+ *
+ * Note that the actual wait time is approximately double the number
+ * given here because there is a delay which doubles until it reaches
+ * this value.
+ */
+#define MAX_ROOT_WAIT 300
+
+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 read_cmdline (void);
+static void insmod (const char *filename);
+static void show_directory (const char *dir);
+
+static char cmdline[1024];
+static char line[1024];
+
+int
+main ()
+{
+  mount_proc ();
+
+  print_uptime ();
+  fprintf (stderr, "supermin: ext2 mini initrd starting up: "
+           PACKAGE_VERSION
+           "\n");
+
+  read_cmdline ();
+
+  /* Create some fixed directories. */
+  mkdir ("/dev", 0755);
+  mkdir ("/root", 0755);
+  mkdir ("/sys", 0755);
+
+  /* Mount /sys. */
+  if (verbose)
+    fprintf (stderr, "supermin: mounting /sys\n");
+  if (mount ("sysfs", "/sys", "sysfs", 0, "") == -1) {
+    perror ("mount: /sys");
+    exit (EXIT_FAILURE);
+  }
+
+  FILE *fp = fopen ("/modules", "r");
+  if (fp == NULL) {
+    perror ("fopen: /modules");
+    exit (EXIT_FAILURE);
+  }
+  while (fgets (line, sizeof line, fp)) {
+    size_t n = strlen (line);
+    if (n > 0 && line[n-1] == '\n')
+      line[--n] = '\0';
+
+    /* 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);
+
+  /* Look for the ext2 filesystem device.  It's always the last one
+   * that was added.  Modern versions of libguestfs supply the
+   * expected name of the root device on the command line
+   * ("root=/dev/...").  For virtio-scsi this is required, because we
+   * must wait for the device to appear after the module is loaded.
+   */
+  char *root, *path;
+  size_t len;
+  root = strstr (cmdline, "root=");
+  if (root) {
+    root += 5;
+    if (strncmp (root, "/dev/", 5) == 0)
+      root += 5;
+    len = strcspn (root, " ");
+    root[len] = '\0';
+
+    asprintf (&path, "/sys/block/%s/dev", root);
+
+    uint64_t delay_ns = 250000;
+    int virtio_message = 0;
+    while (delay_ns <= MAX_ROOT_WAIT * UINT64_C(1000000000)) {
+      fp = fopen (path, "r");
+      if (fp != NULL)
+        goto found;
+
+      if (delay_ns > 1000000000) {
+	fprintf (stderr,
+		 "supermin: waiting another %" PRIu64 " ns for %s to appear\n",
+		 delay_ns, path);
+        if (!virtio_message) {
+          fprintf (stderr,
+                   "This usually means your kernel doesn't support virtio, or supermin was unable\n"
+                   "to load some kernel modules (see module loading messages above).\n");
+          virtio_message = 1;
+        }
+      }
+
+      struct timespec t;
+      t.tv_sec = delay_ns / 1000000000;
+      t.tv_nsec = delay_ns % 1000000000;
+      nanosleep (&t, NULL);
+      delay_ns *= 2;
+    }
+  }
+  else {
+    path = strdup ("/sys/block/xdx/dev");
+
+    char class[3] = { 'v', 's', 'h' };
+    size_t i, j;
+    fp = NULL;
+    for (i = 0; i < sizeof class; ++i) {
+      for (j = 'z'; j >= 'a'; --j) {
+        path[11] = class[i];
+        path[13] = j;
+        fp = fopen (path, "r");
+        if (fp != NULL)
+          goto found;
+      }
+    }
+  }
+
+  fprintf (stderr,
+           "supermin: no ext2 root device found\n"
+           "Please include FULL verbose output in your bug report.\n");
+  exit (EXIT_FAILURE);
+
+ found:
+  if (verbose)
+    fprintf (stderr, "supermin: picked %s as root device\n", path);
+
+  fgets (line, sizeof line, fp);
+  int major = atoi (line);
+  char *p = line + strcspn (line, ":") + 1;
+  int minor = atoi (p);
+
+  fclose (fp);
+  if (umount ("/sys") == -1) {
+    perror ("umount: /sys");
+    exit (EXIT_FAILURE);
+  }
+
+  /* Make current process the controlling process of the tty. */
+  setsid ();
+#ifdef TIOCSCTTY
+  if (ioctl (0, TIOCSCTTY, 1) == -1)
+    perror ("ioctl: TIOCSCTTY");
+#endif
+
+  if (verbose)
+    fprintf (stderr, "supermin: creating /dev/root as block special %d:%d\n",
+             major, minor);
+
+  if (mknod ("/dev/root", S_IFBLK|0700, makedev (major, minor)) == -1) {
+    perror ("mknod: /dev/root");
+    exit (EXIT_FAILURE);
+  }
+
+  /* Mount new root and chroot to it. */
+  if (verbose)
+    fprintf (stderr, "supermin: mounting new root on /root\n");
+  if (mount ("/dev/root", "/root", "ext2", MS_NOATIME, "") == -1) {
+    perror ("mount: /root");
+    exit (EXIT_FAILURE);
+  }
+
+  /* Note that pivot_root won't work.  See the note in
+   * Documentation/filesystems/ramfs-rootfs-initramfs.txt
+   * We could remove the old initramfs files, but let's not bother.
+   */
+  if (verbose)
+    fprintf (stderr, "supermin: chroot\n");
+
+  if (chroot ("/root") == -1) {
+    perror ("chroot: /root");
+    exit (EXIT_FAILURE);
+  }
+
+  chdir ("/");
+
+  /* Run /init from ext2 filesystem. */
+  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);
+}
+
+static void
+insmod (const char *filename)
+{
+  size_t size;
+
+  if (verbose)
+    fprintf (stderr, "supermin: internal insmod %s\n", filename);
+
+  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);
+  }
+  size = st.st_size;
+  char buf[size];
+  size_t offset = 0;
+  do {
+    ssize_t rc = read (fd, buf + offset, size - offset);
+    if (rc == -1) {
+      perror ("insmod: read");
+      exit (EXIT_FAILURE);
+    }
+    offset += rc;
+  } while (offset < size);
+  close (fd);
+
+  if (init_module (buf, 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, "supermin: mounting /proc\n");
+
+    if (mount ("proc", "/proc", "proc", 0, "") == -1) {
+      perror ("mount: /proc");
+      /* Non-fatal. */
+    }
+  }
+}
+
+/* Print contents of /proc/uptime. */
+static void
+print_uptime (void)
+{
+  FILE *fp = fopen ("/proc/uptime", "r");
+  if (fp == NULL) {
+    perror ("/proc/uptime");
+    return;
+  }
+
+  fgets (line, sizeof line, fp);
+  fclose (fp);
+
+  fprintf (stderr, "supermin: uptime: %s", line);
+}
+
+/* Read /proc/cmdline into cmdline global (or at least the first 1024
+ * bytes of it).
+ */
+static void
+read_cmdline (void)
+{
+  FILE *fp;
+  size_t len;
+
+  fp = fopen ("/proc/cmdline", "r");
+  if (fp == NULL) {
+    perror ("/proc/cmdline");
+    return;
+  }
+
+  fgets (cmdline, sizeof cmdline, fp);
+  fclose (fp);
+
+  len = strlen (cmdline);
+  if (len >= 1 && cmdline[len-1] == '\n')
+    cmdline[len-1] = '\0';
+
+  fprintf (stderr, "supermin: cmdline: %s\n", cmdline);
+}
+
+/* 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, "supermin: 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 ("/");
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 5a601fe..443e25d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
 # supermin Makefile.am
-# (C) Copyright 2009-2014 Red Hat Inc.
+# (C) Copyright 2009-2016 Red Hat Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -14,8 +14,6 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-# Written by Richard W.M. Jones <rjones at redhat.com>
 
 EXTRA_DIST = \
 	.depend \
@@ -138,18 +136,12 @@ supermin_LINK = \
 .ml.cmx:
 	$(OCAMLFIND) ocamlopt $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
 
-# init "script" used by ext2 initrd.
-noinst_PROGRAMS = init
-init_SOURCES = init.c
-init_CFLAGS = -static
-init_LDFLAGS = -static
-
 CLEANFILES += ext2init-bin.S
 
 ext2init-bin.o: ext2init-bin.S
 	$(CC) -o $@ -c $<
 
-ext2init-bin.S: init $(srcdir)/bin2s.pl
+ext2init-bin.S: ../init/init $(srcdir)/bin2s.pl
 	strip --strip-all $<
 	@file $< | grep -isq static || \
 	  (echo "*** error: init is not statically linked"; exit 1)
diff --git a/src/bin2s.pl b/src/bin2s.pl
index 8558126..6c70446 100755
--- a/src/bin2s.pl
+++ b/src/bin2s.pl
@@ -30,6 +30,9 @@ my ($buf, $i, $sz);
 open my $ifh, '<', $infile or die "open $infile: $!";
 open my $ofh, '>', $outfile or die "open $outfile: $!";
 
+my $infile_basename = $infile;
+$infile_basename =~ s{.*/}{};
+
 print $ofh <<"EOF";
 /* This file has been automatically generated from $infile by $0 */
 
@@ -37,11 +40,11 @@ print $ofh <<"EOF";
 \t.section .note.GNU-stack,"",%progbits
 \t.previous
 
-\t.globl\t_binary_${infile}_start
-\t.globl\t_binary_${infile}_end
+\t.globl\t_binary_${infile_basename}_start
+\t.globl\t_binary_${infile_basename}_end
 
 \t.section\t.rodata
-_binary_${infile}_start:
+_binary_${infile_basename}_start:
 EOF
 
 $sz = 0;
@@ -54,7 +57,7 @@ die "read $infile (at offset $sz): $!\n" if not defined $i;
 close $ifh;
 
 print $ofh <<"EOF";
-_binary_${infile}_end:
+_binary_${infile_basename}_end:
 EOF
 
 close $ofh;
diff --git a/src/init.c b/src/init.c
deleted file mode 100644
index 25d6bc6..0000000
--- a/src/init.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/* supermin-helper reimplementation in C.
- * Copyright (C) 2009-2014 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* 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, and some kernel modules.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <time.h>
-#include <termios.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <asm/unistd.h>
-
-/* Maximum time to wait for the root device to appear (seconds).
- *
- * On slow machines with lots of disks (Koji running the 255 disk test
- * in libguestfs) this really can take several minutes.
- *
- * Note that the actual wait time is approximately double the number
- * given here because there is a delay which doubles until it reaches
- * this value.
- */
-#define MAX_ROOT_WAIT 300
-
-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 read_cmdline (void);
-static void insmod (const char *filename);
-static void show_directory (const char *dir);
-
-static char cmdline[1024];
-static char line[1024];
-
-int
-main ()
-{
-  mount_proc ();
-
-  print_uptime ();
-  fprintf (stderr, "supermin: ext2 mini initrd starting up: "
-           PACKAGE_VERSION
-           "\n");
-
-  read_cmdline ();
-
-  /* Create some fixed directories. */
-  mkdir ("/dev", 0755);
-  mkdir ("/root", 0755);
-  mkdir ("/sys", 0755);
-
-  /* Mount /sys. */
-  if (verbose)
-    fprintf (stderr, "supermin: mounting /sys\n");
-  if (mount ("sysfs", "/sys", "sysfs", 0, "") == -1) {
-    perror ("mount: /sys");
-    exit (EXIT_FAILURE);
-  }
-
-  FILE *fp = fopen ("/modules", "r");
-  if (fp == NULL) {
-    perror ("fopen: /modules");
-    exit (EXIT_FAILURE);
-  }
-  while (fgets (line, sizeof line, fp)) {
-    size_t n = strlen (line);
-    if (n > 0 && line[n-1] == '\n')
-      line[--n] = '\0';
-
-    /* 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);
-
-  /* Look for the ext2 filesystem device.  It's always the last one
-   * that was added.  Modern versions of libguestfs supply the
-   * expected name of the root device on the command line
-   * ("root=/dev/...").  For virtio-scsi this is required, because we
-   * must wait for the device to appear after the module is loaded.
-   */
-  char *root, *path;
-  size_t len;
-  root = strstr (cmdline, "root=");
-  if (root) {
-    root += 5;
-    if (strncmp (root, "/dev/", 5) == 0)
-      root += 5;
-    len = strcspn (root, " ");
-    root[len] = '\0';
-
-    asprintf (&path, "/sys/block/%s/dev", root);
-
-    uint64_t delay_ns = 250000;
-    int virtio_message = 0;
-    while (delay_ns <= MAX_ROOT_WAIT * UINT64_C(1000000000)) {
-      fp = fopen (path, "r");
-      if (fp != NULL)
-        goto found;
-
-      if (delay_ns > 1000000000) {
-	fprintf (stderr,
-		 "supermin: waiting another %" PRIu64 " ns for %s to appear\n",
-		 delay_ns, path);
-        if (!virtio_message) {
-          fprintf (stderr,
-                   "This usually means your kernel doesn't support virtio, or supermin was unable\n"
-                   "to load some kernel modules (see module loading messages above).\n");
-          virtio_message = 1;
-        }
-      }
-
-      struct timespec t;
-      t.tv_sec = delay_ns / 1000000000;
-      t.tv_nsec = delay_ns % 1000000000;
-      nanosleep (&t, NULL);
-      delay_ns *= 2;
-    }
-  }
-  else {
-    path = strdup ("/sys/block/xdx/dev");
-
-    char class[3] = { 'v', 's', 'h' };
-    size_t i, j;
-    fp = NULL;
-    for (i = 0; i < sizeof class; ++i) {
-      for (j = 'z'; j >= 'a'; --j) {
-        path[11] = class[i];
-        path[13] = j;
-        fp = fopen (path, "r");
-        if (fp != NULL)
-          goto found;
-      }
-    }
-  }
-
-  fprintf (stderr,
-           "supermin: no ext2 root device found\n"
-           "Please include FULL verbose output in your bug report.\n");
-  exit (EXIT_FAILURE);
-
- found:
-  if (verbose)
-    fprintf (stderr, "supermin: picked %s as root device\n", path);
-
-  fgets (line, sizeof line, fp);
-  int major = atoi (line);
-  char *p = line + strcspn (line, ":") + 1;
-  int minor = atoi (p);
-
-  fclose (fp);
-  if (umount ("/sys") == -1) {
-    perror ("umount: /sys");
-    exit (EXIT_FAILURE);
-  }
-
-  /* Make current process the controlling process of the tty. */
-  setsid ();
-#ifdef TIOCSCTTY
-  if (ioctl (0, TIOCSCTTY, 1) == -1)
-    perror ("ioctl: TIOCSCTTY");
-#endif
-
-  if (verbose)
-    fprintf (stderr, "supermin: creating /dev/root as block special %d:%d\n",
-             major, minor);
-
-  if (mknod ("/dev/root", S_IFBLK|0700, makedev (major, minor)) == -1) {
-    perror ("mknod: /dev/root");
-    exit (EXIT_FAILURE);
-  }
-
-  /* Mount new root and chroot to it. */
-  if (verbose)
-    fprintf (stderr, "supermin: mounting new root on /root\n");
-  if (mount ("/dev/root", "/root", "ext2", MS_NOATIME, "") == -1) {
-    perror ("mount: /root");
-    exit (EXIT_FAILURE);
-  }
-
-  /* Note that pivot_root won't work.  See the note in
-   * Documentation/filesystems/ramfs-rootfs-initramfs.txt
-   * We could remove the old initramfs files, but let's not bother.
-   */
-  if (verbose)
-    fprintf (stderr, "supermin: chroot\n");
-
-  if (chroot ("/root") == -1) {
-    perror ("chroot: /root");
-    exit (EXIT_FAILURE);
-  }
-
-  chdir ("/");
-
-  /* Run /init from ext2 filesystem. */
-  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);
-}
-
-static void
-insmod (const char *filename)
-{
-  size_t size;
-
-  if (verbose)
-    fprintf (stderr, "supermin: internal insmod %s\n", filename);
-
-  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);
-  }
-  size = st.st_size;
-  char buf[size];
-  size_t offset = 0;
-  do {
-    ssize_t rc = read (fd, buf + offset, size - offset);
-    if (rc == -1) {
-      perror ("insmod: read");
-      exit (EXIT_FAILURE);
-    }
-    offset += rc;
-  } while (offset < size);
-  close (fd);
-
-  if (init_module (buf, 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, "supermin: mounting /proc\n");
-
-    if (mount ("proc", "/proc", "proc", 0, "") == -1) {
-      perror ("mount: /proc");
-      /* Non-fatal. */
-    }
-  }
-}
-
-/* Print contents of /proc/uptime. */
-static void
-print_uptime (void)
-{
-  FILE *fp = fopen ("/proc/uptime", "r");
-  if (fp == NULL) {
-    perror ("/proc/uptime");
-    return;
-  }
-
-  fgets (line, sizeof line, fp);
-  fclose (fp);
-
-  fprintf (stderr, "supermin: uptime: %s", line);
-}
-
-/* Read /proc/cmdline into cmdline global (or at least the first 1024
- * bytes of it).
- */
-static void
-read_cmdline (void)
-{
-  FILE *fp;
-  size_t len;
-
-  fp = fopen ("/proc/cmdline", "r");
-  if (fp == NULL) {
-    perror ("/proc/cmdline");
-    return;
-  }
-
-  fgets (cmdline, sizeof cmdline, fp);
-  fclose (fp);
-
-  len = strlen (cmdline);
-  if (len >= 1 && cmdline[len-1] == '\n')
-    cmdline[len-1] = '\0';
-
-  fprintf (stderr, "supermin: cmdline: %s\n", cmdline);
-}
-
-/* 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, "supermin: 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 ("/");
-}
-- 
2.5.0




More information about the Libguestfs mailing list