1139825Simp/* 273782Sjasone * bthidd.c 373782Sjasone */ 473782Sjasone 573782Sjasone/*- 673782Sjasone * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com> 773782Sjasone * All rights reserved. 873782Sjasone * 973782Sjasone * Redistribution and use in source and binary forms, with or without 1073782Sjasone * modification, are permitted provided that the following conditions 1173782Sjasone * are met: 1273782Sjasone * 1. Redistributions of source code must retain the above copyright 1373782Sjasone * notice, this list of conditions and the following disclaimer. 1473782Sjasone * 2. Redistributions in binary form must reproduce the above copyright 1573782Sjasone * notice, this list of conditions and the following disclaimer in the 1673782Sjasone * documentation and/or other materials provided with the distribution. 1773782Sjasone * 1873782Sjasone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1973782Sjasone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2073782Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2173782Sjasone * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2273782Sjasone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2373782Sjasone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2473782Sjasone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2573782Sjasone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2673782Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2773782Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2873782Sjasone * SUCH DAMAGE. 2973782Sjasone * 3073782Sjasone * $Id: bthidd.c,v 1.8 2006/09/07 21:06:53 max Exp $ 3173782Sjasone * $FreeBSD$ 3273782Sjasone */ 33125444Sbde 3483103Sjhb#include <sys/time.h> 3574912Sjhb#include <sys/queue.h> 3673782Sjasone#include <assert.h> 3773782Sjasone#include <bluetooth.h> 3874912Sjhb#include <err.h> 3986333Sdillon#include <errno.h> 4073782Sjasone#include <signal.h> 4173782Sjasone#include <stdio.h> 4273782Sjasone#include <stdlib.h> 4373782Sjasone#include <string.h> 4473782Sjasone#include <syslog.h> 4583366Sjulian#include <unistd.h> 4673782Sjasone#include <usbhid.h> 4773782Sjasone#include "bthid_config.h" 4873782Sjasone#include "bthidd.h" 4993672Sarr 5073782Sjasonestatic int32_t write_pid_file (char const *file); 5173782Sjasonestatic int32_t remove_pid_file (char const *file); 5274912Sjhbstatic int32_t elapsed (int32_t tval); 5374912Sjhbstatic void sighandler (int32_t s); 5478872Sjhbstatic void usage (void); 5578872Sjhb 5674912Sjhb/* 5774912Sjhb * bthidd 5881599Sjasone */ 5981599Sjasone 60161721Sjhbstatic int32_t done = 0; /* are we done? */ 6185388Sjhb 6293688Sarrint32_t 63161337Sjhbmain(int32_t argc, char *argv[]) 64161337Sjhb{ 65161337Sjhb struct bthid_server srv; 6693672Sarr struct sigaction sa; 6793672Sarr char const *pid_file = BTHIDD_PIDFILE; 6893672Sarr char *ep; 6993672Sarr int32_t opt, detach, tval; 7093672Sarr 7193672Sarr memset(&srv, 0, sizeof(srv)); 7293672Sarr memset(&srv.bdaddr, 0, sizeof(srv.bdaddr)); 7393672Sarr detach = 1; 74149739Sjhb tval = 10; /* sec */ 75149739Sjhb 7693672Sarr while ((opt = getopt(argc, argv, "a:c:dH:hp:t:")) != -1) { 7793672Sarr switch (opt) { 78149739Sjhb case 'a': /* BDADDR */ 79149739Sjhb if (!bt_aton(optarg, &srv.bdaddr)) { 80149739Sjhb struct hostent *he; 8173782Sjasone 82159844Sjhb if ((he = bt_gethostbyname(optarg)) == NULL) 8383593Sjhb errx(1, "%s: %s", optarg, hstrerror(h_errno)); 8483593Sjhb 8583593Sjhb memcpy(&srv.bdaddr, he->h_addr, sizeof(srv.bdaddr)); 8683593Sjhb } 8783593Sjhb break; 8883593Sjhb 8983593Sjhb case 'c': /* config file */ 9083593Sjhb config_file = optarg; 91157296Sjhb break; 92159844Sjhb 93157296Sjhb case 'd': /* do not detach */ 94157296Sjhb detach = 0; 95157296Sjhb break; 96157296Sjhb 9774912Sjhb case 'H': /* hids file */ 9885412Sjhb hids_file = optarg; 9985388Sjhb break; 10085388Sjhb 10185388Sjhb case 'p': /* pid file */ 102125419Spjd pid_file = optarg; 103125444Sbde break; 10473863Sbmilekic 10585412Sjhb case 't': /* rescan interval */ 10685388Sjhb tval = strtol(optarg, (char **) &ep, 10); 107125444Sbde if (*ep != '\0' || tval <= 0) 10885388Sjhb usage(); 109125444Sbde break; 11073782Sjasone 111125444Sbde case 'h': 112125444Sbde default: 113125444Sbde 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 178static int32_t 179write_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 201static int32_t 202remove_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 219static int32_t 220elapsed(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 239static void 240sighandler(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 250static void 251usage(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