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