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$ 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 48 static int write_pid_file (char const *file); 49 static int remove_pid_file (char const *file); 50 static int elapsed (int tval); 51 static void sighandler (int s); 52 static void sighup (int s); 53 static void usage (void); 54 55 /* 56 * bthidd 57 */ 58 59 static int done = 0; /* are we done? */ 60 static int reload = 0; /* reload config file */ 61 62 int 63 main(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 203 static int 204 write_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 226 static int 227 remove_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 244 static int 245 elapsed(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 264 static void 265 sighandler(int s) 266 { 267 syslog(LOG_NOTICE, "Got signal %d, total number of signals %d", 268 s, ++ done); 269 } 270 271 static void 272 sighup(int s) 273 { 274 syslog(LOG_NOTICE, "Got SIGHUP: reload config"); 275 reload = 1; 276 } 277 278 /* 279 * Display usage and exit 280 */ 281 282 static void 283 usage(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