/* * * 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 #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #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[]) { int exit_status; if (getpid() == 1 && getppid() == 0) is_init = true; mainloop_init(); 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_with_signal(signal_callback, NULL); if (is_init) attach_stop(); gap_stop(); log_close(); return exit_status; }