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 struct pidfh *pfh = NULL; 66 const char *pidfile = NULL; 67 68 bdaddr_copy(&bdaddr, BDADDR_ANY); 69 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 70 71 while ((ch = getopt(argc, argv, "d:fm:ns:h")) != -1) { 72 switch (ch) { 73 case 'd': 74 if (!bt_devaddr(optarg, &bdaddr)) 75 err(EXIT_FAILURE, "%s", optarg); 76 break; 77 78 case 'f': 79 detach = 0; 80 break; 81 82 case 'm': 83 mode = atoi(optarg); 84 break; 85 86 case 'n': 87 socket_name = NULL; 88 break; 89 90 case 's': 91 socket_name = optarg; 92 break; 93 94 case 'h': 95 default: 96 usage(); 97 /* NOT REACHED */ 98 } 99 } 100 101 if (getuid() != 0) 102 errx(EXIT_FAILURE, 103 "** ERROR: You should run %s as privileged user!", 104 getprogname()); 105 106 if (detach) 107 if (daemon(0, 0) < 0) 108 err(EXIT_FAILURE, "Could not daemon()ize"); 109 110 openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON); 111 112 if ((hci_kq = kqueue()) == -1) { 113 syslog(LOG_ERR, "could not create kqueue"); 114 exit(EXIT_FAILURE); 115 } 116 117 EV_SET(&change, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 118 kevent(hci_kq, &change, 1, NULL, 0, &timeout); 119 EV_SET(&change, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 120 kevent(hci_kq, &change, 1, NULL, 0, &timeout); 121 EV_SET(&change, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 122 kevent(hci_kq, &change, 1, NULL, 0, &timeout); 123 124 if ((hci_fd = init_hci(&bdaddr)) < 0) { 125 syslog(LOG_ERR, "init_hci(%s)", bt_ntoa(&bdaddr, NULL)); 126 exit(EXIT_FAILURE); 127 } 128 129 if ((control_fd = init_control(socket_name, mode)) < 0) { 130 syslog(LOG_ERR, "init_control(%s)", socket_name); 131 exit(EXIT_FAILURE); 132 } 133 134 if (detach) { 135 pfh = pidfile_open(pidfile, 600, NULL); 136 if (pfh == NULL) { 137 syslog(LOG_ERR, "Could not create PID file: %m"); 138 exit(EXIT_FAILURE); 139 } 140 pidfile_write(pfh); 141 } 142 143 read_config_file(); 144 read_keys_file(); 145 146 for ( ; ; ) { 147 int i, nevents; 148 struct kevent events[BTHCID_KQ_EVENTS], *event; 149 150 nevents = kevent(hci_kq, NULL, 0, &events[0], BTHCID_KQ_EVENTS, NULL); 151 if (nevents == -1) { 152 syslog(LOG_ERR, "kevent failure"); 153 exit(EXIT_FAILURE); 154 } 155 156 for (i = 0; i < nevents; ++i) { 157 event = &events[i]; 158 159 if (event->filter == EVFILT_SIGNAL) { 160 process_signal(event->ident); 161 continue; 162 } 163 164 if (event->filter == EVFILT_TIMER) { 165 process_item(event->udata); 166 continue; 167 } 168 169 if (event->ident == (u_int)control_fd) { 170 process_control(event->ident); 171 continue; 172 } else if (event->ident == (u_int)hci_fd) { 173 process_hci(event->ident); 174 continue; 175 } else if (event->udata != NULL) { 176 process_client(event->ident, event->udata); 177 continue; 178 } 179 180 syslog(LOG_DEBUG, "Unknown event for descriptor %d", 181 (int)event->ident); 182 } 183 } 184 185 /* NOTREACHED */ 186 /* gcc fodder */ 187 exit(EXIT_FAILURE); 188 } 189 190 static void 191 process_signal(int s) 192 { 193 if (s == SIGHUP) { 194 syslog(LOG_DEBUG, "Got SIGHUP (%d). Dumping and rereading config", s); 195 dump_keys_file(); 196 read_config_file(); 197 read_keys_file(); 198 return; 199 } 200 201 202 203 syslog(LOG_DEBUG, "Exiting on signal %d", s); 204 205 if (socket_name) 206 unlink(socket_name); 207 208 clean_config(); 209 closelog(); 210 exit(EXIT_FAILURE); 211 212 } 213 214 /* Display usage and exit */ 215 static void 216 usage(void) 217 { 218 219 fprintf(stderr, 220 "Usage: %s [-fhn] [-c config] [-d devaddr] [-m mode] [-s path]\n" 221 "Where:\n" 222 "\t-c config specify config filename\n" 223 "\t-d device specify device address\n" 224 "\t-f run in foreground\n" 225 "\t-m mode specify socket permissions\n" 226 "\t-n do not listen for clients\n" 227 "\t-s path specify client socket pathname\n" 228 "\t-h display this message\n", 229 getprogname()); 230 231 exit(EXIT_FAILURE); 232 } 233