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