1 /* 2 * bthidd.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 34 */ 35 36 #include <sys/time.h> 37 #include <sys/queue.h> 38 #include <assert.h> 39 #define L2CAP_SOCKET_CHECKED 40 #include <bluetooth.h> 41 #include <err.h> 42 #include <errno.h> 43 #include <signal.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <syslog.h> 48 #include <unistd.h> 49 #include <usbhid.h> 50 #include "bthid_config.h" 51 #include "bthidd.h" 52 53 static int32_t write_pid_file (char const *file); 54 static int32_t remove_pid_file (char const *file); 55 static int32_t elapsed (int32_t tval); 56 static void sighandler (int32_t s); 57 static void usage (void); 58 59 /* 60 * bthidd 61 */ 62 63 static int32_t done = 0; /* are we done? */ 64 65 int32_t 66 main(int32_t argc, char *argv[]) 67 { 68 struct bthid_server srv; 69 struct sigaction sa; 70 char const *pid_file = BTHIDD_PIDFILE; 71 char *ep; 72 int32_t opt, detach, tval, uinput; 73 74 memset(&srv, 0, sizeof(srv)); 75 memset(&srv.bdaddr, 0, sizeof(srv.bdaddr)); 76 detach = 1; 77 tval = 10; /* sec */ 78 uinput = 0; 79 80 while ((opt = getopt(argc, argv, "a:c:dH:hp:t:u")) != -1) { 81 switch (opt) { 82 case 'a': /* BDADDR */ 83 if (!bt_aton(optarg, &srv.bdaddr)) { 84 struct hostent *he; 85 86 if ((he = bt_gethostbyname(optarg)) == NULL) 87 errx(1, "%s: %s", optarg, hstrerror(h_errno)); 88 89 memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr)); 90 } 91 break; 92 93 case 'c': /* config file */ 94 config_file = optarg; 95 break; 96 97 case 'd': /* do not detach */ 98 detach = 0; 99 break; 100 101 case 'H': /* hids file */ 102 hids_file = optarg; 103 break; 104 105 case 'p': /* pid file */ 106 pid_file = optarg; 107 break; 108 109 case 't': /* rescan interval */ 110 tval = strtol(optarg, (char **) &ep, 10); 111 if (*ep != '\0' || tval <= 0) 112 usage(); 113 break; 114 115 case 'u': /* enable evdev support */ 116 uinput = 1; 117 break; 118 119 case 'h': 120 default: 121 usage(); 122 /* NOT REACHED */ 123 } 124 } 125 126 openlog(BTHIDD_IDENT, LOG_PID|LOG_PERROR|LOG_NDELAY, LOG_USER); 127 128 /* Become daemon if required */ 129 if (detach && daemon(0, 0) < 0) { 130 syslog(LOG_CRIT, "Could not become daemon. %s (%d)", 131 strerror(errno), errno); 132 exit(1); 133 } 134 135 /* Install signal handler */ 136 memset(&sa, 0, sizeof(sa)); 137 sa.sa_handler = sighandler; 138 139 if (sigaction(SIGTERM, &sa, NULL) < 0 || 140 sigaction(SIGHUP, &sa, NULL) < 0 || 141 sigaction(SIGINT, &sa, NULL) < 0) { 142 syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", 143 strerror(errno), errno); 144 exit(1); 145 } 146 147 sa.sa_handler = SIG_IGN; 148 if (sigaction(SIGPIPE, &sa, NULL) < 0) { 149 syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", 150 strerror(errno), errno); 151 exit(1); 152 } 153 154 sa.sa_handler = SIG_IGN; 155 sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT; 156 if (sigaction(SIGCHLD, &sa, NULL) < 0) { 157 syslog(LOG_CRIT, "Could not install signal handlers. %s (%d)", 158 strerror(errno), errno); 159 exit(1); 160 } 161 162 if (read_config_file() < 0 || read_hids_file() < 0 || 163 server_init(&srv) < 0 || write_pid_file(pid_file) < 0) 164 exit(1); 165 166 srv.uinput = uinput; 167 168 for (done = 0; !done; ) { 169 if (elapsed(tval)) 170 client_rescan(&srv); 171 172 if (server_do(&srv) < 0) 173 break; 174 } 175 176 server_shutdown(&srv); 177 remove_pid_file(pid_file); 178 clean_config(); 179 closelog(); 180 181 return (0); 182 } 183 184 /* 185 * Write pid file 186 */ 187 188 static int32_t 189 write_pid_file(char const *file) 190 { 191 FILE *pid; 192 193 assert(file != NULL); 194 195 if ((pid = fopen(file, "w")) == NULL) { 196 syslog(LOG_ERR, "Could not open file %s. %s (%d)", 197 file, strerror(errno), errno); 198 return (-1); 199 } 200 201 fprintf(pid, "%d", getpid()); 202 fclose(pid); 203 204 return (0); 205 } 206 207 /* 208 * Remote pid file 209 */ 210 211 static int32_t 212 remove_pid_file(char const *file) 213 { 214 assert(file != NULL); 215 216 if (unlink(file) < 0) { 217 syslog(LOG_ERR, "Could not unlink file %s. %s (%d)", 218 file, strerror(errno), errno); 219 return (-1); 220 } 221 222 return (0); 223 } 224 225 /* 226 * Returns true if desired time interval has elapsed 227 */ 228 229 static int32_t 230 elapsed(int32_t tval) 231 { 232 static struct timeval last = { 0, 0 }; 233 struct timeval now; 234 235 gettimeofday(&now, NULL); 236 237 if (now.tv_sec - last.tv_sec >= tval) { 238 last = now; 239 return (1); 240 } 241 242 return (0); 243 } 244 245 /* 246 * Signal handler 247 */ 248 249 static void 250 sighandler(int32_t s) 251 { 252 syslog(LOG_NOTICE, "Got signal %d, total number of signals %d", 253 s, ++ done); 254 } 255 256 /* 257 * Display usage and exit 258 */ 259 260 static void 261 usage(void) 262 { 263 fprintf(stderr, 264 "Usage: %s [options]\n" \ 265 "Where options are:\n" \ 266 " -a address specify address to listen on (default ANY)\n" \ 267 " -c file specify config file name\n" \ 268 " -d run in foreground\n" \ 269 " -H file specify known HIDs file name\n" \ 270 " -h display this message\n" \ 271 " -p file specify PID file name\n" \ 272 " -t tval specify client rescan interval (sec)\n" \ 273 " -u enable evdev protocol support\n" \ 274 "", BTHIDD_IDENT); 275 exit(255); 276 } 277 278