// SPDX-License-Identifier: LGPL-2.1-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. * * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #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" static char exec_dir[PATH_MAX]; static pid_t daemon_pid = -1; static pid_t snoop_pid = -1; static void run_valgrind(char *prg_name) { char *prg_argv[6]; char *prg_envp[3]; prg_argv[0] = "/usr/bin/valgrind"; prg_argv[1] = "--leak-check=full"; prg_argv[2] = "--track-origins=yes"; prg_argv[3] = prg_name; prg_argv[4] = "-d"; prg_argv[5] = NULL; prg_envp[0] = "G_SLICE=always-malloc"; prg_envp[1] = "G_DEBUG=gc-friendly"; prg_envp[2] = NULL; execve(prg_argv[0], prg_argv, prg_envp); } static void run_bluetoothd(char *prg_name) { char *prg_argv[3]; char *prg_envp[1]; prg_argv[0] = prg_name; prg_argv[1] = "-d"; prg_argv[2] = NULL; prg_envp[0] = NULL; execve(prg_argv[0], prg_argv, prg_envp); } static void ctl_start(void) { char prg_name[PATH_MAX + 11]; pid_t pid; snprintf(prg_name, sizeof(prg_name), "%s/%s", exec_dir, "bluetoothd"); printf("Starting %s\n", prg_name); pid = fork(); if (pid < 0) { perror("Failed to fork new process"); return; } if (pid == 0) { run_valgrind(prg_name); /* Fallback to no valgrind if running with valgind failed */ run_bluetoothd(prg_name); exit(0); } printf("New process %d created\n", pid); daemon_pid = pid; } static void snoop_start(void) { char prg_name[PATH_MAX + 17]; char *prg_argv[3]; char *prg_envp[1]; pid_t pid; snprintf(prg_name, sizeof(prg_name), "%s/%s", exec_dir, "bluetoothd-snoop"); prg_argv[0] = prg_name; prg_argv[1] = "/tmp/btsnoop_hci.log"; prg_argv[2] = NULL; prg_envp[0] = NULL; printf("Starting %s\n", prg_name); pid = fork(); if (pid < 0) { perror("Failed to fork new process"); return; } if (pid == 0) { execve(prg_argv[0], prg_argv, prg_envp); exit(0); } printf("New process %d created\n", pid); snoop_pid = pid; } static void snoop_stop(void) { printf("Stoping %s/%s\n", exec_dir, "bluetoothd-snoop"); kill(snoop_pid, SIGTERM); } static void system_socket_callback(int fd, uint32_t events, void *user_data) { char buf[4096]; ssize_t len; if (events & (EPOLLERR | EPOLLHUP)) { mainloop_remove_fd(fd); return; } len = read(fd, buf, sizeof(buf)); if (len < 0) return; printf("Received %s\n", buf); if (!strcmp(buf, "bluetooth.start=daemon")) { if (daemon_pid > 0) return; ctl_start(); } else if (!strcmp(buf, "bluetooth.start=snoop")) { if (snoop_pid > 0) return; snoop_start(); } else if (!strcmp(buf, "bluetooth.stop=snoop")) { if (snoop_pid > 0) snoop_stop(); } } 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; printf("Process %d terminated with status=%d\n", pid, status); if (pid == daemon_pid) daemon_pid = -1; else if (pid == snoop_pid) snoop_pid = -1; } break; } } int main(int argc, char *argv[]) { const char SYSTEM_SOCKET_PATH[] = "\0android_system"; struct sockaddr_un addr; int fd; mainloop_init(); printf("Android system emulator ver %s\n", VERSION); snprintf(exec_dir, sizeof(exec_dir), "%s", dirname(argv[0])); fd = socket(PF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (fd < 0) { perror("Failed to create system socket"); return EXIT_FAILURE; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; memcpy(addr.sun_path, SYSTEM_SOCKET_PATH, sizeof(SYSTEM_SOCKET_PATH)); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("Failed to bind system socket"); close(fd); return EXIT_FAILURE; } mainloop_add_fd(fd, EPOLLIN, system_socket_callback, NULL, NULL); /* Make sure bluetoothd creates files with proper permissions */ umask(0177); return mainloop_run_with_signal(signal_callback, NULL); }