| /* |
| * |
| * BlueZ - Bluetooth protocol stack for Linux |
| * |
| * Copyright (C) 2015 Intel Corporation. All rights reserved. |
| * |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <stdbool.h> |
| #include <signal.h> |
| #include <string.h> |
| #include <poll.h> |
| #include <sys/wait.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/mount.h> |
| |
| #ifndef WAIT_ANY |
| #define WAIT_ANY (-1) |
| #endif |
| |
| #include "src/shared/mainloop.h" |
| #include "peripheral/efivars.h" |
| #include "peripheral/attach.h" |
| #include "peripheral/gap.h" |
| #include "peripheral/log.h" |
| |
| static bool is_init = false; |
| static pid_t shell_pid = -1; |
| |
| static const struct { |
| const char *target; |
| const char *linkpath; |
| } dev_table[] = { |
| { "/proc/self/fd", "/dev/fd" }, |
| { "/proc/self/fd/0", "/dev/stdin" }, |
| { "/proc/self/fd/1", "/dev/stdout" }, |
| { "/proc/self/fd/2", "/dev/stderr" }, |
| { } |
| }; |
| |
| static const struct { |
| const char *fstype; |
| const char *target; |
| const char *options; |
| unsigned long flags; |
| } mount_table[] = { |
| { "sysfs", "/sys", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV }, |
| { "proc", "/proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV }, |
| { "devtmpfs", "/dev", NULL, MS_NOSUID|MS_STRICTATIME }, |
| { "efivarfs", "/sys/firmware/efi/efivars", |
| NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV }, |
| { "pstore", "/sys/fs/pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV }, |
| { } |
| }; |
| |
| static void prepare_filesystem(void) |
| { |
| int i; |
| |
| if (!is_init) |
| return; |
| |
| for (i = 0; mount_table[i].fstype; i++) { |
| struct stat st; |
| |
| if (lstat(mount_table[i].target, &st) < 0) { |
| printf("Creating %s\n", mount_table[i].target); |
| mkdir(mount_table[i].target, 0755); |
| } |
| |
| printf("Mounting %s to %s\n", mount_table[i].fstype, |
| mount_table[i].target); |
| |
| if (mount(mount_table[i].fstype, |
| mount_table[i].target, |
| mount_table[i].fstype, |
| mount_table[i].flags, NULL) < 0) |
| perror("Failed to mount filesystem"); |
| } |
| |
| for (i = 0; dev_table[i].target; i++) { |
| printf("Linking %s to %s\n", dev_table[i].linkpath, |
| dev_table[i].target); |
| |
| if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0) |
| perror("Failed to create device symlink"); |
| } |
| } |
| |
| static void run_shell(void) |
| { |
| pid_t pid; |
| |
| printf("Starting shell\n"); |
| |
| pid = fork(); |
| if (pid < 0) { |
| perror("Failed to fork new process"); |
| return; |
| } |
| |
| if (pid == 0) { |
| char *prg_argv[] = { "/bin/sh", NULL }; |
| char *prg_envp[] = { NULL }; |
| |
| execve(prg_argv[0], prg_argv, prg_envp); |
| exit(0); |
| } |
| |
| printf("PID %d created\n", pid); |
| |
| shell_pid = pid; |
| } |
| |
| static void exit_shell(void) |
| { |
| shell_pid = -1; |
| |
| if (!is_init) { |
| mainloop_quit(); |
| return; |
| } |
| |
| run_shell(); |
| } |
| |
| static void signal_callback(int signum, void *user_data) |
| { |
| switch (signum) { |
| case SIGINT: |
| case SIGTERM: |
| mainloop_quit(); |
| break; |
| case SIGCHLD: |
| while (1) { |
| pid_t pid; |
| int status; |
| |
| pid = waitpid(WAIT_ANY, &status, WNOHANG); |
| if (pid < 0 || pid == 0) |
| break; |
| |
| if (WIFEXITED(status)) { |
| printf("PID %d exited (status=%d)\n", |
| pid, WEXITSTATUS(status)); |
| |
| if (pid == shell_pid) |
| exit_shell(); |
| } else if (WIFSIGNALED(status)) { |
| printf("PID %d terminated (signal=%d)\n", |
| pid, WTERMSIG(status)); |
| |
| if (pid == shell_pid) |
| exit_shell(); |
| } |
| } |
| break; |
| } |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| sigset_t mask; |
| int exit_status; |
| |
| if (getpid() == 1 && getppid() == 0) |
| is_init = true; |
| |
| mainloop_init(); |
| |
| sigemptyset(&mask); |
| sigaddset(&mask, SIGINT); |
| sigaddset(&mask, SIGTERM); |
| sigaddset(&mask, SIGCHLD); |
| |
| mainloop_set_signal(&mask, signal_callback, NULL, NULL); |
| |
| printf("Bluetooth periperhal ver %s\n", VERSION); |
| |
| prepare_filesystem(); |
| |
| if (is_init) { |
| uint8_t addr[6]; |
| |
| if (efivars_read("BluetoothStaticAddress", NULL, |
| addr, 6) < 0) { |
| printf("Generating new persistent static address\n"); |
| |
| addr[0] = rand(); |
| addr[1] = rand(); |
| addr[2] = rand(); |
| addr[3] = 0x34; |
| addr[4] = 0x12; |
| addr[5] = 0xc0; |
| |
| efivars_write("BluetoothStaticAddress", |
| EFIVARS_NON_VOLATILE | |
| EFIVARS_BOOTSERVICE_ACCESS | |
| EFIVARS_RUNTIME_ACCESS, |
| addr, 6); |
| } |
| |
| gap_set_static_address(addr); |
| |
| run_shell(); |
| } |
| |
| log_open(); |
| gap_start(); |
| |
| if (is_init) |
| attach_start(); |
| |
| exit_status = mainloop_run(); |
| |
| if (is_init) |
| attach_stop(); |
| |
| gap_stop(); |
| log_close(); |
| |
| return exit_status; |
| } |