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