/* Try to reproduce RHBZ#1184405. * Note: needs to be linked statically. * By Richard W.M. Jones */ #include #include #include #include #include #include #include #include #include #include extern long init_module (void *, unsigned long, const char *); /* NB! Must match the number of disks in Makefile. */ #define NR_SCSI_DISKS 6 /* NB! Must match the module list in Makefile. Also they must be * in module dependency order. */ static const char *modules[] = { "virtio.ko", "virtio_ring.ko", "virtio_mmio.ko", "virtio_scsi.ko", NULL }; static void load_modules (void); static void make_devices (void); static void run_test (const char *dev); int main (int argc, char *argv[]) { int i; char dev[] = "/dev/sda"; int child_pids[NR_SCSI_DISKS-1]; printf ("init: started\n"); load_modules (); /* Really we should wait for the kernel to probe devices, but bleah. */ sleep (2); make_devices (); for (i = 0; i < NR_SCSI_DISKS-1; ++i) { child_pids[i] = fork (); if (child_pids[i] == -1) { perror ("fork"); exit (EXIT_FAILURE); } if (child_pids[i] == 0) { /* child */ dev[7] = 'a' + i + 1; /* /dev/sd[b..] */ run_test (dev); _exit (EXIT_SUCCESS); } } run_test (dev); /* /dev/sda test in parent */ for (i = 0; i < NR_SCSI_DISKS-1; ++i) { waitpid (child_pids[i], NULL, 0); } printf ("init: parent process exiting\n"); exit (EXIT_SUCCESS); } static char buffer[BUFSIZ]; #define MIN(a,b) ((a)<(b)?(a):(b)) static void run_test (const char *dev) { int fd, passno; uint64_t size; ssize_t r; printf ("init: testing %s\n", dev); for (passno = 0; passno < 5; ++passno) { printf ("init: %s: pass %d\n", dev, passno); fflush (stdout); fd = open (dev, O_RDONLY); if (fd == -1) { perror (dev); _exit (EXIT_FAILURE); } if (ioctl (fd, BLKGETSIZE64, &size) == -1) { perror ("ioctl: BLKGETSIZE64"); _exit (EXIT_FAILURE); } while (size > 0) { r = read (fd, buffer, MIN (BUFSIZ, size)); if (r == -1) { perror ("read"); _exit (EXIT_FAILURE); } size -= r; } if (close (fd) == -1) { perror ("close"); _exit (EXIT_FAILURE); } } printf ("init: test of %s finished successfully\n", dev); fflush (stdout); } /* Originally taken from supermin's init.c */ static void load_modules (void) { size_t i; int fd; struct stat statbuf; size_t size; ssize_t r; for (i = 0; modules[i] != NULL; ++i) { printf ("init: loading module %s\n", modules[i]); fd = open (modules[i], O_RDONLY); if (fd == -1) { perror (modules[i]); exit (EXIT_FAILURE); } if (fstat (fd, &statbuf) == -1) { perror (modules[i]); exit (EXIT_FAILURE); } char buf[size = statbuf.st_size]; while (size > 0) { r = read (fd, buf, size); if (r == -1) { perror ("read"); exit (EXIT_FAILURE); } size -= r; } close (fd); if (init_module (buf, statbuf.st_size, "") != 0) { fprintf (stderr, "insmod: "); perror (modules[i]); exit (EXIT_FAILURE); } } } /* Much less trouble than udev! */ static void make_devices (void) { int i; char dev[] = "/dev/sda"; printf ("init: creating device nodes\n"); for (i = 0; i < NR_SCSI_DISKS; ++i) { dev[7] = 'a' + i; if (mknod (dev, S_IFBLK, makedev (8, 16*i)) == -1) { perror (dev); exit (EXIT_FAILURE); } } }