Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / tools / test-runner.c
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2012-2014  Intel Corporation. All rights reserved.
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <stdbool.h>
34 #include <signal.h>
35 #include <string.h>
36 #include <getopt.h>
37 #include <poll.h>
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/mount.h>
42 #include <sys/param.h>
43 #include <sys/reboot.h>
44
45 #include "lib/bluetooth.h"
46 #include "lib/hci.h"
47 #include "lib/hci_lib.h"
48 #include "tools/hciattach.h"
49
50 #ifndef WAIT_ANY
51 #define WAIT_ANY (-1)
52 #endif
53
54 #define CMDLINE_MAX 2048
55
56 static const char *own_binary;
57 static char **test_argv;
58 static int test_argc;
59
60 static bool run_auto = false;
61 static bool start_dbus = false;
62 static int num_devs = 0;
63 static const char *qemu_binary = NULL;
64 static const char *kernel_image = NULL;
65
66 static const char *qemu_table[] = {
67         "qemu-system-x86_64",
68         "qemu-system-i386",
69         "/usr/bin/qemu-system-x86_64",
70         "/usr/bin/qemu-system-i386",
71         NULL
72 };
73
74 static const char *find_qemu(void)
75 {
76         int i;
77
78         for (i = 0; qemu_table[i]; i++) {
79                 struct stat st;
80
81                 if (!stat(qemu_table[i], &st))
82                         return qemu_table[i];
83         }
84
85         return NULL;
86 }
87
88 static const char *kernel_table[] = {
89         "bzImage",
90         "arch/x86/boot/bzImage",
91         "vmlinux",
92         "arch/x86/boot/vmlinux",
93         NULL
94 };
95
96 static const char *find_kernel(void)
97 {
98         int i;
99
100         for (i = 0; kernel_table[i]; i++) {
101                 struct stat st;
102
103                 if (!stat(kernel_table[i], &st))
104                         return kernel_table[i];
105         }
106
107         return NULL;
108 }
109
110 static const struct {
111         const char *target;
112         const char *linkpath;
113 } dev_table[] = {
114         { "/proc/self/fd",      "/dev/fd"       },
115         { "/proc/self/fd/0",    "/dev/stdin"    },
116         { "/proc/self/fd/1",    "/dev/stdout"   },
117         { "/proc/self/fd/2",    "/dev/stderr"   },
118         { }
119 };
120
121 static const struct {
122         const char *fstype;
123         const char *target;
124         const char *options;
125         unsigned long flags;
126 } mount_table[] = {
127         { "sysfs",    "/sys",     NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV },
128         { "proc",     "/proc",    NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV },
129         { "devtmpfs", "/dev",     "mode=0755", MS_NOSUID|MS_STRICTATIME },
130         { "devpts",   "/dev/pts", "mode=0620", MS_NOSUID|MS_NOEXEC },
131         { "tmpfs",    "/dev/shm", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME },
132         { "tmpfs",    "/run",     "mode=0755", MS_NOSUID|MS_NODEV|MS_STRICTATIME },
133         { "tmpfs",    "/tmp",              NULL, 0 },
134         { "debugfs",  "/sys/kernel/debug", NULL, 0 },
135         { }
136 };
137
138 static const char *config_table[] = {
139         "/var/lib/bluetooth",
140         "/etc/bluetooth",
141         "/etc/dbus-1",
142         "/usr/share/dbus-1",
143         NULL
144 };
145
146 static void prepare_sandbox(void)
147 {
148         int i;
149
150         for (i = 0; mount_table[i].fstype; i++) {
151                 struct stat st;
152
153                 if (lstat(mount_table[i].target, &st) < 0) {
154                         printf("Creating %s\n", mount_table[i].target);
155                         mkdir(mount_table[i].target, 0755);
156                 }
157
158                 printf("Mounting %s to %s\n", mount_table[i].fstype,
159                                                 mount_table[i].target);
160
161                 if (mount(mount_table[i].fstype,
162                                 mount_table[i].target,
163                                 mount_table[i].fstype,
164                                 mount_table[i].flags,
165                                 mount_table[i].options) < 0)
166                         perror("Failed to mount filesystem");
167         }
168
169         for (i = 0; dev_table[i].target; i++) {
170                 printf("Linking %s to %s\n", dev_table[i].linkpath,
171                                                 dev_table[i].target);
172
173                 if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
174                         perror("Failed to create device symlink");
175         }
176
177         printf("Creating new session group leader\n");
178         setsid();
179
180         printf("Setting controlling terminal\n");
181         ioctl(STDIN_FILENO, TIOCSCTTY, 1);
182
183         for (i = 0; config_table[i]; i++) {
184                 printf("Creating %s\n", config_table[i]);
185
186                 if (mount("tmpfs", config_table[i], "tmpfs",
187                                 MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
188                                 "mode=0755") < 0)
189                         perror("Failed to create filesystem");
190         }
191 }
192
193 static char *const qemu_argv[] = {
194         "",
195         "-nodefaults",
196         "-nodefconfig",
197         "-no-user-config",
198         "-monitor", "none",
199         "-display", "none",
200         "-machine", "type=q35,accel=kvm:tcg",
201         "-m", "192M",
202         "-nographic",
203         "-vga", "none",
204         "-net", "none",
205         "-balloon", "none",
206         "-no-acpi",
207         "-no-hpet",
208         "-no-reboot",
209         "-fsdev", "local,id=fsdev-root,path=/,readonly,security_model=none",
210         "-device", "virtio-9p-pci,fsdev=fsdev-root,mount_tag=/dev/root",
211         "-chardev", "stdio,id=chardev-serial0,signal=off",
212         "-device", "pci-serial,chardev=chardev-serial0",
213         NULL
214 };
215
216 static char *const qemu_envp[] = {
217         "HOME=/",
218         NULL
219 };
220
221 static void check_virtualization(void)
222 {
223 #if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
224         uint32_t ecx;
225
226         __asm__ __volatile__("cpuid" : "=c" (ecx) : "a" (1) : "memory");
227
228         if (!!(ecx & (1 << 5)))
229                 printf("Found support for Virtual Machine eXtensions\n");
230 #endif
231 }
232
233 static void start_qemu(void)
234 {
235         char cwd[PATH_MAX], initcmd[PATH_MAX], testargs[PATH_MAX];
236         char cmdline[CMDLINE_MAX];
237         char **argv;
238         int i, pos;
239
240         check_virtualization();
241
242         if (!getcwd(cwd, sizeof(cwd)))
243                 strcat(cwd, "/");
244
245         if (own_binary[0] == '/')
246                 snprintf(initcmd, sizeof(initcmd), "%s", own_binary);
247         else
248                 snprintf(initcmd, sizeof(initcmd), "%s/%s", cwd, own_binary);
249
250         pos = snprintf(testargs, sizeof(testargs), "%s", test_argv[0]);
251
252         for (i = 1; i < test_argc; i++) {
253                 int len = sizeof(testargs) - pos;
254                 pos += snprintf(testargs + pos, len, " %s", test_argv[i]);
255         }
256
257         snprintf(cmdline, sizeof(cmdline),
258                                 "console=ttyS0,115200n8 earlyprintk=serial "
259                                 "rootfstype=9p "
260                                 "rootflags=trans=virtio,version=9p2000.L "
261                                 "acpi=off pci=noacpi noapic quiet ro init=%s "
262                                 "TESTHOME=%s TESTDBUS=%u TESTDEVS=%d "
263                                 "TESTAUTO=%u TESTARGS=\'%s\'", initcmd, cwd,
264                                 start_dbus, num_devs, run_auto, testargs);
265
266         argv = alloca(sizeof(qemu_argv) +
267                                 (sizeof(char *) * (4 + (num_devs * 4))));
268         memcpy(argv, qemu_argv, sizeof(qemu_argv));
269
270         pos = (sizeof(qemu_argv) / sizeof(char *)) - 1;
271
272         argv[0] = (char *) qemu_binary;
273
274         argv[pos++] = "-kernel";
275         argv[pos++] = (char *) kernel_image;
276         argv[pos++] = "-append";
277         argv[pos++] = (char *) cmdline;
278
279         for (i = 0; i < num_devs; i++) {
280                 const char *path = "/tmp/bt-server-bredr";
281                 char *chrdev, *serdev;
282
283                 chrdev = alloca(32 + strlen(path));
284                 sprintf(chrdev, "socket,path=%s,id=bt%d", path, i);
285
286                 serdev = alloca(32);
287                 sprintf(serdev, "pci-serial,chardev=bt%d", i);
288
289                 argv[pos++] = "-chardev";
290                 argv[pos++] = chrdev;
291                 argv[pos++] = "-device";
292                 argv[pos++] = serdev;
293         }
294
295         argv[pos] = NULL;
296
297         execve(argv[0], argv, qemu_envp);
298 }
299
300 static int open_serial(const char *path)
301 {
302         struct termios ti;
303         int fd, saved_ldisc, ldisc = N_HCI;
304
305         fd = open(path, O_RDWR | O_NOCTTY);
306         if (fd < 0) {
307                 perror("Failed to open serial port");
308                 return -1;
309         }
310
311         if (tcflush(fd, TCIOFLUSH) < 0) {
312                 perror("Failed to flush serial port");
313                 close(fd);
314                 return -1;
315         }
316
317         if (ioctl(fd, TIOCGETD, &saved_ldisc) < 0) {
318                 perror("Failed get serial line discipline");
319                 close(fd);
320                 return -1;
321         }
322
323         /* Switch TTY to raw mode */
324         memset(&ti, 0, sizeof(ti));
325         cfmakeraw(&ti);
326
327         ti.c_cflag |= (B115200 | CLOCAL | CREAD);
328
329         /* Set flow control */
330         ti.c_cflag |= CRTSCTS;
331
332         if (tcsetattr(fd, TCSANOW, &ti) < 0) {
333                 perror("Failed to set serial port settings");
334                 close(fd);
335                 return -1;
336         }
337
338         if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
339                 perror("Failed set serial line discipline");
340                 close(fd);
341                 return -1;
342         }
343
344         printf("Switched line discipline from %d to %d\n", saved_ldisc, ldisc);
345
346         return fd;
347 }
348
349 static int attach_proto(const char *path, unsigned int proto,
350                                         unsigned int mandatory_flags,
351                                         unsigned int optional_flags)
352 {
353         unsigned int flags = mandatory_flags | optional_flags;
354         int fd, dev_id;
355
356         fd = open_serial(path);
357         if (fd < 0)
358                 return -1;
359
360         if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
361                 if (errno == EINVAL) {
362                         if (ioctl(fd, HCIUARTSETFLAGS, mandatory_flags) < 0) {
363                                 perror("Failed to set mandatory flags");
364                                 close(fd);
365                                 return -1;
366                         }
367                 } else {
368                         perror("Failed to set flags");
369                         close(fd);
370                         return -1;
371                 }
372         }
373
374         if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
375                 perror("Failed to set protocol");
376                 close(fd);
377                 return -1;
378         }
379
380         dev_id = ioctl(fd, HCIUARTGETDEVICE);
381         if (dev_id < 0) {
382                 perror("Failed to get device id");
383                 close(fd);
384                 return -1;
385         }
386
387         printf("Device index %d attached\n", dev_id);
388
389         return fd;
390 }
391
392 static void create_dbus_system_conf(void)
393 {
394         FILE *fp;
395
396         fp = fopen("/etc/dbus-1/system.conf", "we");
397         if (!fp)
398                 return;
399
400         fputs("<!DOCTYPE busconfig PUBLIC "
401                 "\"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\" "
402                 "\"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n", fp);
403         fputs("<busconfig>\n", fp);
404         fputs("<type>system</type>\n", fp);
405         fputs("<listen>unix:path=/run/dbus/system_bus_socket</listen>\n", fp);
406         fputs("<policy context=\"default\">\n", fp);
407         fputs("<allow user=\"*\"/>\n", fp);
408         fputs("<allow own=\"*\"/>\n", fp);
409         fputs("<allow send_type=\"method_call\"/>\n",fp);
410         fputs("<allow send_type=\"signal\"/>\n", fp);
411         fputs("<allow send_type=\"method_return\"/>\n", fp);
412         fputs("<allow send_type=\"error\"/>\n", fp);
413         fputs("<allow receive_type=\"method_call\"/>\n",fp);
414         fputs("<allow receive_type=\"signal\"/>\n", fp);
415         fputs("<allow receive_type=\"method_return\"/>\n", fp);
416         fputs("<allow receive_type=\"error\"/>\n", fp);
417         fputs("</policy>\n", fp);
418         fputs("</busconfig>\n", fp);
419
420         fclose(fp);
421
422         mkdir("/run/dbus", 0755);
423 }
424
425 static pid_t start_dbus_daemon(void)
426 {
427         char *argv[3], *envp[1];
428         pid_t pid;
429         int i;
430
431         argv[0] = "/usr/bin/dbus-daemon";
432         argv[1] = "--system";
433         argv[2] = NULL;
434
435         envp[0] = NULL;
436
437         printf("Starting D-Bus daemon\n");
438
439         pid = fork();
440         if (pid < 0) {
441                 perror("Failed to fork new process");
442                 return -1;
443         }
444
445         if (pid == 0) {
446                 execve(argv[0], argv, envp);
447                 exit(EXIT_SUCCESS);
448         }
449
450         printf("D-Bus daemon process %d created\n", pid);
451
452         for (i = 0; i < 20; i++) {
453                 struct stat st;
454
455                 if (!stat("/run/dbus/system_bus_socket", &st)) {
456                         printf("Found D-Bus daemon socket\n");
457                         break;
458                 }
459
460                 usleep(25 * 1000);
461         }
462
463         return pid;
464 }
465
466 static const char *daemon_table[] = {
467         "bluetoothd",
468         "src/bluetoothd",
469         "/usr/sbin/bluetoothd",
470         "/usr/libexec/bluetooth/bluetoothd",
471         NULL
472 };
473
474 static pid_t start_bluetooth_daemon(const char *home)
475 {
476         const char *daemon = NULL;
477         char *argv[3], *envp[2];
478         pid_t pid;
479         int i;
480
481         if (chdir(home + 5) < 0) {
482                 perror("Failed to change home directory for daemon");
483                 return -1;
484         }
485
486         for (i = 0; daemon_table[i]; i++) {
487                 struct stat st;
488
489                 if (!stat(daemon_table[i], &st)) {
490                         daemon = daemon_table[i];
491                         break;
492                 }
493         }
494
495         if (!daemon) {
496                 fprintf(stderr, "Failed to locate Bluetooth daemon binary\n");
497                 return -1;
498         }
499
500         printf("Using Bluetooth daemon %s\n", daemon);
501
502         argv[0] = (char *) daemon;
503         argv[1] = "--nodetach";
504         argv[2] = NULL;
505
506         envp[0] = "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket";
507         envp[1] = NULL;
508
509         printf("Starting Bluetooth daemon\n");
510
511         pid = fork();
512         if (pid < 0) {
513                 perror("Failed to fork new process");
514                 return -1;
515         }
516
517         if (pid == 0) {
518                 execve(argv[0], argv, envp);
519                 exit(EXIT_SUCCESS);
520         }
521
522         printf("Bluetooth daemon process %d created\n", pid);
523
524         return pid;
525 }
526
527 static const char *test_table[] = {
528         "mgmt-tester",
529         "smp-tester",
530         "l2cap-tester",
531         "rfcomm-tester",
532         "sco-tester",
533         "bnep-tester",
534         "check-selftest",
535         "tools/mgmt-tester",
536         "tools/smp-tester",
537         "tools/l2cap-tester",
538         "tools/rfcomm-tester",
539         "tools/sco-tester",
540         "tools/bnep-tester",
541         "tools/check-selftest",
542         NULL
543 };
544
545 static void run_command(char *cmdname, char *home)
546 {
547         char *argv[9], *envp[3];
548         int pos = 0, idx = 0;
549         int serial_fd;
550         pid_t pid, dbus_pid, daemon_pid;
551
552         if (num_devs) {
553                 const char *node = "/dev/ttyS1";
554                 unsigned int basic_flags, extra_flags;
555
556                 printf("Attaching BR/EDR controller to %s\n", node);
557
558                 basic_flags = (1 << HCI_UART_RESET_ON_INIT);
559                 extra_flags = (1 << HCI_UART_VND_DETECT);
560
561                 serial_fd = attach_proto(node, HCI_UART_H4, basic_flags,
562                                                                 extra_flags);
563         } else
564                 serial_fd = -1;
565
566         if (start_dbus) {
567                 create_dbus_system_conf();
568                 dbus_pid = start_dbus_daemon();
569                 daemon_pid = start_bluetooth_daemon(home);
570         } else {
571                 dbus_pid = -1;
572                 daemon_pid = -1;
573         }
574
575 start_next:
576         if (run_auto) {
577                 if (chdir(home + 5) < 0) {
578                         perror("Failed to change home test directory");
579                         return;
580                 }
581
582                 while (1) {
583                         struct stat st;
584
585                         if (!test_table[idx])
586                                 return;
587
588                         if (!stat(test_table[idx], &st))
589                                 break;
590
591                         idx++;
592                 }
593
594                 argv[0] = (char *) test_table[idx];
595                 argv[1] = "-q";
596                 argv[2] = NULL;
597         } else {
598                 while (1) {
599                         char *ptr;
600
601                         ptr = strchr(cmdname, ' ');
602                         if (!ptr) {
603                                 argv[pos++] = cmdname;
604                                 break;
605                         }
606
607                         *ptr = '\0';
608                         argv[pos++] = cmdname;
609                         if (pos > 8)
610                                 break;
611
612                         cmdname = ptr + 1;
613                 }
614
615                 argv[pos] = NULL;
616         }
617
618         pos = 0;
619         envp[pos++] = "TERM=linux";
620         if (home)
621                 envp[pos++] = home;
622         envp[pos] = NULL;
623
624         printf("Running command %s\n", argv[0]);
625
626         pid = fork();
627         if (pid < 0) {
628                 perror("Failed to fork new process");
629                 return;
630         }
631
632         if (pid == 0) {
633                 if (home) {
634                         printf("Changing into directory %s\n", home + 5);
635                         if (chdir(home + 5) < 0)
636                                 perror("Failed to change directory");
637                 }
638
639                 execve(argv[0], argv, envp);
640                 exit(EXIT_SUCCESS);
641         }
642
643         printf("New process %d created\n", pid);
644
645         while (1)  {
646                 pid_t corpse;
647                 int status;
648
649                 corpse = waitpid(WAIT_ANY, &status, 0);
650                 if (corpse < 0 || corpse == 0)
651                         continue;
652
653                 if (WIFEXITED(status))
654                         printf("Process %d exited with status %d\n",
655                                                 corpse, WEXITSTATUS(status));
656                 else if (WIFSIGNALED(status))
657                         printf("Process %d terminated with signal %d\n",
658                                                 corpse, WTERMSIG(status));
659                 else if (WIFSTOPPED(status))
660                         printf("Process %d stopped with signal %d\n",
661                                                 corpse, WSTOPSIG(status));
662                 else if (WIFCONTINUED(status))
663                         printf("Process %d continued\n", corpse);
664
665                 if (corpse == dbus_pid) {
666                         printf("D-Bus daemon terminated\n");
667                         dbus_pid = -1;
668                 }
669
670                 if (corpse == daemon_pid) {
671                         printf("Bluetooth daemon terminated\n");
672                         daemon_pid = -1;
673                 }
674
675                 if (corpse == pid) {
676                         if (!run_auto) {
677                                 if (daemon_pid > 0)
678                                         kill(daemon_pid, SIGTERM);
679                                 if (dbus_pid > 0)
680                                         kill(dbus_pid, SIGTERM);
681                         }
682                         break;
683                 }
684         }
685
686         if (run_auto) {
687                 idx++;
688                 goto start_next;
689         }
690
691         if (serial_fd >= 0) {
692                 close(serial_fd);
693                 serial_fd = -1;
694         }
695 }
696
697 static void run_tests(void)
698 {
699         char cmdline[CMDLINE_MAX], *ptr, *cmds, *home = NULL;
700         FILE *fp;
701
702         fp = fopen("/proc/cmdline", "re");
703         if (!fp) {
704                 fprintf(stderr, "Failed to open kernel command line\n");
705                 return;
706         }
707
708         ptr = fgets(cmdline, sizeof(cmdline), fp);
709         fclose(fp);
710
711         if (!ptr) {
712                 fprintf(stderr, "Failed to read kernel command line\n");
713                 return;
714         }
715
716         ptr = strstr(cmdline, "TESTARGS=");
717         if (!ptr) {
718                 fprintf(stderr, "No test command section found\n");
719                 return;
720         }
721
722         cmds = ptr + 10;
723         ptr = strchr(cmds, '\'');
724         if (!ptr) {
725                 fprintf(stderr, "Malformed test command section\n");
726                 return;
727         }
728
729         *ptr = '\0';
730
731         ptr = strstr(cmdline, "TESTAUTO=1");
732         if (ptr) {
733                 printf("Automatic test execution requested\n");
734                 run_auto= true;
735         }
736
737         ptr = strstr(cmdline, "TESTDEVS=1");
738         if (ptr) {
739                 printf("Attachment of devices requested\n");
740                 num_devs = 1;
741         }
742
743         ptr = strstr(cmdline, "TESTDBUS=1");
744         if (ptr) {
745                 printf("D-Bus daemon requested\n");
746                 start_dbus = true;
747         }
748
749         ptr = strstr(cmdline, "TESTHOME=");
750         if (ptr) {
751                 home = ptr + 4;
752                 ptr = strpbrk(home + 9, " \r\n");
753                 if (ptr)
754                         *ptr = '\0';
755         }
756
757         run_command(cmds, home);
758 }
759
760 static void usage(void)
761 {
762         printf("test-runner - Automated test execution utility\n"
763                 "Usage:\n");
764         printf("\ttest-runner [options] [--] <command> [args]\n");
765         printf("Options:\n"
766                 "\t-a, --auto             Find tests and run them\n"
767                 "\t-d, --dbus             Start D-Bus daemon\n"
768                 "\t-u, --unix [path]      Provide serial device\n"
769                 "\t-q, --qemu <path>      QEMU binary\n"
770                 "\t-k, --kernel <image>   Kernel image (bzImage)\n"
771                 "\t-h, --help             Show help options\n");
772 }
773
774 static const struct option main_options[] = {
775         { "all",     no_argument,       NULL, 'a' },
776         { "auto",    no_argument,       NULL, 'a' },
777         { "unix",    no_argument,       NULL, 'u' },
778         { "dbus",    no_argument,       NULL, 'd' },
779         { "qemu",    required_argument, NULL, 'q' },
780         { "kernel",  required_argument, NULL, 'k' },
781         { "version", no_argument,       NULL, 'v' },
782         { "help",    no_argument,       NULL, 'h' },
783         { }
784 };
785
786 int main(int argc, char *argv[])
787 {
788         if (getpid() == 1 && getppid() == 0) {
789                 prepare_sandbox();
790                 run_tests();
791
792                 sync();
793                 reboot(RB_AUTOBOOT);
794                 return EXIT_SUCCESS;
795         }
796
797         for (;;) {
798                 int opt;
799
800                 opt = getopt_long(argc, argv, "audq:k:vh", main_options, NULL);
801                 if (opt < 0)
802                         break;
803
804                 switch (opt) {
805                 case 'a':
806                         run_auto = true;
807                         break;
808                 case 'u':
809                         num_devs = 1;
810                         break;
811                 case 'd':
812                         start_dbus = true;
813                         break;
814                 case 'q':
815                         qemu_binary = optarg;
816                         break;
817                 case 'k':
818                         kernel_image = optarg;
819                         break;
820                 case 'v':
821                         printf("%s\n", VERSION);
822                         return EXIT_SUCCESS;
823                 case 'h':
824                         usage();
825                         return EXIT_SUCCESS;
826                 default:
827                         return EXIT_FAILURE;
828                 }
829         }
830
831         if (run_auto) {
832                 if (argc - optind > 0) {
833                         fprintf(stderr, "Invalid command line parameters\n");
834                         return EXIT_FAILURE;
835                 }
836         } else {
837                 if (argc - optind < 1) {
838                         fprintf(stderr, "Failed to specify test command\n");
839                         return EXIT_FAILURE;
840                 }
841         }
842
843         own_binary = argv[0];
844         test_argv = argv + optind;
845         test_argc = argc - optind;
846
847         if (!qemu_binary) {
848                 qemu_binary = find_qemu();
849                 if (!qemu_binary) {
850                         fprintf(stderr, "No default QEMU binary found\n");
851                         return EXIT_FAILURE;
852                 }
853         }
854
855         if (!kernel_image) {
856                 kernel_image = find_kernel();
857                 if (!kernel_image) {
858                         fprintf(stderr, "No default kernel image found\n");
859                         return EXIT_FAILURE;
860                 }
861         }
862
863         printf("Using QEMU binary %s\n", qemu_binary);
864         printf("Using kernel image %s\n", kernel_image);
865
866         start_qemu();
867
868         return EXIT_SUCCESS;
869 }