From: "Richard W.M. Jones" <rjones(a)redhat.com>
This is required when using virtio-scsi with libguestfs.
---
helper/init.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 66 insertions(+), 12 deletions(-)
diff --git a/helper/init.c b/helper/init.c
index a1887a0..19e8948 100644
--- a/helper/init.c
+++ b/helper/init.c
@@ -1,5 +1,5 @@
/* febootstrap-supermin-helper reimplementation in C.
- * Copyright (C) 2009-2011 Red Hat Inc.
+ * Copyright (C) 2009-2012 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
@@ -31,6 +31,7 @@
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/stat.h>
@@ -68,9 +69,11 @@ static const char *moderror(int err)
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
@@ -86,6 +89,8 @@ main ()
#endif
"\n");
+ read_cmdline ();
+
/* Create some fixed directories. */
mkdir ("/dev", 0755);
mkdir ("/root", 0755);
@@ -121,23 +126,54 @@ main ()
}
fclose (fp);
- /* Look for the ext2 filesystem device. It's always the last
- * one that was added.
- * XXX More than 25 devices?
+ /* 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 path[] = "/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;
+ 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);
+
+ long delay_ns = 250000;
+ while (delay_ns <= 2000000000) {
fp = fopen (path, "r");
if (fp != NULL)
goto found;
+
+ 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,
"febootstrap: no ext2 root device found\n"
"Please include FULL verbose output in your bug report.\n");
@@ -313,6 +349,24 @@ print_uptime (void)
fprintf (stderr, "febootstrap: 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 = fopen ("/proc/cmdline", "r");
+ if (fp == NULL) {
+ perror ("/proc/cmdline");
+ return;
+ }
+
+ fgets (cmdline, sizeof cmdline, fp);
+ fclose (fp);
+
+ fprintf (stderr, "febootstrap: cmdline: %s", cmdline);
+}
+
/* Display a directory on stderr. This is used for debugging only. */
static char
dirtype (int dt)
--
1.7.10.1