45e103f8dc19f4671b427c9a68a0b65ced3c992d
[platform/upstream/bluez.git] / peripheral / main.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2015  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 <unistd.h>
18 #include <stdlib.h>
19 #include <stdbool.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <poll.h>
23 #include <sys/wait.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/mount.h>
27
28 #ifndef WAIT_ANY
29 #define WAIT_ANY (-1)
30 #endif
31
32 #include "src/shared/mainloop.h"
33 #include "peripheral/efivars.h"
34 #include "peripheral/attach.h"
35 #include "peripheral/gap.h"
36 #include "peripheral/log.h"
37
38 static bool is_init = false;
39 static pid_t shell_pid = -1;
40
41 static const struct {
42         const char *target;
43         const char *linkpath;
44 } dev_table[] = {
45         { "/proc/self/fd",      "/dev/fd"       },
46         { "/proc/self/fd/0",    "/dev/stdin"    },
47         { "/proc/self/fd/1",    "/dev/stdout"   },
48         { "/proc/self/fd/2",    "/dev/stderr"   },
49         { }
50 };
51
52 static const struct {
53         const char *fstype;
54         const char *target;
55         const char *options;
56         unsigned long flags;
57 } mount_table[] = {
58         { "sysfs",    "/sys",           NULL,   MS_NOSUID|MS_NOEXEC|MS_NODEV },
59         { "proc",     "/proc",          NULL,   MS_NOSUID|MS_NOEXEC|MS_NODEV },
60         { "devtmpfs", "/dev",           NULL,   MS_NOSUID|MS_STRICTATIME },
61         { "efivarfs", "/sys/firmware/efi/efivars",
62                                         NULL,   MS_NOSUID|MS_NOEXEC|MS_NODEV },
63         { "pstore",   "/sys/fs/pstore", NULL,   MS_NOSUID|MS_NOEXEC|MS_NODEV },
64         { }
65 };
66
67 static void prepare_filesystem(void)
68 {
69         int i;
70
71         if (!is_init)
72                 return;
73
74         for (i = 0; mount_table[i].fstype; i++) {
75                 struct stat st;
76
77                 if (lstat(mount_table[i].target, &st) < 0) {
78                         printf("Creating %s\n", mount_table[i].target);
79                         if (mkdir(mount_table[i].target, 0755) < 0)
80                                 perror("Failed to create dir");
81                 }
82
83                 printf("Mounting %s to %s\n", mount_table[i].fstype,
84                                                 mount_table[i].target);
85
86                 if (mount(mount_table[i].fstype,
87                                 mount_table[i].target,
88                                 mount_table[i].fstype,
89                                 mount_table[i].flags, NULL) < 0)
90                         perror("Failed to mount filesystem");
91         }
92
93         for (i = 0; dev_table[i].target; i++) {
94                 printf("Linking %s to %s\n", dev_table[i].linkpath,
95                                                 dev_table[i].target);
96
97                 if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
98                         perror("Failed to create device symlink");
99         }
100 }
101
102 static void run_shell(void)
103 {
104         pid_t pid;
105
106         printf("Starting shell\n");
107
108         pid = fork();
109         if (pid < 0) {
110                 perror("Failed to fork new process");
111                 return;
112         }
113
114         if (pid == 0) {
115                 char *prg_argv[] = { "/bin/sh", NULL };
116                 char *prg_envp[] = { NULL };
117
118                 execve(prg_argv[0], prg_argv, prg_envp);
119                 exit(0);
120         }
121
122         printf("PID %d created\n", pid);
123
124         shell_pid = pid;
125 }
126
127 static void exit_shell(void)
128 {
129         shell_pid = -1;
130
131         if (!is_init) {
132                 mainloop_quit();
133                 return;
134         }
135
136         run_shell();
137 }
138
139 static void signal_callback(int signum, void *user_data)
140 {
141         switch (signum) {
142         case SIGINT:
143         case SIGTERM:
144                 mainloop_quit();
145                 break;
146         case SIGCHLD:
147                 while (1) {
148                         pid_t pid;
149                         int status;
150
151                         pid = waitpid(WAIT_ANY, &status, WNOHANG);
152                         if (pid < 0 || pid == 0)
153                                 break;
154
155                         if (WIFEXITED(status)) {
156                                 printf("PID %d exited (status=%d)\n",
157                                                 pid, WEXITSTATUS(status));
158
159                                 if (pid == shell_pid)
160                                         exit_shell();
161                         } else if (WIFSIGNALED(status)) {
162                                 printf("PID %d terminated (signal=%d)\n",
163                                                         pid, WTERMSIG(status));
164
165                                 if (pid == shell_pid)
166                                         exit_shell();
167                         }
168                 }
169                 break;
170         }
171 }
172
173 int main(int argc, char *argv[])
174 {
175         int exit_status;
176
177         if (getpid() == 1 && getppid() == 0)
178                 is_init = true;
179
180         mainloop_init();
181
182         printf("Bluetooth periperhal ver %s\n", VERSION);
183
184         prepare_filesystem();
185
186         if (is_init) {
187                 uint8_t addr[6];
188
189                 if (efivars_read("BluetoothStaticAddress", NULL,
190                                                         addr, 6) < 0) {
191                         printf("Generating new persistent static address\n");
192
193                         addr[0] = rand();
194                         addr[1] = rand();
195                         addr[2] = rand();
196                         addr[3] = 0x34;
197                         addr[4] = 0x12;
198                         addr[5] = 0xc0;
199
200                         efivars_write("BluetoothStaticAddress",
201                                         EFIVARS_NON_VOLATILE |
202                                         EFIVARS_BOOTSERVICE_ACCESS |
203                                         EFIVARS_RUNTIME_ACCESS,
204                                         addr, 6);
205                 }
206
207                 gap_set_static_address(addr);
208
209                 run_shell();
210         }
211
212         log_open();
213         gap_start();
214
215         if (is_init)
216                 attach_start();
217
218         exit_status = mainloop_run_with_signal(signal_callback, NULL);
219
220         if (is_init)
221                 attach_stop();
222
223         gap_stop();
224         log_close();
225
226         return exit_status;
227 }