main.c revision 2f8164437df992cfc2e713aedbf360aafb141549
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 <stdio.h> 31#include <unistd.h> 32#include <stdlib.h> 33#include <string.h> 34#include <signal.h> 35#include <sys/stat.h> 36#include <sys/ioctl.h> 37#include <sys/socket.h> 38#include <sys/types.h> 39 40#include <bluetooth/bluetooth.h> 41#include <bluetooth/hci.h> 42#include <bluetooth/hci_lib.h> 43 44#include <glib.h> 45 46#include <dbus/dbus.h> 47 48#include "logging.h" 49 50#include "hcid.h" 51#include "sdpd.h" 52#include "adapter.h" 53#include "dbus-hci.h" 54#include "dbus-common.h" 55#include "agent.h" 56#include "manager.h" 57 58struct main_opts main_opts; 59 60static gboolean starting = TRUE; 61 62static GKeyFile *load_config(const char *file) 63{ 64 GError *err = NULL; 65 GKeyFile *keyfile; 66 67 keyfile = g_key_file_new(); 68 69 g_key_file_set_list_separator(keyfile, ','); 70 71 if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { 72 error("Parsing %s failed: %s", file, err->message); 73 g_error_free(err); 74 g_key_file_free(keyfile); 75 return NULL; 76 } 77 78 return keyfile; 79} 80 81static void parse_config(GKeyFile *config) 82{ 83 GError *err = NULL; 84 char *str; 85 int val; 86 gboolean boolean; 87 88 if (!config) 89 return; 90 91 debug("parsing main.conf"); 92 93 val = g_key_file_get_integer(config, "General", 94 "DiscoverableTimeout", &err); 95 if (err) { 96 debug("%s", err->message); 97 g_clear_error(&err); 98 } else { 99 debug("discovto=%d", val); 100 main_opts.discovto = val; 101 main_opts.flags |= 1 << HCID_SET_DISCOVTO; 102 } 103 104 val = g_key_file_get_integer(config, "General", 105 "PairableTimeout", &err); 106 if (err) { 107 debug("%s", err->message); 108 g_clear_error(&err); 109 } else { 110 debug("pairto=%d", val); 111 main_opts.pairto = val; 112 } 113 114 val = g_key_file_get_integer(config, "General", "PageTimeout", &err); 115 if (err) { 116 debug("%s", err->message); 117 g_clear_error(&err); 118 } else { 119 debug("pageto=%d", val); 120 main_opts.pageto = val; 121 main_opts.flags |= 1 << HCID_SET_PAGETO; 122 } 123 124 str = g_key_file_get_string(config, "General", "Name", &err); 125 if (err) { 126 debug("%s", err->message); 127 g_clear_error(&err); 128 } else { 129 debug("name=%s", str); 130 g_free(main_opts.name); 131 main_opts.name = g_strdup(str); 132 main_opts.flags |= 1 << HCID_SET_NAME; 133 g_free(str); 134 } 135 136 str = g_key_file_get_string(config, "General", "Class", &err); 137 if (err) { 138 debug("%s", err->message); 139 g_clear_error(&err); 140 } else { 141 debug("class=%s", str); 142 main_opts.class = strtol(str, NULL, 16); 143 main_opts.flags |= 1 << HCID_SET_CLASS; 144 g_free(str); 145 } 146 147 val = g_key_file_get_integer(config, "General", 148 "DiscoverSchedulerInterval", &err); 149 if (err) { 150 debug("%s", err->message); 151 g_clear_error(&err); 152 } else { 153 debug("inqmode=%d", val); 154 main_opts.inqmode = val; 155 } 156 157 boolean = g_key_file_get_boolean(config, "General", 158 "InitiallyPowered", &err); 159 if (err) { 160 debug("%s", err->message); 161 g_clear_error(&err); 162 } else if (boolean == FALSE) 163 main_opts.mode = MODE_OFF; 164 165 boolean = g_key_file_get_boolean(config, "General", 166 "RememberPowered", &err); 167 if (err) { 168 debug("%s", err->message); 169 g_clear_error(&err); 170 } else 171 main_opts.remember_powered = boolean; 172 173 str = g_key_file_get_string(config, "General", "DeviceID", &err); 174 if (err) { 175 debug("%s", err->message); 176 g_clear_error(&err); 177 } else { 178 debug("deviceid=%s", str); 179 strncpy(main_opts.deviceid, str, 180 sizeof(main_opts.deviceid) - 1); 181 g_free(str); 182 } 183 184 boolean = g_key_file_get_boolean(config, "General", 185 "ReverseServiceDiscovery", &err); 186 if (err) { 187 debug("%s", err->message); 188 g_clear_error(&err); 189 } else 190 main_opts.reverse_sdp = boolean; 191 192 main_opts.link_mode = HCI_LM_ACCEPT; 193 194 main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF | 195 HCI_LP_HOLD | HCI_LP_PARK; 196} 197 198static void update_service_classes(const bdaddr_t *bdaddr, uint8_t value) 199{ 200 struct hci_dev_list_req *dl; 201 struct hci_dev_req *dr; 202 int i, sk; 203 204 sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 205 if (sk < 0) 206 return; 207 208 dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); 209 210 dl->dev_num = HCI_MAX_DEV; 211 212 if (ioctl(sk, HCIGETDEVLIST, dl) < 0) { 213 close(sk); 214 g_free(dl); 215 return; 216 } 217 218 dr = dl->dev_req; 219 220 for (i = 0; i < dl->dev_num; i++, dr++) { 221 struct hci_dev_info di; 222 223 if (hci_devinfo(dr->dev_id, &di) < 0) 224 continue; 225 226 if (hci_test_bit(HCI_RAW, &di.flags)) 227 continue; 228 229 if (!hci_test_bit(HCI_UP, &di.flags)) 230 continue; 231 232 if (bacmp(bdaddr, BDADDR_ANY) != 0 && 233 bacmp(bdaddr, &di.bdaddr) != 0) 234 continue; 235 236 manager_update_adapter(di.dev_id, value, starting); 237 } 238 239 g_free(dl); 240 241 close(sk); 242} 243 244/* 245 * Device name expansion 246 * %d - device id 247 */ 248char *expand_name(char *dst, int size, char *str, int dev_id) 249{ 250 register int sp, np, olen; 251 char *opt, buf[10]; 252 253 if (!str || !dst) 254 return NULL; 255 256 sp = np = 0; 257 while (np < size - 1 && str[sp]) { 258 switch (str[sp]) { 259 case '%': 260 opt = NULL; 261 262 switch (str[sp+1]) { 263 case 'd': 264 sprintf(buf, "%d", dev_id); 265 opt = buf; 266 break; 267 268 case 'h': 269 opt = main_opts.host_name; 270 break; 271 272 case '%': 273 dst[np++] = str[sp++]; 274 /* fall through */ 275 default: 276 sp++; 277 continue; 278 } 279 280 if (opt) { 281 /* substitute */ 282 olen = strlen(opt); 283 if (np + olen < size - 1) 284 memcpy(dst + np, opt, olen); 285 np += olen; 286 } 287 sp += 2; 288 continue; 289 290 case '\\': 291 sp++; 292 /* fall through */ 293 default: 294 dst[np++] = str[sp++]; 295 break; 296 } 297 } 298 dst[np] = '\0'; 299 return dst; 300} 301 302static void init_defaults(void) 303{ 304 /* Default HCId settings */ 305 memset(&main_opts, 0, sizeof(main_opts)); 306 main_opts.scan = SCAN_PAGE; 307 main_opts.mode = MODE_CONNECTABLE; 308 main_opts.name = g_strdup("BlueZ"); 309 main_opts.discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT; 310 main_opts.remember_powered = TRUE; 311 main_opts.reverse_sdp = TRUE; 312 313 if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0) 314 strcpy(main_opts.host_name, "noname"); 315} 316 317static GMainLoop *event_loop; 318 319static void sig_term(int sig) 320{ 321 g_main_loop_quit(event_loop); 322} 323 324static void sig_debug(int sig) 325{ 326 toggle_debug(); 327} 328 329static gboolean option_detach = TRUE; 330static gboolean option_debug = FALSE; 331 332static GOptionEntry options[] = { 333 { "nodaemon", 'n', G_OPTION_FLAG_REVERSE, 334 G_OPTION_ARG_NONE, &option_detach, 335 "Don't run as daemon in background" }, 336 { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, 337 "Enable debug information output" }, 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 context = g_option_context_new(NULL); 352 g_option_context_add_main_entries(context, options, NULL); 353 354 if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) { 355 if (err != NULL) { 356 g_printerr("%s\n", err->message); 357 g_error_free(err); 358 } else 359 g_printerr("An unknown error occurred\n"); 360 exit(1); 361 } 362 363 g_option_context_free(context); 364 365 if (option_detach == TRUE) { 366 if (daemon(0, 0)) { 367 perror("Can't start daemon"); 368 exit(1); 369 } 370 } 371 372 umask(0077); 373 374 start_logging("bluetoothd", "Bluetooth daemon %s", VERSION); 375 376 memset(&sa, 0, sizeof(sa)); 377 sa.sa_flags = SA_NOCLDSTOP; 378 sa.sa_handler = sig_term; 379 sigaction(SIGTERM, &sa, NULL); 380 sigaction(SIGINT, &sa, NULL); 381 382 sa.sa_handler = sig_debug; 383 sigaction(SIGUSR2, &sa, NULL); 384 385 sa.sa_handler = SIG_IGN; 386 sigaction(SIGPIPE, &sa, NULL); 387 388 if (option_debug == TRUE) { 389 info("Enabling debug information"); 390 enable_debug(); 391 } 392 393 config = load_config(CONFIGDIR "/main.conf"); 394 395 parse_config(config); 396 397 agent_init(); 398 399 if (hcid_dbus_init() < 0) { 400 error("Unable to get on D-Bus"); 401 exit(1); 402 } 403 404 start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT); 405 set_service_classes_callback(update_service_classes); 406 407 /* Loading plugins has to be done after D-Bus has been setup since 408 * the plugins might wanna expose some paths on the bus. However the 409 * best order of how to init various subsystems of the Bluetooth 410 * daemon needs to be re-worked. */ 411 plugin_init(config); 412 413 event_loop = g_main_loop_new(NULL, FALSE); 414 415 if (adapter_ops_setup() < 0) { 416 error("adapter_ops_setup failed"); 417 exit(1); 418 } 419 420 starting = FALSE; 421 422 manager_startup_complete(); 423 424 debug("Entering main loop"); 425 426 g_main_loop_run(event_loop); 427 428 hcid_dbus_unregister(); 429 430 hcid_dbus_exit(); 431 432 plugin_cleanup(); 433 434 stop_sdp_server(); 435 436 agent_exit(); 437 438 g_main_loop_unref(event_loop); 439 440 if (config) 441 g_key_file_free(config); 442 443 info("Exit"); 444 445 stop_logging(); 446 447 return 0; 448} 449