main.c revision 03971a2d726bc9a8630b2419508235a2920eb19f
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2000-2001 Qualcomm Incorporated 6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 7 * Copyright (C) 2002-2009 Marcel Holtmann <marcel@holtmann.org> 8 * 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 */ 25 26#ifdef HAVE_CONFIG_H 27#include <config.h> 28#endif 29 30#include <errno.h> 31#include <stdio.h> 32#include <unistd.h> 33#include <stdlib.h> 34#include <string.h> 35#include <signal.h> 36#include <sys/stat.h> 37#include <sys/ioctl.h> 38#include <sys/socket.h> 39#include <sys/types.h> 40 41#include <bluetooth/bluetooth.h> 42#include <bluetooth/hci.h> 43#include <bluetooth/hci_lib.h> 44 45#include <glib.h> 46 47#include <dbus/dbus.h> 48 49#include "logging.h" 50 51#include "hcid.h" 52#include "sdpd.h" 53#include "adapter.h" 54#include "dbus-hci.h" 55#include "dbus-common.h" 56#include "agent.h" 57#include "manager.h" 58 59#define LAST_ADAPTER_EXIT_TIMEOUT 30 60 61struct main_opts main_opts; 62 63static GKeyFile *load_config(const char *file) 64{ 65 GError *err = NULL; 66 GKeyFile *keyfile; 67 68 keyfile = g_key_file_new(); 69 70 g_key_file_set_list_separator(keyfile, ','); 71 72 if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { 73 error("Parsing %s failed: %s", file, err->message); 74 g_error_free(err); 75 g_key_file_free(keyfile); 76 return NULL; 77 } 78 79 return keyfile; 80} 81 82static void parse_config(GKeyFile *config) 83{ 84 GError *err = NULL; 85 char *str; 86 int val; 87 gboolean boolean; 88 89 if (!config) 90 return; 91 92 debug("parsing main.conf"); 93 94 val = g_key_file_get_integer(config, "General", 95 "DiscoverableTimeout", &err); 96 if (err) { 97 debug("%s", err->message); 98 g_clear_error(&err); 99 } else { 100 debug("discovto=%d", val); 101 main_opts.discovto = val; 102 main_opts.flags |= 1 << HCID_SET_DISCOVTO; 103 } 104 105 val = g_key_file_get_integer(config, "General", 106 "PairableTimeout", &err); 107 if (err) { 108 debug("%s", err->message); 109 g_clear_error(&err); 110 } else { 111 debug("pairto=%d", val); 112 main_opts.pairto = val; 113 } 114 115 val = g_key_file_get_integer(config, "General", "PageTimeout", &err); 116 if (err) { 117 debug("%s", err->message); 118 g_clear_error(&err); 119 } else { 120 debug("pageto=%d", val); 121 main_opts.pageto = val; 122 main_opts.flags |= 1 << HCID_SET_PAGETO; 123 } 124 125 str = g_key_file_get_string(config, "General", "Name", &err); 126 if (err) { 127 debug("%s", err->message); 128 g_clear_error(&err); 129 } else { 130 debug("name=%s", str); 131 g_free(main_opts.name); 132 main_opts.name = g_strdup(str); 133 main_opts.flags |= 1 << HCID_SET_NAME; 134 g_free(str); 135 } 136 137 str = g_key_file_get_string(config, "General", "Class", &err); 138 if (err) { 139 debug("%s", err->message); 140 g_clear_error(&err); 141 } else { 142 debug("class=%s", str); 143 main_opts.class = strtol(str, NULL, 16); 144 main_opts.flags |= 1 << HCID_SET_CLASS; 145 g_free(str); 146 } 147 148 val = g_key_file_get_integer(config, "General", 149 "DiscoverSchedulerInterval", &err); 150 if (err) { 151 debug("%s", err->message); 152 g_clear_error(&err); 153 } else { 154 debug("discov_interval=%d", val); 155 main_opts.discov_interval = val; 156 } 157 158 boolean = g_key_file_get_boolean(config, "General", 159 "InitiallyPowered", &err); 160 if (err) { 161 debug("%s", err->message); 162 g_clear_error(&err); 163 } else if (boolean == FALSE) 164 main_opts.mode = MODE_OFF; 165 166 boolean = g_key_file_get_boolean(config, "General", 167 "RememberPowered", &err); 168 if (err) { 169 debug("%s", err->message); 170 g_clear_error(&err); 171 } else 172 main_opts.remember_powered = boolean; 173 174 str = g_key_file_get_string(config, "General", "DeviceID", &err); 175 if (err) { 176 debug("%s", err->message); 177 g_clear_error(&err); 178 } else { 179 debug("deviceid=%s", str); 180 strncpy(main_opts.deviceid, str, 181 sizeof(main_opts.deviceid) - 1); 182 g_free(str); 183 } 184 185 boolean = g_key_file_get_boolean(config, "General", 186 "ReverseServiceDiscovery", &err); 187 if (err) { 188 debug("%s", err->message); 189 g_clear_error(&err); 190 } else 191 main_opts.reverse_sdp = boolean; 192 193 boolean = g_key_file_get_boolean(config, "General", 194 "NameResolving", &err); 195 if (err) 196 g_clear_error(&err); 197 else 198 main_opts.name_resolv = boolean; 199 200 main_opts.link_mode = HCI_LM_ACCEPT; 201 202 main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF | 203 HCI_LP_HOLD | HCI_LP_PARK; 204} 205 206static void update_service_classes(const bdaddr_t *bdaddr, uint8_t value) 207{ 208 struct hci_dev_list_req *dl; 209 struct hci_dev_req *dr; 210 int i, sk; 211 212 sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 213 if (sk < 0) 214 return; 215 216 dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); 217 218 dl->dev_num = HCI_MAX_DEV; 219 220 if (ioctl(sk, HCIGETDEVLIST, dl) < 0) { 221 close(sk); 222 g_free(dl); 223 return; 224 } 225 226 dr = dl->dev_req; 227 228 for (i = 0; i < dl->dev_num; i++, dr++) { 229 struct hci_dev_info di; 230 231 if (hci_devinfo(dr->dev_id, &di) < 0) 232 continue; 233 234 if (hci_test_bit(HCI_RAW, &di.flags)) 235 continue; 236 237 if (bacmp(bdaddr, BDADDR_ANY) != 0 && 238 bacmp(bdaddr, &di.bdaddr) != 0) 239 continue; 240 241 manager_update_adapter(di.dev_id, value); 242 } 243 244 g_free(dl); 245 246 close(sk); 247} 248 249/* 250 * Device name expansion 251 * %d - device id 252 */ 253char *expand_name(char *dst, int size, char *str, int dev_id) 254{ 255 register int sp, np, olen; 256 char *opt, buf[10]; 257 258 if (!str || !dst) 259 return NULL; 260 261 sp = np = 0; 262 while (np < size - 1 && str[sp]) { 263 switch (str[sp]) { 264 case '%': 265 opt = NULL; 266 267 switch (str[sp+1]) { 268 case 'd': 269 sprintf(buf, "%d", dev_id); 270 opt = buf; 271 break; 272 273 case 'h': 274 opt = main_opts.host_name; 275 break; 276 277 case '%': 278 dst[np++] = str[sp++]; 279 /* fall through */ 280 default: 281 sp++; 282 continue; 283 } 284 285 if (opt) { 286 /* substitute */ 287 olen = strlen(opt); 288 if (np + olen < size - 1) 289 memcpy(dst + np, opt, olen); 290 np += olen; 291 } 292 sp += 2; 293 continue; 294 295 case '\\': 296 sp++; 297 /* fall through */ 298 default: 299 dst[np++] = str[sp++]; 300 break; 301 } 302 } 303 dst[np] = '\0'; 304 return dst; 305} 306 307static void init_defaults(void) 308{ 309 /* Default HCId settings */ 310 memset(&main_opts, 0, sizeof(main_opts)); 311 main_opts.scan = SCAN_PAGE; 312 main_opts.mode = MODE_CONNECTABLE; 313 main_opts.name = g_strdup("BlueZ"); 314 main_opts.discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT; 315 main_opts.remember_powered = TRUE; 316 main_opts.reverse_sdp = TRUE; 317 main_opts.name_resolv = TRUE; 318 319 if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0) 320 strcpy(main_opts.host_name, "noname"); 321} 322 323static GMainLoop *event_loop; 324 325static void sig_term(int sig) 326{ 327 g_main_loop_quit(event_loop); 328} 329 330static void sig_debug(int sig) 331{ 332 toggle_debug(); 333} 334 335static gboolean option_detach = TRUE; 336static gboolean option_debug = FALSE; 337static gboolean option_udev = FALSE; 338 339static guint last_adapter_timeout = 0; 340 341static gboolean exit_timeout(gpointer data) 342{ 343 g_main_loop_quit(event_loop); 344 last_adapter_timeout = 0; 345 return FALSE; 346} 347 348void btd_start_exit_timer(void) 349{ 350 if (option_udev == FALSE) 351 return; 352 353 if (last_adapter_timeout > 0) 354 g_source_remove(last_adapter_timeout); 355 356 last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT, 357 exit_timeout, NULL); 358} 359 360void btd_stop_exit_timer(void) 361{ 362 if (last_adapter_timeout == 0) 363 return; 364 365 g_source_remove(last_adapter_timeout); 366 last_adapter_timeout = 0; 367} 368 369static GOptionEntry options[] = { 370 { "nodaemon", 'n', G_OPTION_FLAG_REVERSE, 371 G_OPTION_ARG_NONE, &option_detach, 372 "Don't run as daemon in background" }, 373 { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, 374 "Enable debug information output" }, 375 { "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev, 376 "Run from udev mode of operation" }, 377 { NULL }, 378}; 379 380int main(int argc, char *argv[]) 381{ 382 GOptionContext *context; 383 GError *err = NULL; 384 struct sigaction sa; 385 uint16_t mtu = 0; 386 GKeyFile *config; 387 388 init_defaults(); 389 390 context = g_option_context_new(NULL); 391 g_option_context_add_main_entries(context, options, NULL); 392 393 if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) { 394 if (err != NULL) { 395 g_printerr("%s\n", err->message); 396 g_error_free(err); 397 } else 398 g_printerr("An unknown error occurred\n"); 399 exit(1); 400 } 401 402 if (option_udev == TRUE) { 403 int err; 404 405 option_detach = TRUE; 406 err = hcid_dbus_init(); 407 if (err < 0) { 408 if (err == -EALREADY) 409 exit(0); 410 exit(1); 411 } 412 } 413 414 g_option_context_free(context); 415 416 if (option_detach == TRUE && option_udev == FALSE) { 417 if (daemon(0, 0)) { 418 perror("Can't start daemon"); 419 exit(1); 420 } 421 } 422 423 umask(0077); 424 425 start_logging("bluetoothd", "Bluetooth daemon %s", VERSION); 426 427 memset(&sa, 0, sizeof(sa)); 428 sa.sa_flags = SA_NOCLDSTOP; 429 sa.sa_handler = sig_term; 430 sigaction(SIGTERM, &sa, NULL); 431 sigaction(SIGINT, &sa, NULL); 432 433 sa.sa_handler = sig_debug; 434 sigaction(SIGUSR2, &sa, NULL); 435 436 sa.sa_handler = SIG_IGN; 437 sigaction(SIGPIPE, &sa, NULL); 438 439 if (option_debug == TRUE) { 440 info("Enabling debug information"); 441 enable_debug(); 442 } 443 444 config = load_config(CONFIGDIR "/main.conf"); 445 446 parse_config(config); 447 448 agent_init(); 449 450 if (option_udev == FALSE) { 451 if (hcid_dbus_init() < 0) { 452 error("Unable to get on D-Bus"); 453 exit(1); 454 } 455 } else { 456 if (daemon(0, 0)) { 457 perror("Can't start daemon"); 458 exit(1); 459 } 460 } 461 462 start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT); 463 set_service_classes_callback(update_service_classes); 464 465 /* Loading plugins has to be done after D-Bus has been setup since 466 * the plugins might wanna expose some paths on the bus. However the 467 * best order of how to init various subsystems of the Bluetooth 468 * daemon needs to be re-worked. */ 469 plugin_init(config); 470 471 event_loop = g_main_loop_new(NULL, FALSE); 472 473 if (adapter_ops_setup() < 0) { 474 error("adapter_ops_setup failed"); 475 exit(1); 476 } 477 478 manager_startup_complete(); 479 480 debug("Entering main loop"); 481 482 g_main_loop_run(event_loop); 483 484 hcid_dbus_unregister(); 485 486 hcid_dbus_exit(); 487 488 plugin_cleanup(); 489 490 stop_sdp_server(); 491 492 agent_exit(); 493 494 g_main_loop_unref(event_loop); 495 496 if (config) 497 g_key_file_free(config); 498 499 info("Exit"); 500 501 stop_logging(); 502 503 return 0; 504} 505