main.c revision b757bc94cb7be06a6ae1931dcc917c62f962566e
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#ifdef HAVE_CAPNG 60#include <cap-ng.h> 61#endif 62 63#define LAST_ADAPTER_EXIT_TIMEOUT 30 64 65struct main_opts main_opts; 66 67static GKeyFile *load_config(const char *file) 68{ 69 GError *err = NULL; 70 GKeyFile *keyfile; 71 72 keyfile = g_key_file_new(); 73 74 g_key_file_set_list_separator(keyfile, ','); 75 76 if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { 77 error("Parsing %s failed: %s", file, err->message); 78 g_error_free(err); 79 g_key_file_free(keyfile); 80 return NULL; 81 } 82 83 return keyfile; 84} 85 86static void parse_config(GKeyFile *config) 87{ 88 GError *err = NULL; 89 char *str; 90 int val; 91 gboolean boolean; 92 93 if (!config) 94 return; 95 96 debug("parsing main.conf"); 97 98 val = g_key_file_get_integer(config, "General", 99 "DiscoverableTimeout", &err); 100 if (err) { 101 debug("%s", err->message); 102 g_clear_error(&err); 103 } else { 104 debug("discovto=%d", val); 105 main_opts.discovto = val; 106 main_opts.flags |= 1 << HCID_SET_DISCOVTO; 107 } 108 109 val = g_key_file_get_integer(config, "General", 110 "PairableTimeout", &err); 111 if (err) { 112 debug("%s", err->message); 113 g_clear_error(&err); 114 } else { 115 debug("pairto=%d", val); 116 main_opts.pairto = val; 117 } 118 119 val = g_key_file_get_integer(config, "General", "PageTimeout", &err); 120 if (err) { 121 debug("%s", err->message); 122 g_clear_error(&err); 123 } else { 124 debug("pageto=%d", val); 125 main_opts.pageto = val; 126 main_opts.flags |= 1 << HCID_SET_PAGETO; 127 } 128 129 str = g_key_file_get_string(config, "General", "Name", &err); 130 if (err) { 131 debug("%s", err->message); 132 g_clear_error(&err); 133 } else { 134 debug("name=%s", str); 135 g_free(main_opts.name); 136 main_opts.name = g_strdup(str); 137 main_opts.flags |= 1 << HCID_SET_NAME; 138 g_free(str); 139 } 140 141 str = g_key_file_get_string(config, "General", "Class", &err); 142 if (err) { 143 debug("%s", err->message); 144 g_clear_error(&err); 145 } else { 146 debug("class=%s", str); 147 main_opts.class = strtol(str, NULL, 16); 148 main_opts.flags |= 1 << HCID_SET_CLASS; 149 g_free(str); 150 } 151 152 val = g_key_file_get_integer(config, "General", 153 "DiscoverSchedulerInterval", &err); 154 if (err) { 155 debug("%s", err->message); 156 g_clear_error(&err); 157 } else { 158 debug("discov_interval=%d", val); 159 main_opts.discov_interval = val; 160 } 161 162 boolean = g_key_file_get_boolean(config, "General", 163 "InitiallyPowered", &err); 164 if (err) { 165 debug("%s", err->message); 166 g_clear_error(&err); 167 } else if (boolean == FALSE) 168 main_opts.mode = MODE_OFF; 169 170 boolean = g_key_file_get_boolean(config, "General", 171 "RememberPowered", &err); 172 if (err) { 173 debug("%s", err->message); 174 g_clear_error(&err); 175 } else 176 main_opts.remember_powered = boolean; 177 178 str = g_key_file_get_string(config, "General", "DeviceID", &err); 179 if (err) { 180 debug("%s", err->message); 181 g_clear_error(&err); 182 } else { 183 debug("deviceid=%s", str); 184 strncpy(main_opts.deviceid, str, 185 sizeof(main_opts.deviceid) - 1); 186 g_free(str); 187 } 188 189 boolean = g_key_file_get_boolean(config, "General", 190 "ReverseServiceDiscovery", &err); 191 if (err) { 192 debug("%s", err->message); 193 g_clear_error(&err); 194 } else 195 main_opts.reverse_sdp = boolean; 196 197 boolean = g_key_file_get_boolean(config, "General", 198 "NameResolving", &err); 199 if (err) 200 g_clear_error(&err); 201 else 202 main_opts.name_resolv = boolean; 203 204 main_opts.link_mode = HCI_LM_ACCEPT; 205 206 main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF | 207 HCI_LP_HOLD | HCI_LP_PARK; 208} 209 210/* 211 * Device name expansion 212 * %d - device id 213 */ 214char *expand_name(char *dst, int size, char *str, int dev_id) 215{ 216 register int sp, np, olen; 217 char *opt, buf[10]; 218 219 if (!str || !dst) 220 return NULL; 221 222 sp = np = 0; 223 while (np < size - 1 && str[sp]) { 224 switch (str[sp]) { 225 case '%': 226 opt = NULL; 227 228 switch (str[sp+1]) { 229 case 'd': 230 sprintf(buf, "%d", dev_id); 231 opt = buf; 232 break; 233 234 case 'h': 235 opt = main_opts.host_name; 236 break; 237 238 case '%': 239 dst[np++] = str[sp++]; 240 /* fall through */ 241 default: 242 sp++; 243 continue; 244 } 245 246 if (opt) { 247 /* substitute */ 248 olen = strlen(opt); 249 if (np + olen < size - 1) 250 memcpy(dst + np, opt, olen); 251 np += olen; 252 } 253 sp += 2; 254 continue; 255 256 case '\\': 257 sp++; 258 /* fall through */ 259 default: 260 dst[np++] = str[sp++]; 261 break; 262 } 263 } 264 dst[np] = '\0'; 265 return dst; 266} 267 268static void init_defaults(void) 269{ 270 /* Default HCId settings */ 271 memset(&main_opts, 0, sizeof(main_opts)); 272 main_opts.scan = SCAN_PAGE; 273 main_opts.mode = MODE_CONNECTABLE; 274 main_opts.name = g_strdup("BlueZ"); 275 main_opts.discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT; 276 main_opts.remember_powered = TRUE; 277 main_opts.reverse_sdp = TRUE; 278 main_opts.name_resolv = TRUE; 279 280 if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0) 281 strcpy(main_opts.host_name, "noname"); 282} 283 284static GMainLoop *event_loop; 285 286static void sig_term(int sig) 287{ 288 g_main_loop_quit(event_loop); 289} 290 291static void sig_debug(int sig) 292{ 293 toggle_debug(); 294} 295 296static gboolean option_detach = TRUE; 297static gboolean option_debug = FALSE; 298static gboolean option_udev = FALSE; 299 300static guint last_adapter_timeout = 0; 301 302static gboolean exit_timeout(gpointer data) 303{ 304 g_main_loop_quit(event_loop); 305 last_adapter_timeout = 0; 306 return FALSE; 307} 308 309void btd_start_exit_timer(void) 310{ 311 if (option_udev == FALSE) 312 return; 313 314 if (last_adapter_timeout > 0) 315 g_source_remove(last_adapter_timeout); 316 317 last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT, 318 exit_timeout, NULL); 319} 320 321void btd_stop_exit_timer(void) 322{ 323 if (last_adapter_timeout == 0) 324 return; 325 326 g_source_remove(last_adapter_timeout); 327 last_adapter_timeout = 0; 328} 329 330static GOptionEntry options[] = { 331 { "nodaemon", 'n', G_OPTION_FLAG_REVERSE, 332 G_OPTION_ARG_NONE, &option_detach, 333 "Don't run as daemon in background" }, 334 { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, 335 "Enable debug information output" }, 336 { "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev, 337 "Run from udev mode of operation" }, 338 { NULL }, 339}; 340 341int main(int argc, char *argv[]) 342{ 343 GOptionContext *context; 344 GError *err = NULL; 345 struct sigaction sa; 346 uint16_t mtu = 0; 347 GKeyFile *config; 348 349 init_defaults(); 350 351#ifdef HAVE_CAPNG 352 /* Drop capabilities */ 353 capng_clear(CAPNG_SELECT_BOTH); 354 capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, 355 CAP_NET_BIND_SERVICE, CAP_NET_ADMIN, 356 CAP_NET_RAW, CAP_IPC_LOCK, -1); 357 capng_apply(CAPNG_SELECT_BOTH); 358#endif 359 360 context = g_option_context_new(NULL); 361 g_option_context_add_main_entries(context, options, NULL); 362 363 if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) { 364 if (err != NULL) { 365 g_printerr("%s\n", err->message); 366 g_error_free(err); 367 } else 368 g_printerr("An unknown error occurred\n"); 369 exit(1); 370 } 371 372 if (option_udev == TRUE) { 373 int err; 374 375 option_detach = TRUE; 376 err = hcid_dbus_init(); 377 if (err < 0) { 378 if (err == -EALREADY) 379 exit(0); 380 exit(1); 381 } 382 } 383 384 g_option_context_free(context); 385 386 if (option_detach == TRUE && option_udev == FALSE) { 387 if (daemon(0, 0)) { 388 perror("Can't start daemon"); 389 exit(1); 390 } 391 } 392 393 umask(0077); 394 395 start_logging("bluetoothd", "Bluetooth daemon %s", VERSION); 396 397 memset(&sa, 0, sizeof(sa)); 398 sa.sa_flags = SA_NOCLDSTOP; 399 sa.sa_handler = sig_term; 400 sigaction(SIGTERM, &sa, NULL); 401 sigaction(SIGINT, &sa, NULL); 402 403 sa.sa_handler = sig_debug; 404 sigaction(SIGUSR2, &sa, NULL); 405 406 sa.sa_handler = SIG_IGN; 407 sigaction(SIGPIPE, &sa, NULL); 408 409 if (option_debug == TRUE) { 410 info("Enabling debug information"); 411 enable_debug(); 412 } 413 414 config = load_config(CONFIGDIR "/main.conf"); 415 416 parse_config(config); 417 418 agent_init(); 419 420 if (option_udev == FALSE) { 421 if (hcid_dbus_init() < 0) { 422 error("Unable to get on D-Bus"); 423 exit(1); 424 } 425 } else { 426 if (daemon(0, 0)) { 427 perror("Can't start daemon"); 428 exit(1); 429 } 430 } 431 432 start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT); 433 434 /* Loading plugins has to be done after D-Bus has been setup since 435 * the plugins might wanna expose some paths on the bus. However the 436 * best order of how to init various subsystems of the Bluetooth 437 * daemon needs to be re-worked. */ 438 plugin_init(config); 439 440 event_loop = g_main_loop_new(NULL, FALSE); 441 442 if (adapter_ops_setup() < 0) { 443 error("adapter_ops_setup failed"); 444 exit(1); 445 } 446 447 rfkill_init(); 448 449 debug("Entering main loop"); 450 451 g_main_loop_run(event_loop); 452 453 hcid_dbus_unregister(); 454 455 hcid_dbus_exit(); 456 457 rfkill_exit(); 458 459 plugin_cleanup(); 460 461 stop_sdp_server(); 462 463 agent_exit(); 464 465 g_main_loop_unref(event_loop); 466 467 if (config) 468 g_key_file_free(config); 469 470 info("Exit"); 471 472 stop_logging(); 473 474 return 0; 475} 476