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 usage (void); 53 54 /* 55 * bthidd 56 */ 57 58 static int done = 0; /* are we done? */ 59 60 int 61 main(int argc, char *argv[]) 62 { 63 struct bthid_server srv; 64 struct sigaction sa; 65 char const *pid_file = BTHIDD_PIDFILE, *ep = NULL; 66 int opt, detach, tval; 67 68 memset(&srv, 0, sizeof(srv)); 69 memcpy(&srv.bdaddr, NG_HCI_BDADDR_ANY, sizeof(srv.bdaddr)); 70 srv.windex = -1; 71 detach = 1; 72 tval = 10; /* sec */ 73 74 while ((opt = getopt(argc, argv, "a:c:dH:hp:s:t:")) != -1) { 75 switch (opt) { 76 case 'a': /* BDADDR */ 77 if (!bt_aton(optarg, &srv.bdaddr)) { 78 struct hostent *he = NULL; 79 80 if ((he = bt_gethostbyname(optarg)) == NULL) 81 errx(1, "%s: %s", optarg, hstrerror(h_errno)); 82 83 memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr)); 84 } 85 break; 86 87 case 'c': /* config file */ 88 config_file = optarg; 89 break; 90 91 case 'd': /* do not detach */ 92 detach = 0; 93 break; 94 95 case 'H': /* hids file */ 96 hids_file = optarg; 97 break; 98 99 case 'p': /* pid file */ 100 pid_file = optarg; 101 break; 102 103 case 's': /* switch script */ 104 srv.script = optarg; 105 break; 106 107 case 't': /* rescan interval */ 108 tval = strtol(optarg, (char **) &ep, 10); 109 if (*ep != '\0' || tval <= 0) 110 usage(); 111 break; 112 113 case 'u': /* wired keyboard index */ 114 srv.windex = strtol(optarg, (char **) &ep, 10); 115 if (*ep != '\0' || srv.windex < 0) 116 usage(); 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 for (done = 0; !done; ) { 167 if (elapsed(tval)) 168 client_rescan(&srv); 169 170 if (server_do(&srv) < 0) 171 break; 172 } 173 174 server_shutdown(&srv); 175 remove_pid_file(pid_file); 176 clean_config(); 177 closelog(); 178 179 return (0); 180 } 181 182 /* 183 * Write pid file 184 */ 185 186 static int 187 write_pid_file(char const *file) 188 { 189 FILE *pid = NULL; 190 191 assert(file != NULL); 192 193 if ((pid = fopen(file, "w")) == NULL) { 194 syslog(LOG_ERR, "Could not open file %s. %s (%d)", 195 file, strerror(errno), errno); 196 return (-1); 197 } 198 199 fprintf(pid, "%d", getpid()); 200 fclose(pid); 201 202 return (0); 203 } 204 205 /* 206 * Remote pid file 207 */ 208 209 static int 210 remove_pid_file(char const *file) 211 { 212 assert(file != NULL); 213 214 if (unlink(file) < 0) { 215 syslog(LOG_ERR, "Could not unlink file %s. %s (%d)", 216 file, strerror(errno), errno); 217 return (-1); 218 } 219 220 return (0); 221 } 222 223 /* 224 * Returns true if desired time interval has elapsed 225 */ 226 227 static int 228 elapsed(int tval) 229 { 230 static struct timeval last = { 0, }; 231 struct timeval now; 232 233 gettimeofday(&now, NULL); 234 235 if (now.tv_sec - last.tv_sec >= tval) { 236 last = now; 237 return (1); 238 } 239 240 return (0); 241 } 242 243 /* 244 * Signal handler 245 */ 246 247 static void 248 sighandler(int s) 249 { 250 syslog(LOG_NOTICE, "Got signal %d, total number of signals %d", 251 s, ++ done); 252 } 253 254 /* 255 * Display usage and exit 256 */ 257 258 static void 259 usage(void) 260 { 261 fprintf(stderr, 262 "Usage: %s [options]\n" \ 263 "Where options are:\n" \ 264 " -a address specify address to listen on (default ANY)\n" \ 265 " -c file specify config file name\n" \ 266 " -d run in foreground\n" \ 267 " -H file specify known HIDs file name\n" \ 268 " -h display this message\n" \ 269 " -p file specify PID file name\n" \ 270 " -s script specify keyboard switching script\n" \ 271 " -t tval specify client rescan interval (sec)\n" \ 272 " -u unit specify wired keyboard unit\n" \ 273 "", BTHIDD_IDENT); 274 exit(255); 275 } 276 277