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