| // SPDX-License-Identifier: LGPL-2.1-or-later |
| /* |
| * |
| * BlueZ - Bluetooth protocol stack for Linux |
| * |
| * Copyright (C) 2015 Intel Corporation. All rights reserved. |
| * |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #define _GNU_SOURCE |
| #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 "src/shared/util.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 && mount_table[i].target; i++) { |
| struct stat st; |
| |
| if (lstat(mount_table[i].target, &st) < 0) { |
| printf("Creating %s\n", mount_table[i].target); |
| if (mkdir(mount_table[i].target, 0755) < 0) |
| perror("Failed to create dir"); |
| } |
| |
| 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"); |
| |
| if (util_getrandom(addr, sizeof(addr), 0) < 0) { |
| perror("Failed to get random static address"); |
| return EXIT_FAILURE; |
| } |
| /* Overwrite the MSB to make it a static address */ |
| 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; |
| } |