1/* 2 * bthidd.c 3 */ 4 5/*- 6 * SPDX-License-Identifier: BSD-2-Clause 7 * 8 * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: bthidd.c,v 1.8 2006/09/07 21:06:53 max Exp $ 33 */ 34 35#include <sys/time.h> 36#include <sys/queue.h> 37#include <assert.h> 38#define L2CAP_SOCKET_CHECKED 39#include <bluetooth.h> 40#include <err.h> 41#include <errno.h> 42#include <signal.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <syslog.h> 47#include <unistd.h> 48#include <usbhid.h> 49#include "bthid_config.h" 50#include "bthidd.h" 51 52static int32_t write_pid_file (char const *file); 53static int32_t remove_pid_file (char const *file); 54static int32_t elapsed (int32_t tval); 55static void sighandler (int32_t s); 56static void usage (void); 57 58/* 59 * bthidd 60 */ 61 62static int32_t done = 0; /* are we done? */ 63 64int32_t 65main(int32_t argc, char *argv[]) 66{ 67 struct bthid_server srv; 68 struct sigaction sa; 69 char const *pid_file = BTHIDD_PIDFILE; 70 char *ep; 71 int32_t opt, detach, tval, uinput; 72 73 memset(&srv, 0, sizeof(srv)); 74 memset(&srv.bdaddr, 0, sizeof(srv.bdaddr)); 75 detach = 1; 76 tval = 10; /* sec */ 77 uinput = 0; 78 79 while ((opt = getopt(argc, argv, "a:c:dH:hp:t:u")) != -1) { 80 switch (opt) { 81 case 'a': /* BDADDR */ 82 if (!bt_aton(optarg, &srv.bdaddr)) { 83 struct hostent *he; 84 85 if ((he = bt_gethostbyname(optarg)) == NULL) 86 errx(1, "%s: %s", optarg, hstrerror(h_errno)); 87 88 memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr)); 89 } 90 break; 91 92 case 'c': /* config file */ 93 config_file = optarg; 94 break; 95 96 case 'd': /* do not detach */ 97 detach = 0; 98 break; 99 100 case 'H': /* hids file */ 101 hids_file = optarg; 102 break; 103 104 case 'p': /* pid file */ 105 pid_file = optarg; 106 break; 107 108 case 't': /* rescan interval */ 109 tval = strtol(optarg, (char **) &ep, 10); 110 if (*ep != '\0' || tval <= 0) 111 usage(); 112 break; 113 114 case 'u': /* enable evdev support */ 115 uinput = 1; 116 break; 117 118 case 'h': 119 default: 120 usage(); 121 /* NOT REACHED */ 122 } 123 } 124 125 openlog(BTHIDD_IDENT, LOG_PID|LOG_PERROR|LOG_NDELAY, LOG_USER); 126 127 /* Become daemon if required */ 128 if (detach && daemon(0, 0) < 0) { 129 syslog(LOG_CRIT, "Could not become daemon. %s (%d)", 130 strerror(errno), errno); 131 exit(1); 132 } 133 134 /* Install signal handler */ 135 memset(&sa, 0, sizeof(sa)); 136 sa.sa_handler = sighandler; 137 138 if (sigaction(SIGTERM, &sa, NULL) < 0 || 139 sigaction(SIGHUP, &sa, NULL) < 0 || 140 sigaction(SIGINT, &sa, NULL) < 0) { 141 syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", 142 strerror(errno), errno); 143 exit(1); 144 } 145 146 sa.sa_handler = SIG_IGN; 147 if (sigaction(SIGPIPE, &sa, NULL) < 0) { 148 syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", 149 strerror(errno), errno); 150 exit(1); 151 } 152 153 sa.sa_handler = SIG_IGN; 154 sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT; 155 if (sigaction(SIGCHLD, &sa, NULL) < 0) { 156 syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", 157 strerror(errno), errno); 158 exit(1); 159 } 160 161 if (read_config_file() < 0 || read_hids_file() < 0 || 162 server_init(&srv) < 0 || write_pid_file(pid_file) < 0) 163 exit(1); 164 165 srv.uinput = uinput; 166 167 for (done = 0; !done; ) { 168 if (elapsed(tval)) 169 client_rescan(&srv); 170 171 if (server_do(&srv) < 0) 172 break; 173 } 174 175 server_shutdown(&srv); 176 remove_pid_file(pid_file); 177 clean_config(); 178 closelog(); 179 180 return (0); 181} 182 183/* 184 * Write pid file 185 */ 186 187static int32_t 188write_pid_file(char const *file) 189{ 190 FILE *pid; 191 192 assert(file != NULL); 193 194 if ((pid = fopen(file, "w")) == NULL) { 195 syslog(LOG_ERR, "Could not open file %s. %s (%d)", 196 file, strerror(errno), errno); 197 return (-1); 198 } 199 200 fprintf(pid, "%d", getpid()); 201 fclose(pid); 202 203 return (0); 204} 205 206/* 207 * Remote pid file 208 */ 209 210static int32_t 211remove_pid_file(char const *file) 212{ 213 assert(file != NULL); 214 215 if (unlink(file) < 0) { 216 syslog(LOG_ERR, "Could not unlink file %s. %s (%d)", 217 file, strerror(errno), errno); 218 return (-1); 219 } 220 221 return (0); 222} 223 224/* 225 * Returns true if desired time interval has elapsed 226 */ 227 228static int32_t 229elapsed(int32_t tval) 230{ 231 static struct timeval last = { 0, 0 }; 232 struct timeval now; 233 234 gettimeofday(&now, NULL); 235 236 if (now.tv_sec - last.tv_sec >= tval) { 237 last = now; 238 return (1); 239 } 240 241 return (0); 242} 243 244/* 245 * Signal handler 246 */ 247 248static void 249sighandler(int32_t s) 250{ 251 syslog(LOG_NOTICE, "Got signal %d, total number of signals %d", 252 s, ++ done); 253} 254 255/* 256 * Display usage and exit 257 */ 258 259static void 260usage(void) 261{ 262 fprintf(stderr, 263"Usage: %s [options]\n" \ 264"Where options are:\n" \ 265" -a address specify address to listen on (default ANY)\n" \ 266" -c file specify config file name\n" \ 267" -d run in foreground\n" \ 268" -H file specify known HIDs file name\n" \ 269" -h display this message\n" \ 270" -p file specify PID file name\n" \ 271" -t tval specify client rescan interval (sec)\n" \ 272" -u enable evdev protocol support\n" \ 273"", BTHIDD_IDENT); 274 exit(255); 275} 276 277