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