1 /* $NetBSD: bthcid.c,v 1.3 2007/01/25 20:33:41 plunky Exp $ */ 2 /* $DragonFly: src/usr.sbin/bthcid/bthcid.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */ 3 4 /*- 5 * Copyright (c) 2006 Itronix Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of Itronix Inc. may not be used to endorse 17 * or promote products derived from this software without specific 18 * prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 * ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 #include <sys/event.h> 37 #include <sys/time.h> 38 #include <bluetooth.h> 39 #include <err.h> 40 #include <errno.h> 41 #include <libutil.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <syslog.h> 45 #include <unistd.h> 46 47 #include "bthcid.h" 48 49 const char *socket_name = BTHCID_SOCKET_NAME; 50 int detach = 1; 51 52 int hci_kq; 53 54 static void process_signal(int); 55 static void usage(void); 56 57 int 58 main(int argc, char *argv[]) 59 { 60 bdaddr_t bdaddr; 61 int ch, hci_fd, control_fd; 62 mode_t mode; 63 struct kevent change; 64 struct timespec timeout = { 0, 0 }; 65 66 bdaddr_copy(&bdaddr, BDADDR_ANY); 67 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 68 69 while ((ch = getopt(argc, argv, "d:fm:ns:h")) != -1) { 70 switch (ch) { 71 case 'd': 72 if (!bt_devaddr(optarg, &bdaddr)) 73 err(EXIT_FAILURE, "%s", optarg); 74 break; 75 76 case 'f': 77 detach = 0; 78 break; 79 80 case 'm': 81 mode = atoi(optarg); 82 break; 83 84 case 'n': 85 socket_name = NULL; 86 break; 87 88 case 's': 89 socket_name = optarg; 90 break; 91 92 case 'h': 93 default: 94 usage(); 95 /* NOT REACHED */ 96 } 97 } 98 99 if (getuid() != 0) 100 errx(EXIT_FAILURE, 101 "** ERROR: You should run %s as privileged user!", 102 getprogname()); 103 104 if (detach) 105 if (daemon(0, 0) < 0) 106 err(EXIT_FAILURE, "Could not daemon()ize"); 107 108 openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON); 109 110 if ((hci_kq = kqueue()) == -1) { 111 syslog(LOG_ERR, "could not create kqueue"); 112 exit(EXIT_FAILURE); 113 } 114 115 EV_SET(&change, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 116 kevent(hci_kq, &change, 1, NULL, 0, &timeout); 117 EV_SET(&change, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 118 kevent(hci_kq, &change, 1, NULL, 0, &timeout); 119 EV_SET(&change, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 120 kevent(hci_kq, &change, 1, NULL, 0, &timeout); 121 122 if ((hci_fd = init_hci(&bdaddr)) < 0) { 123 syslog(LOG_ERR, "init_hci(%s)", bt_ntoa(&bdaddr, NULL)); 124 exit(EXIT_FAILURE); 125 } 126 127 if ((control_fd = init_control(socket_name, mode)) < 0) { 128 syslog(LOG_ERR, "init_control(%s)", socket_name); 129 exit(EXIT_FAILURE); 130 } 131 132 if (detach && pidfile(NULL) < 0) { 133 syslog(LOG_ERR, "Could not create PID file: %m"); 134 exit(EXIT_FAILURE); 135 } 136 137 read_config_file(); 138 read_keys_file(); 139 140 for ( ; ; ) { 141 int i, nevents; 142 struct kevent events[BTHCID_KQ_EVENTS], *event; 143 144 nevents = kevent(hci_kq, NULL, 0, &events[0], BTHCID_KQ_EVENTS, NULL); 145 if (nevents == -1) { 146 syslog(LOG_ERR, "kevent failure"); 147 exit(EXIT_FAILURE); 148 } 149 150 for (i = 0; i < nevents; ++i) { 151 event = &events[i]; 152 153 if (event->filter == EVFILT_SIGNAL) { 154 process_signal(event->ident); 155 continue; 156 } 157 158 if (event->filter == EVFILT_TIMER) { 159 process_item(event->udata); 160 continue; 161 } 162 163 if (event->ident == (u_int)control_fd) { 164 process_control(event->ident); 165 continue; 166 } else if (event->ident == (u_int)hci_fd) { 167 process_hci(event->ident); 168 continue; 169 } else if (event->udata != NULL) { 170 process_client(event->ident, event->udata); 171 continue; 172 } 173 174 syslog(LOG_DEBUG, "Unknown event for descriptor %d", 175 (int)event->ident); 176 } 177 } 178 179 /* NOTREACHED */ 180 /* gcc fodder */ 181 exit(EXIT_FAILURE); 182 } 183 184 static void 185 process_signal(int s) 186 { 187 if (s == SIGHUP) { 188 syslog(LOG_DEBUG, "Got SIGHUP (%d). Dumping and rereading config", s); 189 dump_keys_file(); 190 read_config_file(); 191 read_keys_file(); 192 return; 193 } 194 195 196 197 syslog(LOG_DEBUG, "Exiting on signal %d", s); 198 199 if (socket_name) 200 unlink(socket_name); 201 202 clean_config(); 203 closelog(); 204 exit(EXIT_FAILURE); 205 206 } 207 208 /* Display usage and exit */ 209 static void 210 usage(void) 211 { 212 213 fprintf(stderr, 214 "Usage: %s [-fhn] [-c config] [-d devaddr] [-m mode] [-s path]\n" 215 "Where:\n" 216 "\t-c config specify config filename\n" 217 "\t-d device specify device address\n" 218 "\t-f run in foreground\n" 219 "\t-m mode specify socket permissions\n" 220 "\t-n do not listen for clients\n" 221 "\t-s path specify client socket pathname\n" 222 "\t-h display this message\n", 223 getprogname()); 224 225 exit(EXIT_FAILURE); 226 } 227