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