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