tools/ioctl-tester - Add ioctl-tester
[platform/upstream/bluez.git] / tools / test-runner.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2012-2014  Intel Corporation. All rights reserved.
7  *
8  *
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdio.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <stdbool.h>
21 #include <signal.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <poll.h>
25 #include <sys/wait.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/mount.h>
29 #include <sys/param.h>
30 #include <sys/reboot.h>
31
32 #include "lib/bluetooth.h"
33 #include "lib/hci.h"
34 #include "lib/hci_lib.h"
35 #include "tools/hciattach.h"
36
37 #ifndef WAIT_ANY
38 #define WAIT_ANY (-1)
39 #endif
40
41 #define CMDLINE_MAX 2048
42
43 static const char *own_binary;
44 static char **test_argv;
45 static int test_argc;
46
47 static bool run_auto = false;
48 static bool start_dbus = false;
49 static bool start_dbus_session;
50 static bool start_daemon = false;
51 static bool start_emulator = false;
52 static bool start_monitor = false;
53 static int num_devs = 0;
54 static const char *qemu_binary = NULL;
55 static const char *kernel_image = NULL;
56 static bool audio_support;
57
58 static const char *qemu_table[] = {
59         "qemu-system-x86_64",
60         "qemu-system-i386",
61         "/usr/bin/qemu-system-x86_64",
62         "/usr/bin/qemu-system-i386",
63         NULL
64 };
65
66 static const char *find_qemu(void)
67 {
68         int i;
69
70         for (i = 0; qemu_table[i]; i++) {
71                 struct stat st;
72
73                 if (!stat(qemu_table[i], &st))
74                         return qemu_table[i];
75         }
76
77         return NULL;
78 }
79
80 static const char *kernel_table[] = {
81         "bzImage",
82         "arch/x86/boot/bzImage",
83         "vmlinux",
84         "arch/x86/boot/vmlinux",
85         NULL
86 };
87
88 static const char *find_kernel(void)
89 {
90         int i;
91
92         for (i = 0; kernel_table[i]; i++) {
93                 struct stat st;
94
95                 if (!stat(kernel_table[i], &st))
96                         return kernel_table[i];
97         }
98
99         return NULL;
100 }
101
102 static const struct {
103         const char *target;
104         const char *linkpath;
105 } dev_table[] = {
106         { "/proc/self/fd",      "/dev/fd"       },
107         { "/proc/self/fd/0",    "/dev/stdin"    },
108         { "/proc/self/fd/1",    "/dev/stdout"   },
109         { "/proc/self/fd/2",    "/dev/stderr"   },
110         { }
111 };
112
113 static const struct {
114         const char *fstype;
115         const char *target;
116         const char *options;
117         unsigned long flags;
118 } mount_table[] = {
119         { "sysfs",    "/sys",     NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV },
120         { "proc",     "/proc",    NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV },
121         { "devtmpfs", "/dev",     "mode=0755", MS_NOSUID|MS_STRICTATIME },
122         { "devpts",   "/dev/pts", "mode=0620", MS_NOSUID|MS_NOEXEC },
123         { "tmpfs",    "/dev/shm", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME },
124         { "tmpfs",    "/run",     "mode=0755", MS_NOSUID|MS_NODEV|MS_STRICTATIME },
125         { "tmpfs",    "/tmp",              NULL, 0 },
126         { "debugfs",  "/sys/kernel/debug", NULL, 0 },
127         { }
128 };
129
130 static const char *config_table[] = {
131         "/var/lib/bluetooth",
132         "/etc/bluetooth",
133         "/etc/dbus-1",
134         "/usr/share/dbus-1",
135         NULL
136 };
137
138 static void prepare_sandbox(void)
139 {
140         int i;
141
142         for (i = 0; mount_table[i].fstype && mount_table[i].target; i++) {
143                 struct stat st;
144
145                 if (lstat(mount_table[i].target, &st) < 0) {
146                         printf("Creating %s\n", mount_table[i].target);
147                         mkdir(mount_table[i].target, 0755);
148                 }
149
150                 printf("Mounting %s to %s\n", mount_table[i].fstype,
151                                                 mount_table[i].target);
152
153                 if (mount(mount_table[i].fstype,
154                                 mount_table[i].target,
155                                 mount_table[i].fstype,
156                                 mount_table[i].flags,
157                                 mount_table[i].options) < 0)
158                         perror("Failed to mount filesystem");
159         }
160
161         for (i = 0; dev_table[i].target; i++) {
162                 printf("Linking %s to %s\n", dev_table[i].linkpath,
163                                                 dev_table[i].target);
164
165                 if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
166                         perror("Failed to create device symlink");
167         }
168
169         printf("Creating new session group leader\n");
170         setsid();
171
172         printf("Setting controlling terminal\n");
173         ioctl(STDIN_FILENO, TIOCSCTTY, 1);
174
175         for (i = 0; config_table[i]; i++) {
176                 printf("Creating %s\n", config_table[i]);
177
178                 if (mount("tmpfs", config_table[i], "tmpfs",
179                                 MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
180                                 "mode=0755") < 0)
181                         perror("Failed to create filesystem");
182         }
183 }
184
185 static char *const qemu_argv[] = {
186         "",
187         "-nodefaults",
188         "-no-user-config",
189         "-monitor", "none",
190         "-display", "none",
191         "-machine", "type=q35,accel=kvm:tcg",
192         "-m", "192M",
193         "-nographic",
194         "-net", "none",
195         "-no-acpi",
196         "-no-hpet",
197         "-no-reboot",
198         "-fsdev", "local,id=fsdev-root,path=/,readonly,security_model=none,"
199         "multidevs=remap",
200         "-device", "virtio-9p-pci,fsdev=fsdev-root,mount_tag=/dev/root",
201         "-chardev", "stdio,id=con,mux=on",
202         "-serial", "chardev:con",
203         NULL
204 };
205
206 static char *const qemu_envp[] = {
207         "HOME=/",
208         NULL
209 };
210
211 static void check_virtualization(void)
212 {
213 #if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
214         uint32_t ecx;
215
216         __asm__ __volatile__("cpuid" : "=c" (ecx) : "a" (1) : "memory");
217
218         if (!!(ecx & (1 << 5)))
219                 printf("Found support for Virtual Machine eXtensions\n");
220 #endif
221 }
222
223 static void start_qemu(void)
224 {
225         char cwd[PATH_MAX/2], initcmd[PATH_MAX], testargs[PATH_MAX];
226         char cmdline[CMDLINE_MAX];
227         char **argv;
228         int i, pos;
229
230         check_virtualization();
231
232         if (!getcwd(cwd, sizeof(cwd)))
233                 strcat(cwd, "/");
234
235         if (own_binary[0] == '/')
236                 snprintf(initcmd, sizeof(initcmd), "%s", own_binary);
237         else
238                 snprintf(initcmd, sizeof(initcmd), "%s/%s", cwd, own_binary);
239
240         pos = snprintf(testargs, sizeof(testargs), "%s", test_argv[0]);
241
242         for (i = 1; i < test_argc; i++) {
243                 int len = sizeof(testargs) - pos;
244                 pos += snprintf(testargs + pos, len, " %s", test_argv[i]);
245         }
246
247         snprintf(cmdline, sizeof(cmdline),
248                                 "console=ttyS0,115200n8 earlyprintk=serial "
249                                 "rootfstype=9p "
250                                 "rootflags=trans=virtio,version=9p2000.u "
251                                 "acpi=off pci=noacpi noapic quiet ro init=%s "
252                                 "bluetooth.enable_ecred=1 "
253                                 "TESTHOME=%s TESTDBUS=%u TESTDAEMON=%u "
254                                 "TESTDBUSSESSION=%u XDG_RUNTIME_DIR=/run/user/0 "
255                                 "TESTAUDIO=%u "
256                                 "TESTMONITOR=%u TESTEMULATOR=%u TESTDEVS=%d "
257                                 "TESTAUTO=%u TESTARGS=\'%s\'",
258                                 initcmd, cwd, start_dbus, start_daemon,
259                                 start_dbus_session, audio_support,
260                                 start_monitor, start_emulator, num_devs,
261                                 run_auto, testargs);
262
263         argv = alloca(sizeof(qemu_argv) +
264                                 (audio_support ? 4 : 0) +
265                                 (sizeof(char *) * (4 + (num_devs * 4))));
266         memcpy(argv, qemu_argv, sizeof(qemu_argv));
267
268         pos = (sizeof(qemu_argv) / sizeof(char *)) - 1;
269
270         /* Make sure qemu_binary is not null */
271         if (!qemu_binary) {
272                 fprintf(stderr, "No QEMU binary is set\n");
273                 exit(1);
274         }
275         argv[0] = (char *) qemu_binary;
276
277         if (audio_support) {
278                 char *xdg_runtime_dir, *audiodev;
279
280                 xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
281                 if (!xdg_runtime_dir) {
282                         fprintf(stderr, "XDG_RUNTIME_DIR not set\n");
283                         exit(1);
284                 }
285                 audiodev = alloca(40 + strlen(xdg_runtime_dir));
286                 sprintf(audiodev, "id=audio,driver=pa,server=%s/pulse/native",
287                                 xdg_runtime_dir);
288
289                 argv[pos++] = "-audiodev";
290                 argv[pos++] = audiodev;
291                 argv[pos++] = "-device";
292                 argv[pos++] = "AC97,audiodev=audio";
293         }
294
295         argv[pos++] = "-kernel";
296         argv[pos++] = (char *) kernel_image;
297         argv[pos++] = "-append";
298         argv[pos++] = (char *) cmdline;
299
300         for (i = 0; i < num_devs; i++) {
301                 const char *path = "/tmp/bt-server-bredr";
302                 char *chrdev, *serdev;
303
304                 chrdev = alloca(32 + strlen(path));
305                 sprintf(chrdev, "socket,path=%s,id=bt%d", path, i);
306
307                 serdev = alloca(32);
308                 sprintf(serdev, "pci-serial,chardev=bt%d", i);
309
310                 argv[pos++] = "-chardev";
311                 argv[pos++] = chrdev;
312                 argv[pos++] = "-device";
313                 argv[pos++] = serdev;
314         }
315
316         argv[pos] = NULL;
317
318         execve(argv[0], argv, qemu_envp);
319 }
320
321 static int open_serial(const char *path)
322 {
323         struct termios ti;
324         int fd, saved_ldisc, ldisc = N_HCI;
325
326         fd = open(path, O_RDWR | O_NOCTTY);
327         if (fd < 0) {
328                 perror("Failed to open serial port");
329                 return -1;
330         }
331
332         if (tcflush(fd, TCIOFLUSH) < 0) {
333                 perror("Failed to flush serial port");
334                 close(fd);
335                 return -1;
336         }
337
338         if (ioctl(fd, TIOCGETD, &saved_ldisc) < 0) {
339                 perror("Failed get serial line discipline");
340                 close(fd);
341                 return -1;
342         }
343
344         /* Switch TTY to raw mode */
345         memset(&ti, 0, sizeof(ti));
346         cfmakeraw(&ti);
347
348         ti.c_cflag |= (B115200 | CLOCAL | CREAD);
349
350         /* Set flow control */
351         ti.c_cflag |= CRTSCTS;
352
353         if (tcsetattr(fd, TCSANOW, &ti) < 0) {
354                 perror("Failed to set serial port settings");
355                 close(fd);
356                 return -1;
357         }
358
359         if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
360                 perror("Failed set serial line discipline");
361                 close(fd);
362                 return -1;
363         }
364
365         printf("Switched line discipline from %d to %d\n", saved_ldisc, ldisc);
366
367         return fd;
368 }
369
370 static int attach_proto(const char *path, unsigned int proto,
371                                         unsigned int mandatory_flags,
372                                         unsigned int optional_flags)
373 {
374         unsigned int flags = mandatory_flags | optional_flags;
375         int fd, dev_id;
376
377         fd = open_serial(path);
378         if (fd < 0)
379                 return -1;
380
381         if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
382                 if (errno == EINVAL) {
383                         if (ioctl(fd, HCIUARTSETFLAGS, mandatory_flags) < 0) {
384                                 perror("Failed to set mandatory flags");
385                                 close(fd);
386                                 return -1;
387                         }
388                 } else {
389                         perror("Failed to set flags");
390                         close(fd);
391                         return -1;
392                 }
393         }
394
395         if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
396                 perror("Failed to set protocol");
397                 close(fd);
398                 return -1;
399         }
400
401         dev_id = ioctl(fd, HCIUARTGETDEVICE);
402         if (dev_id < 0) {
403                 perror("Failed to get device id");
404                 close(fd);
405                 return -1;
406         }
407
408         printf("Device index %d attached\n", dev_id);
409
410         return fd;
411 }
412
413 static void create_dbus_system_conf(void)
414 {
415         FILE *fp;
416
417         fp = fopen("/etc/dbus-1/system.conf", "we");
418         if (!fp)
419                 return;
420
421         fputs("<!DOCTYPE busconfig PUBLIC "
422                 "\"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\" "
423                 "\"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n", fp);
424         fputs("<busconfig>\n", fp);
425         fputs("<type>system</type>\n", fp);
426         fputs("<listen>unix:path=/run/dbus/system_bus_socket</listen>\n", fp);
427         fputs("<policy context=\"default\">\n", fp);
428         fputs("<allow user=\"*\"/>\n", fp);
429         fputs("<allow own=\"*\"/>\n", fp);
430         fputs("<allow send_type=\"method_call\"/>\n",fp);
431         fputs("<allow send_type=\"signal\"/>\n", fp);
432         fputs("<allow send_type=\"method_return\"/>\n", fp);
433         fputs("<allow send_type=\"error\"/>\n", fp);
434         fputs("<allow receive_type=\"method_call\"/>\n",fp);
435         fputs("<allow receive_type=\"signal\"/>\n", fp);
436         fputs("<allow receive_type=\"method_return\"/>\n", fp);
437         fputs("<allow receive_type=\"error\"/>\n", fp);
438         fputs("</policy>\n", fp);
439         fputs("</busconfig>\n", fp);
440
441         fclose(fp);
442
443         if (symlink("/etc/dbus-1/system.conf",
444                                 "/usr/share/dbus-1/system.conf") < 0)
445                 perror("Failed to create system.conf symlink");
446
447         mkdir("/run/dbus", 0755);
448 }
449
450 static void create_dbus_session_conf(void)
451 {
452         FILE *fp;
453
454         fp = fopen("/etc/dbus-1/session.conf", "we");
455         if (!fp)
456                 return;
457
458         fputs("<!DOCTYPE busconfig PUBLIC "
459                 "\"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\" "
460                 "\"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n", fp);
461         fputs("<busconfig>\n", fp);
462         fputs("<type>session</type>\n", fp);
463         fputs("<listen>unix:path=/run/user/0/bus</listen>\n", fp);
464         fputs("<policy context=\"default\">\n", fp);
465         fputs("<allow user=\"*\"/>\n", fp);
466         fputs("<allow own=\"*\"/>\n", fp);
467         fputs("<allow send_type=\"method_call\"/>\n", fp);
468         fputs("<allow send_type=\"signal\"/>\n", fp);
469         fputs("<allow send_type=\"method_return\"/>\n", fp);
470         fputs("<allow send_type=\"error\"/>\n", fp);
471         fputs("<allow receive_type=\"method_call\"/>\n", fp);
472         fputs("<allow receive_type=\"signal\"/>\n", fp);
473         fputs("<allow receive_type=\"method_return\"/>\n", fp);
474         fputs("<allow receive_type=\"error\"/>\n", fp);
475         fputs("</policy>\n", fp);
476         fputs("</busconfig>\n", fp);
477
478         fclose(fp);
479
480         if (symlink("/etc/dbus-1/session.conf",
481                                 "/usr/share/dbus-1/session.conf") < 0)
482                 perror("Failed to create session.conf symlink");
483
484         if (mkdir("/run/user", 0755) < 0) {
485                 fprintf(stderr, "unable to create /run/user directory\n");
486                 return;
487         }
488         if (mkdir("/run/user/0", 0755) < 0) {
489                 fprintf(stderr, "unable to create /run/user/0 directory\n");
490                 return;
491         }
492 }
493
494 static pid_t start_dbus_daemon(bool session)
495 {
496         char *argv[3], *envp[1];
497         pid_t pid;
498         int i;
499         char *bus_type = session ? "session" : "system";
500         char *socket_path = session ?
501                         "/run/user/0/bus" : "/run/dbus/system_bus_socket";
502
503         argv[0] = "/usr/bin/dbus-daemon";
504         if (session)
505                 argv[1] = "--session";
506         else
507                 argv[1] = "--system";
508         argv[2] = NULL;
509
510         envp[0] = NULL;
511
512         printf("Starting D-Bus %s daemon\n", bus_type);
513
514         pid = fork();
515         if (pid < 0) {
516                 perror("Failed to fork new process");
517                 return -1;
518         }
519
520         if (pid == 0) {
521                 execve(argv[0], argv, envp);
522                 exit(EXIT_SUCCESS);
523         }
524
525         printf("D-Bus %s daemon process %d created\n", bus_type, pid);
526
527         for (i = 0; i < 20; i++) {
528                 struct stat st;
529
530                 if (!stat(socket_path, &st)) {
531                         printf("Found D-Bus %s daemon socket\n", bus_type);
532                         return pid;
533                 }
534
535                 sleep(1);
536         }
537
538         return -1;
539 }
540
541 static const char *daemon_table[] = {
542         "bluetoothd",
543         "src/bluetoothd",
544         "/usr/sbin/bluetoothd",
545         "/usr/libexec/bluetooth/bluetoothd",
546         NULL
547 };
548
549 static pid_t start_bluetooth_daemon(const char *home)
550 {
551         const char *daemon = NULL;
552         char *argv[6], *envp[2];
553         pid_t pid;
554         struct stat st;
555         int i;
556
557         if (chdir(home + 5) < 0) {
558                 perror("Failed to change home directory for daemon");
559                 return -1;
560         }
561
562         for (i = 0; daemon_table[i]; i++) {
563
564                 if (!stat(daemon_table[i], &st)) {
565                         daemon = daemon_table[i];
566                         break;
567                 }
568         }
569
570         if (!daemon) {
571                 fprintf(stderr, "Failed to locate Bluetooth daemon binary\n");
572                 return -1;
573         }
574
575         printf("Using Bluetooth daemon %s\n", daemon);
576
577         argv[0] = (char *) daemon;
578         argv[1] = "--nodetach";
579         argv[2] = "-d";
580         argv[3] = NULL;
581
582         if (!stat("src/main.conf", &st)) {
583                 argv[3] = "-f";
584                 argv[4] = "src/main.conf";
585                 argv[5] = NULL;
586         }
587
588         envp[0] = "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket";
589         envp[1] = NULL;
590
591         printf("Starting Bluetooth daemon\n");
592
593         pid = fork();
594         if (pid < 0) {
595                 perror("Failed to fork new process");
596                 return -1;
597         }
598
599         if (pid == 0) {
600                 execve(argv[0], argv, envp);
601                 exit(EXIT_SUCCESS);
602         }
603
604         printf("Bluetooth daemon process %d created\n", pid);
605
606         return pid;
607 }
608
609 static const char *test_table[] = {
610         "mgmt-tester",
611         "smp-tester",
612         "l2cap-tester",
613         "rfcomm-tester",
614         "sco-tester",
615         "iso-tester",
616         "mesh-tester",
617         "ioctl-tester",
618         "bnep-tester",
619         "check-selftest",
620         "tools/mgmt-tester",
621         "tools/smp-tester",
622         "tools/l2cap-tester",
623         "tools/rfcomm-tester",
624         "tools/sco-tester",
625         "tools/iso-tester",
626         "tools/mesh-tester",
627         "tools/ioctl-tester",
628         "tools/bnep-tester",
629         "tools/check-selftest",
630         NULL
631 };
632
633 static const char *monitor_table[] = {
634         "btmon",
635         "monitor/btmon",
636         "/usr/sbin/btmon",
637         NULL
638 };
639
640 static pid_t start_btmon(const char *home)
641 {
642         const char *monitor = NULL;
643         char *argv[3], *envp[2];
644         pid_t pid;
645         int i;
646
647         if (chdir(home + 5) < 0) {
648                 perror("Failed to change home directory for monitor");
649                 return -1;
650         }
651
652         for (i = 0; monitor_table[i]; i++) {
653                 struct stat st;
654
655                 if (!stat(monitor_table[i], &st)) {
656                         monitor = monitor_table[i];
657                         break;
658                 }
659         }
660
661         if (!monitor) {
662                 fprintf(stderr, "Failed to locate Monitor binary\n");
663                 return -1;
664         }
665
666         printf("Using Monitor %s\n", monitor);
667
668         argv[0] = (char *) monitor;
669         argv[1] = "-t";
670         argv[2] = NULL;
671
672         printf("Starting Monitor\n");
673
674         pid = fork();
675         if (pid < 0) {
676                 perror("Failed to fork new process");
677                 return -1;
678         }
679
680         if (pid == 0) {
681                 execve(argv[0], argv, envp);
682                 exit(EXIT_SUCCESS);
683         }
684
685         printf("Monitor process %d created\n", pid);
686
687         return pid;
688 }
689
690 static const char *btvirt_table[] = {
691         "btvirt",
692         "emulator/btvirt",
693         "/usr/sbin/btvirt",
694         NULL
695 };
696
697 static pid_t start_btvirt(const char *home)
698 {
699         const char *btvirt = NULL;
700         char *argv[3], *envp[2];
701         pid_t pid;
702         int i;
703
704         if (chdir(home + 5) < 0) {
705                 perror("Failed to change home directory for daemon");
706                 return -1;
707         }
708
709         for (i = 0; btvirt_table[i]; i++) {
710                 struct stat st;
711
712         if (!stat(btvirt_table[i], &st)) {
713                 btvirt = btvirt_table[i];
714                 break;
715                 }
716         }
717
718         if (!btvirt) {
719                 fprintf(stderr, "Failed to locate btvirt binary\n");
720                 return -1;
721         }
722
723         printf("Using %s\n", btvirt);
724
725         argv[0] = (char *) btvirt;
726         argv[1] = "-l";
727         argv[2] = NULL;
728
729         printf("Starting Emulator\n");
730
731         pid = fork();
732         if (pid < 0) {
733                 perror("Failed to fork new process");
734                 return -1;
735         }
736
737         if (pid == 0) {
738                 execve(argv[0], argv, envp);
739                 exit(EXIT_SUCCESS);
740         }
741
742         printf("Emulator process %d created\n", pid);
743
744         return pid;
745 }
746
747 static void trigger_udev(void)
748 {
749         char *argv[3], *envp[1];
750         pid_t pid;
751
752         argv[0] = "/bin/udevadm";
753         argv[1] = "trigger";
754         argv[2] = NULL;
755
756         envp[0] = NULL;
757
758         printf("Triggering udev events\n");
759
760         pid = fork();
761         if (pid < 0) {
762                 perror("Failed to fork new process");
763                 return;
764         }
765
766         if (pid == 0) {
767                 execve(argv[0], argv, envp);
768                 exit(EXIT_SUCCESS);
769         }
770
771         printf("udev trigger process %d created\n", pid);
772 }
773
774 static pid_t start_udevd(void)
775 {
776         char *argv[2], *envp[1];
777         pid_t pid;
778
779         argv[0] = "/lib/systemd/systemd-udevd";
780         argv[1] = NULL;
781
782         envp[0] = NULL;
783
784         printf("Starting udevd daemon\n");
785
786         pid = fork();
787         if (pid < 0) {
788                 perror("Failed to fork new process");
789                 return -1;
790         }
791
792         if (pid == 0) {
793                 execve(argv[0], argv, envp);
794                 exit(EXIT_SUCCESS);
795         }
796
797         printf("udevd daemon process %d created\n", pid);
798
799         trigger_udev();
800
801         return pid;
802 }
803
804 static void run_command(char *cmdname, char *home)
805 {
806 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
807         char *argv[10], *envp[3];
808 #else
809         char *argv[9], *envp[3];
810 #endif
811         int pos = 0, idx = 0;
812         int serial_fd;
813         pid_t pid, dbus_pid, daemon_pid, monitor_pid, emulator_pid,
814               dbus_session_pid, udevd_pid;
815
816         if (!home) {
817                 perror("Invalid parameter: TESTHOME");
818                 return;
819         }
820
821         if (num_devs) {
822                 const char *node = "/dev/ttyS1";
823                 unsigned int basic_flags, extra_flags;
824
825                 printf("Attaching BR/EDR controller to %s\n", node);
826
827                 basic_flags = (1 << HCI_UART_RESET_ON_INIT);
828                 extra_flags = (1 << HCI_UART_VND_DETECT);
829
830                 serial_fd = attach_proto(node, HCI_UART_H4, basic_flags,
831                                                                 extra_flags);
832         } else
833                 serial_fd = -1;
834
835         if (audio_support)
836                 udevd_pid = start_udevd();
837         else
838                 udevd_pid = -1;
839
840         if (start_dbus) {
841                 create_dbus_system_conf();
842                 dbus_pid = start_dbus_daemon(false);
843         } else
844                 dbus_pid = -1;
845
846         if (start_dbus_session) {
847                 create_dbus_session_conf();
848                 dbus_session_pid = start_dbus_daemon(true);
849         } else
850                 dbus_session_pid = -1;
851
852         if (start_daemon)
853                 daemon_pid = start_bluetooth_daemon(home);
854         else
855                 daemon_pid = -1;
856
857         if (start_monitor)
858                 monitor_pid = start_btmon(home);
859         else
860                 monitor_pid = -1;
861
862         if (start_emulator)
863                 emulator_pid = start_btvirt(home);
864         else
865                 emulator_pid = -1;
866
867 start_next:
868         if (run_auto) {
869                 if (chdir(home + 5) < 0) {
870                         perror("Failed to change home test directory");
871                         return;
872                 }
873
874                 while (1) {
875                         struct stat st;
876
877                         if (!test_table[idx])
878                                 return;
879
880                         if (!stat(test_table[idx], &st))
881                                 break;
882
883                         idx++;
884                 }
885
886                 argv[0] = (char *) test_table[idx];
887                 argv[1] = "-q";
888                 argv[2] = NULL;
889                 cmdname = NULL;
890         }
891
892         pos = 0;
893         envp[pos++] = "TERM=linux";
894         if (home)
895                 envp[pos++] = home;
896         envp[pos] = NULL;
897
898         printf("Running command %s\n", cmdname ? cmdname : argv[0]);
899
900         pid = fork();
901         if (pid < 0) {
902                 perror("Failed to fork new process");
903                 return;
904         }
905
906         if (pid == 0) {
907                 if (home) {
908                         printf("Changing into directory %s\n", home + 5);
909                         if (chdir(home + 5) < 0)
910                                 perror("Failed to change directory");
911                 }
912
913                 if (!cmdname)
914                         execve(argv[0], argv, envp);
915                 else
916                         execl("/bin/sh", "sh", "-c", cmdname, NULL);
917
918                 exit(EXIT_SUCCESS);
919         }
920
921         printf("New process %d created\n", pid);
922
923         while (1)  {
924                 pid_t corpse;
925                 int status;
926
927                 corpse = waitpid(WAIT_ANY, &status, 0);
928                 if (corpse < 0 || corpse == 0)
929                         continue;
930
931                 if (WIFEXITED(status))
932                         printf("Process %d exited with status %d\n",
933                                                 corpse, WEXITSTATUS(status));
934                 else if (WIFSIGNALED(status))
935                         printf("Process %d terminated with signal %d\n",
936                                                 corpse, WTERMSIG(status));
937                 else if (WIFSTOPPED(status))
938                         printf("Process %d stopped with signal %d\n",
939                                                 corpse, WSTOPSIG(status));
940                 else if (WIFCONTINUED(status))
941                         printf("Process %d continued\n", corpse);
942
943                 if (corpse == dbus_pid) {
944                         printf("D-Bus system daemon terminated\n");
945                         dbus_pid = -1;
946                 }
947
948                 if (corpse == dbus_session_pid) {
949                         printf("D-Bus session daemon terminated\n");
950                         dbus_session_pid = -1;
951                 }
952
953                 if (corpse == daemon_pid) {
954                         printf("Bluetooth daemon terminated\n");
955                         daemon_pid = -1;
956                 }
957
958                 if (corpse == emulator_pid) {
959                         printf("Bluetooth emulator terminated\n");
960                         emulator_pid = -1;
961                 }
962
963                 if (corpse == monitor_pid) {
964                         printf("Bluetooth monitor terminated\n");
965                         monitor_pid = -1;
966                 }
967
968                 if (corpse == udevd_pid) {
969                         printf("udevd terminated\n");
970                         udevd_pid = -1;
971                 }
972
973                 if (corpse == pid)
974                         break;
975         }
976
977         if (run_auto) {
978                 idx++;
979                 goto start_next;
980         }
981
982         if (daemon_pid > 0)
983                 kill(daemon_pid, SIGTERM);
984
985         if (dbus_pid > 0)
986                 kill(dbus_pid, SIGTERM);
987
988         if (dbus_session_pid > 0)
989                 kill(dbus_session_pid, SIGTERM);
990
991         if (emulator_pid > 0)
992                 kill(dbus_pid, SIGTERM);
993
994         if (monitor_pid > 0)
995                 kill(monitor_pid, SIGTERM);
996
997         if (udevd_pid > 0)
998                 kill(udevd_pid, SIGTERM);
999
1000         if (serial_fd >= 0)
1001                 close(serial_fd);
1002 }
1003
1004 static void run_tests(void)
1005 {
1006         char cmdline[CMDLINE_MAX], *ptr, *cmds, *home = NULL;
1007         FILE *fp;
1008
1009         fp = fopen("/proc/cmdline", "re");
1010         if (!fp) {
1011                 fprintf(stderr, "Failed to open kernel command line\n");
1012                 return;
1013         }
1014
1015         ptr = fgets(cmdline, sizeof(cmdline), fp);
1016         fclose(fp);
1017
1018         if (!ptr) {
1019                 fprintf(stderr, "Failed to read kernel command line\n");
1020                 return;
1021         }
1022
1023         ptr = strstr(cmdline, "TESTARGS=");
1024         if (!ptr) {
1025                 fprintf(stderr, "No test command section found\n");
1026                 return;
1027         }
1028
1029         cmds = ptr + 10;
1030         ptr = strchr(cmds, '\'');
1031         if (!ptr) {
1032                 fprintf(stderr, "Malformed test command section\n");
1033                 return;
1034         }
1035
1036         *ptr = '\0';
1037
1038         ptr = strstr(cmdline, "TESTAUTO=1");
1039         if (ptr) {
1040                 printf("Automatic test execution requested\n");
1041                 run_auto= true;
1042         }
1043
1044         ptr = strstr(cmdline, "TESTDEVS=1");
1045         if (ptr) {
1046                 printf("Attachment of devices requested\n");
1047                 num_devs = 1;
1048         }
1049
1050         ptr = strstr(cmdline, "TESTDBUS=1");
1051         if (ptr) {
1052                 printf("D-Bus system daemon requested\n");
1053                 start_dbus = true;
1054         }
1055
1056         ptr = strstr(cmdline, "TESTDBUSSESSION=1");
1057         if (ptr) {
1058                 printf("D-Bus session daemon requested\n");
1059                 start_dbus_session = true;
1060         }
1061
1062         ptr = strstr(cmdline, "TESTDAEMON=1");
1063         if (ptr) {
1064                 printf("bluetoothd requested\n");
1065                 start_daemon = true;
1066         }
1067
1068         ptr = strstr(cmdline, "TESTMONITOR=1");
1069         if (ptr) {
1070                 printf("Monitor requested\n");
1071                 start_monitor = true;
1072         }
1073
1074         ptr = strstr(cmdline, "TESTEMULATOR=1");
1075         if (ptr) {
1076                 printf("Emulator requested\n");
1077                 start_emulator = true;
1078         }
1079
1080         ptr = strstr(cmdline, "TESTAUDIO=1");
1081         if (ptr) {
1082                 printf("Audio support requested\n");
1083                 audio_support = true;
1084         }
1085
1086         ptr = strstr(cmdline, "TESTHOME=");
1087         if (ptr) {
1088                 home = ptr + 4;
1089                 ptr = strpbrk(home + 9, " \r\n");
1090                 if (ptr)
1091                         *ptr = '\0';
1092         }
1093
1094         run_command(cmds, home);
1095 }
1096
1097 static void usage(void)
1098 {
1099         printf("test-runner - Automated test execution utility\n"
1100                 "Usage:\n");
1101         printf("\ttest-runner [options] [--] <command> [args]\n");
1102         printf("Options:\n"
1103                 "\t-a, --auto             Find tests and run them\n"
1104                 "\t-b, --dbus             Start D-Bus system daemon\n"
1105                 "\t-s, --dbus-session     Start D-Bus session daemon\n"
1106                 "\t-d, --daemon           Start bluetoothd\n"
1107                 "\t-m, --monitor          Start btmon\n"
1108                 "\t-l, --emulator         Start btvirt\n"
1109                 "\t-u, --unix [path]      Provide serial device\n"
1110                 "\t-q, --qemu <path>      QEMU binary\n"
1111                 "\t-k, --kernel <image>   Kernel image (bzImage)\n"
1112                 "\t-A, --audio            Add audio support\n"
1113                 "\t-h, --help             Show help options\n");
1114 }
1115
1116 static const struct option main_options[] = {
1117         { "all",     no_argument,       NULL, 'a' },
1118         { "auto",    no_argument,       NULL, 'a' },
1119         { "dbus",    no_argument,       NULL, 'b' },
1120         { "dbus-session", no_argument,  NULL, 's' },
1121         { "unix",    no_argument,       NULL, 'u' },
1122         { "daemon",  no_argument,       NULL, 'd' },
1123         { "emulator", no_argument,      NULL, 'l' },
1124         { "monitor", no_argument,       NULL, 'm' },
1125         { "qemu",    required_argument, NULL, 'q' },
1126         { "kernel",  required_argument, NULL, 'k' },
1127         { "audio",   no_argument,       NULL, 'A' },
1128         { "version", no_argument,       NULL, 'v' },
1129         { "help",    no_argument,       NULL, 'h' },
1130         { }
1131 };
1132
1133 int main(int argc, char *argv[])
1134 {
1135         if (getpid() == 1 && getppid() == 0) {
1136                 prepare_sandbox();
1137                 run_tests();
1138
1139                 sync();
1140                 reboot(RB_AUTOBOOT);
1141                 return EXIT_SUCCESS;
1142         }
1143
1144         for (;;) {
1145                 int opt;
1146
1147                 opt = getopt_long(argc, argv, "aubdslmq:k:Avh", main_options,
1148                                                                 NULL);
1149                 if (opt < 0)
1150                         break;
1151
1152                 switch (opt) {
1153                 case 'a':
1154                         run_auto = true;
1155                         break;
1156                 case 'u':
1157                         num_devs = 1;
1158                         break;
1159                 case 'b':
1160                         start_dbus = true;
1161                         break;
1162                 case 's':
1163                         start_dbus_session = true;
1164                         break;
1165                 case 'd':
1166                         start_dbus = true;
1167                         start_daemon = true;
1168                         break;
1169                 case 'l':
1170                         start_emulator = true;
1171                         break;
1172                 case 'm':
1173                         start_monitor = true;
1174                         break;
1175                 case 'q':
1176                         qemu_binary = optarg;
1177                         break;
1178                 case 'k':
1179                         kernel_image = optarg;
1180                         break;
1181                 case 'A':
1182                         audio_support = true;
1183                         break;
1184                 case 'v':
1185                         printf("%s\n", VERSION);
1186                         return EXIT_SUCCESS;
1187                 case 'h':
1188                         usage();
1189                         return EXIT_SUCCESS;
1190                 default:
1191                         return EXIT_FAILURE;
1192                 }
1193         }
1194
1195         if (run_auto) {
1196                 if (argc - optind > 0) {
1197                         fprintf(stderr, "Invalid command line parameters\n");
1198                         return EXIT_FAILURE;
1199                 }
1200         } else {
1201                 if (argc - optind < 1) {
1202                         fprintf(stderr, "Failed to specify test command\n");
1203                         return EXIT_FAILURE;
1204                 }
1205         }
1206
1207         own_binary = argv[0];
1208         test_argv = argv + optind;
1209         test_argc = argc - optind;
1210
1211         if (!qemu_binary) {
1212                 qemu_binary = find_qemu();
1213                 if (!qemu_binary) {
1214                         fprintf(stderr, "No default QEMU binary found\n");
1215                         return EXIT_FAILURE;
1216                 }
1217         }
1218
1219         if (!kernel_image) {
1220                 kernel_image = find_kernel();
1221                 if (!kernel_image) {
1222                         fprintf(stderr, "No default kernel image found\n");
1223                         return EXIT_FAILURE;
1224                 }
1225         }
1226
1227         printf("Using QEMU binary %s\n", qemu_binary);
1228         printf("Using kernel image %s\n", kernel_image);
1229
1230         start_qemu();
1231
1232         return EXIT_SUCCESS;
1233 }