main.c revision 20ccc578c85111ca8790bd773b6fa337e80b4c71
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
43#include <glib.h>
44
45#include <dbus/dbus.h>
46
47#include <gdbus.h>
48
49#include "log.h"
50
51#include "hcid.h"
52#include "sdpd.h"
53#include "attrib-server.h"
54#include "adapter.h"
55#include "event.h"
56#include "dbus-common.h"
57#include "agent.h"
58#include "manager.h"
59
60#ifdef HAVE_CAPNG
61#include <cap-ng.h>
62#endif
63
64#define BLUEZ_NAME "org.bluez"
65
66#define LAST_ADAPTER_EXIT_TIMEOUT 30
67
68#define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
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	boolean = g_key_file_get_boolean(config, "General",
224						"EnableLE", &err);
225	if (err)
226		g_clear_error(&err);
227	else
228		main_opts.le = boolean;
229
230	main_opts.link_mode = HCI_LM_ACCEPT;
231
232	main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
233						HCI_LP_HOLD | HCI_LP_PARK;
234}
235
236static void init_defaults(void)
237{
238	/* Default HCId settings */
239	memset(&main_opts, 0, sizeof(main_opts));
240	main_opts.scan	= SCAN_PAGE;
241	main_opts.mode	= MODE_CONNECTABLE;
242	main_opts.name	= g_strdup("BlueZ");
243	main_opts.discovto	= DEFAULT_DISCOVERABLE_TIMEOUT;
244	main_opts.remember_powered = TRUE;
245	main_opts.reverse_sdp = TRUE;
246	main_opts.name_resolv = TRUE;
247
248	if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0)
249		strcpy(main_opts.host_name, "noname");
250}
251
252static GMainLoop *event_loop;
253
254static void sig_term(int sig)
255{
256	g_main_loop_quit(event_loop);
257}
258
259static void sig_debug(int sig)
260{
261	__btd_toggle_debug();
262}
263
264static gchar *option_debug = NULL;
265static gchar *option_plugin = NULL;
266static gchar *option_noplugin = NULL;
267static gboolean option_detach = TRUE;
268static gboolean option_version = FALSE;
269static gboolean option_udev = FALSE;
270
271static guint last_adapter_timeout = 0;
272
273static gboolean exit_timeout(gpointer data)
274{
275	g_main_loop_quit(event_loop);
276	last_adapter_timeout = 0;
277	return FALSE;
278}
279
280void btd_start_exit_timer(void)
281{
282	if (option_udev == FALSE)
283		return;
284
285	if (last_adapter_timeout > 0)
286		g_source_remove(last_adapter_timeout);
287
288	last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT,
289						exit_timeout, NULL);
290}
291
292void btd_stop_exit_timer(void)
293{
294	if (last_adapter_timeout == 0)
295		return;
296
297	g_source_remove(last_adapter_timeout);
298	last_adapter_timeout = 0;
299}
300
301static void disconnect_dbus(void)
302{
303	DBusConnection *conn = get_dbus_connection();
304
305	if (!conn || !dbus_connection_get_is_connected(conn))
306		return;
307
308	manager_cleanup(conn, "/");
309
310	set_dbus_connection(NULL);
311
312	dbus_connection_unref(conn);
313}
314
315static int connect_dbus(void)
316{
317	DBusConnection *conn;
318	DBusError err;
319
320	dbus_error_init(&err);
321
322	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err);
323	if (!conn) {
324		if (dbus_error_is_set(&err)) {
325			dbus_error_free(&err);
326			return -EIO;
327		}
328		return -EALREADY;
329	}
330
331	if (!manager_init(conn, "/"))
332		return -EIO;
333
334	set_dbus_connection(conn);
335
336	return 0;
337}
338
339static gboolean parse_debug(const char *key, const char *value,
340				gpointer user_data, GError **error)
341{
342	if (value)
343		option_debug = g_strdup(value);
344	else
345		option_debug = g_strdup("*");
346
347	return TRUE;
348}
349
350static GOptionEntry options[] = {
351	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
352				G_OPTION_ARG_CALLBACK, parse_debug,
353				"Specify debug options to enable", "DEBUG" },
354	{ "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
355				"Specify plugins to load", "NAME,..," },
356	{ "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
357				"Specify plugins not to load", "NAME,..." },
358	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
359				G_OPTION_ARG_NONE, &option_detach,
360				"Don't run as daemon in background" },
361	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
362				"Show version information and exit" },
363	{ "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev,
364				"Run from udev mode of operation" },
365	{ NULL },
366};
367
368int main(int argc, char *argv[])
369{
370	GOptionContext *context;
371	GError *err = NULL;
372	struct sigaction sa;
373	uint16_t mtu = 0;
374	GKeyFile *config;
375
376	init_defaults();
377
378#ifdef HAVE_CAPNG
379	/* Drop capabilities */
380	capng_clear(CAPNG_SELECT_BOTH);
381	capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
382					CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
383						CAP_NET_RAW, CAP_IPC_LOCK, -1);
384	capng_apply(CAPNG_SELECT_BOTH);
385#endif
386
387	context = g_option_context_new(NULL);
388	g_option_context_add_main_entries(context, options, NULL);
389
390	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
391		if (err != NULL) {
392			g_printerr("%s\n", err->message);
393			g_error_free(err);
394		} else
395			g_printerr("An unknown error occurred\n");
396		exit(1);
397	}
398
399	g_option_context_free(context);
400
401	if (option_version == TRUE) {
402		printf("%s\n", VERSION);
403		exit(0);
404	}
405
406	if (option_udev == TRUE) {
407		int err;
408
409		option_detach = TRUE;
410		err = connect_dbus();
411		if (err < 0) {
412			if (err == -EALREADY)
413				exit(0);
414			exit(1);
415		}
416	}
417
418	if (option_detach == TRUE && option_udev == FALSE) {
419		if (daemon(0, 0)) {
420			perror("Can't start daemon");
421			exit(1);
422		}
423	}
424
425	umask(0077);
426
427	__btd_log_init(option_debug, option_detach);
428
429	memset(&sa, 0, sizeof(sa));
430	sa.sa_flags = SA_NOCLDSTOP;
431	sa.sa_handler = sig_term;
432	sigaction(SIGTERM, &sa, NULL);
433	sigaction(SIGINT,  &sa, NULL);
434
435	sa.sa_handler = sig_debug;
436	sigaction(SIGUSR2, &sa, NULL);
437
438	sa.sa_handler = SIG_IGN;
439	sigaction(SIGPIPE, &sa, NULL);
440
441	config = load_config(CONFIGDIR "/main.conf");
442
443	parse_config(config);
444
445	agent_init();
446
447	if (option_udev == FALSE) {
448		if (connect_dbus() < 0) {
449			error("Unable to get on D-Bus");
450			exit(1);
451		}
452	} else {
453		if (daemon(0, 0)) {
454			perror("Can't start daemon");
455			exit(1);
456		}
457	}
458
459	start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);
460
461	if (main_opts.attrib_server) {
462		if (attrib_server_init() < 0)
463			error("Can't initialize attribute server");
464	}
465
466	/* Loading plugins has to be done after D-Bus has been setup since
467	 * the plugins might wanna expose some paths on the bus. However the
468	 * best order of how to init various subsystems of the Bluetooth
469	 * daemon needs to be re-worked. */
470	plugin_init(config, option_plugin, option_noplugin);
471
472	event_loop = g_main_loop_new(NULL, FALSE);
473
474	if (adapter_ops_setup() < 0) {
475		error("adapter_ops_setup failed");
476		exit(1);
477	}
478
479	rfkill_init();
480
481	DBG("Entering main loop");
482
483	g_main_loop_run(event_loop);
484
485	disconnect_dbus();
486
487	rfkill_exit();
488
489	plugin_cleanup();
490
491	if (main_opts.attrib_server)
492		attrib_server_exit();
493
494	stop_sdp_server();
495
496	agent_exit();
497
498	g_main_loop_unref(event_loop);
499
500	if (config)
501		g_key_file_free(config);
502
503	info("Exit");
504
505	__btd_log_cleanup();
506
507	return 0;
508}
509