Factor out modules directory into a variable.
[rhbz1184405.git] / init.c
1 /* Try to reproduce RHBZ#1184405.
2  * Note: needs to be linked statically.
3  * By Richard W.M. Jones <rjones@redhat.com>
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <inttypes.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #include <sys/ioctl.h>
13 #include <sys/stat.h>
14 #include <sys/wait.h>
15 #include <linux/fs.h>
16
17 extern long init_module (void *, unsigned long, const char *);
18
19 /* NB! Must match the number of disks in Makefile. */
20 #define NR_SCSI_DISKS 6
21
22 /* NB! Must match the module list in Makefile.  Also they must be
23  * in module dependency order.
24  */
25 static const char *modules[] = {
26   "virtio.ko",
27   "virtio_ring.ko",
28   "virtio_mmio.ko",
29   "virtio_scsi.ko",
30   NULL
31 };
32
33 static void load_modules (void);
34 static void make_devices (void);
35 static void run_test (const char *dev);
36
37 int
38 main (int argc, char *argv[])
39 {
40   int i;
41   char dev[] = "/dev/sda";
42   int child_pids[NR_SCSI_DISKS-1];
43
44   printf ("init: started\n");
45   load_modules ();
46
47   /* Really we should wait for the kernel to probe devices, but bleah. */
48   sleep (2);
49
50   make_devices ();
51
52   for (i = 0; i < NR_SCSI_DISKS-1; ++i) {
53     child_pids[i] = fork ();
54     if (child_pids[i] == -1) {
55       perror ("fork");
56       exit (EXIT_FAILURE);
57     }
58     if (child_pids[i] == 0) {   /* child */
59       dev[7] = 'a' + i + 1;     /* /dev/sd[b..] */
60       run_test (dev);
61       _exit (EXIT_SUCCESS);
62     }
63   }
64
65   run_test (dev);               /* /dev/sda test in parent */
66
67   for (i = 0; i < NR_SCSI_DISKS-1; ++i) {
68     waitpid (child_pids[i], NULL, 0);
69   }
70
71   printf ("init: parent process exiting\n");
72   exit (EXIT_SUCCESS);
73 }
74
75 static char buffer[BUFSIZ];
76 #define MIN(a,b) ((a)<(b)?(a):(b))
77
78 static void
79 run_test (const char *dev)
80 {
81   int fd, passno;
82   uint64_t size;
83   ssize_t r;
84
85   printf ("init: testing %s\n", dev);
86
87   for (passno = 0; passno < 5; ++passno) {
88     printf ("init: %s: pass %d\n", dev, passno);
89     fflush (stdout);
90
91     fd = open (dev, O_RDONLY);
92     if (fd == -1) {
93       perror (dev);
94       _exit (EXIT_FAILURE);
95     }
96     if (ioctl (fd, BLKGETSIZE64, &size) == -1) {
97       perror ("ioctl: BLKGETSIZE64");
98       _exit (EXIT_FAILURE);
99     }
100
101     while (size > 0) {
102       r = read (fd, buffer, MIN (BUFSIZ, size));
103       if (r == -1) {
104         perror ("read");
105         _exit (EXIT_FAILURE);
106       }
107       size -= r;
108     }
109
110     if (close (fd) == -1) {
111       perror ("close");
112       _exit (EXIT_FAILURE);
113     }
114   }
115
116   printf ("init: test of %s finished successfully\n", dev);
117   fflush (stdout);
118 }
119
120 /* Originally taken from supermin's init.c */
121 static void
122 load_modules (void)
123 {
124   size_t i;
125   int fd;
126   struct stat statbuf;
127   size_t size;
128   ssize_t r;
129
130   for (i = 0; modules[i] != NULL; ++i) {
131     printf ("init: loading module %s\n", modules[i]);
132
133     fd = open (modules[i], O_RDONLY);
134     if (fd == -1) {
135       perror (modules[i]);
136       exit (EXIT_FAILURE);
137     }
138     if (fstat (fd, &statbuf) == -1) {
139       perror (modules[i]);
140       exit (EXIT_FAILURE);
141     }
142     char buf[size = statbuf.st_size];
143     while (size > 0) {
144       r = read (fd, buf, size);
145       if (r == -1) {
146         perror ("read");
147         exit (EXIT_FAILURE);
148       }
149       size -= r;
150     }
151     close (fd);
152
153     if (init_module (buf, statbuf.st_size, "") != 0) {
154       fprintf (stderr, "insmod: ");
155       perror (modules[i]);
156       exit (EXIT_FAILURE);
157     }
158   }
159 }
160
161 /* Much less trouble than udev! */
162 static void
163 make_devices (void)
164 {
165   int i;
166   char dev[] = "/dev/sda";
167
168   printf ("init: creating device nodes\n");
169
170   for (i = 0; i < NR_SCSI_DISKS; ++i) {
171     dev[7] = 'a' + i;
172     if (mknod (dev, S_IFBLK, makedev (8, 16*i)) == -1) {
173       perror (dev);
174       exit (EXIT_FAILURE);
175     }
176   }
177 }