Blame src/main.c

Packit 34410b
/*
Packit 34410b
 *
Packit 34410b
 *  BlueZ - Bluetooth protocol stack for Linux
Packit 34410b
 *
Packit 34410b
 *  Copyright (C) 2000-2001  Qualcomm Incorporated
Packit 34410b
 *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
Packit 34410b
 *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
Packit 34410b
 *
Packit 34410b
 *
Packit 34410b
 *  This program is free software; you can redistribute it and/or modify
Packit 34410b
 *  it under the terms of the GNU General Public License as published by
Packit 34410b
 *  the Free Software Foundation; either version 2 of the License, or
Packit 34410b
 *  (at your option) any later version.
Packit 34410b
 *
Packit 34410b
 *  This program is distributed in the hope that it will be useful,
Packit 34410b
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 34410b
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 34410b
 *  GNU General Public License for more details.
Packit 34410b
 *
Packit 34410b
 *  You should have received a copy of the GNU General Public License
Packit 34410b
 *  along with this program; if not, write to the Free Software
Packit 34410b
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 34410b
 *
Packit 34410b
 */
Packit 34410b
Packit 34410b
#ifdef HAVE_CONFIG_H
Packit 34410b
#include <config.h>
Packit 34410b
#endif
Packit 34410b
Packit 34410b
#define _GNU_SOURCE
Packit 34410b
#include <errno.h>
Packit 34410b
#include <stdio.h>
Packit 34410b
#include <unistd.h>
Packit 34410b
#include <stdlib.h>
Packit 34410b
#include <string.h>
Packit 34410b
#include <signal.h>
Packit 34410b
#include <stdbool.h>
Packit 34410b
#include <sys/signalfd.h>
Packit 34410b
#include <sys/types.h>
Packit 34410b
#include <sys/stat.h>
Packit 34410b
Packit 34410b
#include <glib.h>
Packit 34410b
Packit 34410b
#include <dbus/dbus.h>
Packit 34410b
Packit 34410b
#include "lib/bluetooth.h"
Packit 34410b
#include "lib/sdp.h"
Packit 34410b
Packit 34410b
#include "gdbus/gdbus.h"
Packit 34410b
Packit 34410b
#include "log.h"
Packit 34410b
#include "backtrace.h"
Packit 34410b
Packit 34410b
#include "shared/att-types.h"
Packit 34410b
#include "shared/mainloop.h"
Packit 34410b
#include "lib/uuid.h"
Packit 34410b
#include "hcid.h"
Packit 34410b
#include "sdpd.h"
Packit 34410b
#include "adapter.h"
Packit 34410b
#include "device.h"
Packit 34410b
#include "dbus-common.h"
Packit 34410b
#include "agent.h"
Packit 34410b
#include "profile.h"
Packit 34410b
Packit 34410b
#define BLUEZ_NAME "org.bluez"
Packit 34410b
Packit 34410b
#define DEFAULT_PAIRABLE_TIMEOUT       0 /* disabled */
Packit 34410b
#define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
Packit 34410b
Packit 34410b
#define SHUTDOWN_GRACE_SECONDS 10
Packit 34410b
Packit 34410b
struct main_opts main_opts;
Packit 34410b
static GKeyFile *main_conf;
Packit 34410b
static char *main_conf_file_path;
Packit 34410b
Packit 34410b
static enum {
Packit 34410b
	MPS_OFF,
Packit 34410b
	MPS_SINGLE,
Packit 34410b
	MPS_MULTIPLE,
Packit 34410b
} mps = MPS_OFF;
Packit 34410b
Packit 34410b
static const char *supported_options[] = {
Packit 34410b
	"Name",
Packit 34410b
	"Class",
Packit 34410b
	"DiscoverableTimeout",
Packit 34410b
	"AlwaysPairable"
Packit 34410b
	"PairableTimeout",
Packit 34410b
	"DeviceID",
Packit 34410b
	"ReverseServiceDiscovery",
Packit 34410b
	"NameResolving",
Packit 34410b
	"DebugKeys",
Packit 34410b
	"ControllerMode",
Packit 34410b
	"MultiProfile",
Packit 34410b
	"FastConnectable",
Packit 34410b
	"Privacy",
Packit 34410b
	NULL
Packit 34410b
};
Packit 34410b
Packit 34410b
static const char *policy_options[] = {
Packit 34410b
	"ReconnectUUIDs",
Packit 34410b
	"ReconnectAttempts",
Packit 34410b
	"ReconnectIntervals",
Packit 34410b
	"AutoEnable",
Packit 34410b
	NULL
Packit 34410b
};
Packit 34410b
Packit 34410b
static const char *gatt_options[] = {
Packit 34410b
	"Cache",
Packit 34410b
	"KeySize",
Packit 34410b
	"ExchangeMTU",
Packit 34410b
	NULL
Packit 34410b
};
Packit 34410b
Packit 34410b
static const struct group_table {
Packit 34410b
	const char *name;
Packit 34410b
	const char **options;
Packit 34410b
} valid_groups[] = {
Packit 34410b
	{ "General",	supported_options },
Packit 34410b
	{ "Policy",	policy_options },
Packit 34410b
	{ "GATT",	gatt_options },
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
Packit 34410b
GKeyFile *btd_get_main_conf(void)
Packit 34410b
{
Packit 34410b
	return main_conf;
Packit 34410b
}
Packit 34410b
Packit 34410b
static GKeyFile *load_config(const char *file)
Packit 34410b
{
Packit 34410b
	GError *err = NULL;
Packit 34410b
	GKeyFile *keyfile;
Packit 34410b
Packit 34410b
	keyfile = g_key_file_new();
Packit 34410b
Packit 34410b
	g_key_file_set_list_separator(keyfile, ',');
Packit 34410b
Packit 34410b
	if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
Packit 34410b
		if (!g_error_matches(err, G_FILE_ERROR, G_FILE_ERROR_NOENT))
Packit 34410b
			error("Parsing %s failed: %s", file, err->message);
Packit 34410b
		g_error_free(err);
Packit 34410b
		g_key_file_free(keyfile);
Packit 34410b
		return NULL;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return keyfile;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void parse_did(const char *did)
Packit 34410b
{
Packit 34410b
	int result;
Packit 34410b
	uint16_t vendor, product, version , source;
Packit 34410b
Packit 34410b
	/* version and source are optional */
Packit 34410b
	version = 0x0000;
Packit 34410b
	source = 0x0002;
Packit 34410b
Packit 34410b
	result = sscanf(did, "bluetooth:%4hx:%4hx:%4hx",
Packit 34410b
					&vendor, &product, &version);
Packit 34410b
	if (result != EOF && result >= 2) {
Packit 34410b
		source = 0x0001;
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	result = sscanf(did, "usb:%4hx:%4hx:%4hx",
Packit 34410b
					&vendor, &product, &version);
Packit 34410b
	if (result != EOF && result >= 2)
Packit 34410b
		goto done;
Packit 34410b
Packit 34410b
	result = sscanf(did, "%4hx:%4hx:%4hx", &vendor, &product, &version);
Packit 34410b
	if (result == EOF || result < 2)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
done:
Packit 34410b
	main_opts.did_source = source;
Packit 34410b
	main_opts.did_vendor = vendor;
Packit 34410b
	main_opts.did_product = product;
Packit 34410b
	main_opts.did_version = version;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bt_gatt_cache_t parse_gatt_cache(const char *cache)
Packit 34410b
{
Packit 34410b
	if (!strcmp(cache, "always")) {
Packit 34410b
		return BT_GATT_CACHE_ALWAYS;
Packit 34410b
	} else if (!strcmp(cache, "yes")) {
Packit 34410b
		return BT_GATT_CACHE_YES;
Packit 34410b
	} else if (!strcmp(cache, "no")) {
Packit 34410b
		return BT_GATT_CACHE_NO;
Packit 34410b
	} else {
Packit 34410b
		DBG("Invalid value for KeepCache=%s", cache);
Packit 34410b
		return BT_GATT_CACHE_ALWAYS;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void check_options(GKeyFile *config, const char *group,
Packit 34410b
						const char **options)
Packit 34410b
{
Packit 34410b
	char **keys;
Packit 34410b
	int i;
Packit 34410b
Packit 34410b
	keys = g_key_file_get_keys(config, group, NULL, NULL);
Packit 34410b
Packit 34410b
	for (i = 0; keys != NULL && keys[i] != NULL; i++) {
Packit 34410b
		bool found;
Packit 34410b
		unsigned int j;
Packit 34410b
Packit 34410b
		found = false;
Packit 34410b
		for (j = 0; options != NULL && options[j] != NULL; j++) {
Packit 34410b
			if (g_str_equal(keys[i], options[j])) {
Packit 34410b
				found = true;
Packit 34410b
				break;
Packit 34410b
			}
Packit 34410b
		}
Packit 34410b
Packit 34410b
		if (!found)
Packit 34410b
			warn("Unknown key %s for group %s in %s",
Packit 34410b
					keys[i], group, main_conf_file_path);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	g_strfreev(keys);
Packit 34410b
}
Packit 34410b
Packit 34410b
static void check_config(GKeyFile *config)
Packit 34410b
{
Packit 34410b
	char **keys;
Packit 34410b
	int i;
Packit 34410b
	const struct group_table *group;
Packit 34410b
Packit 34410b
	if (!config)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	keys = g_key_file_get_groups(config, NULL);
Packit 34410b
Packit 34410b
	for (i = 0; keys != NULL && keys[i] != NULL; i++) {
Packit 34410b
		bool match = false;
Packit 34410b
Packit 34410b
		for (group = valid_groups; group && group->name ; group++) {
Packit 34410b
			if (g_str_equal(keys[i], group->name)) {
Packit 34410b
				match = true;
Packit 34410b
				break;
Packit 34410b
			}
Packit 34410b
		}
Packit 34410b
Packit 34410b
		if (!match)
Packit 34410b
			warn("Unknown group %s in %s", keys[i],
Packit 34410b
						main_conf_file_path);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	g_strfreev(keys);
Packit 34410b
Packit 34410b
	for (group = valid_groups; group && group->name; group++)
Packit 34410b
		check_options(config, group->name, group->options);
Packit 34410b
}
Packit 34410b
Packit 34410b
static int get_mode(const char *str)
Packit 34410b
{
Packit 34410b
	if (strcmp(str, "dual") == 0)
Packit 34410b
		return BT_MODE_DUAL;
Packit 34410b
	else if (strcmp(str, "bredr") == 0)
Packit 34410b
		return BT_MODE_BREDR;
Packit 34410b
	else if (strcmp(str, "le") == 0)
Packit 34410b
		return BT_MODE_LE;
Packit 34410b
Packit 34410b
	error("Unknown controller mode \"%s\"", str);
Packit 34410b
Packit 34410b
	return BT_MODE_DUAL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void parse_config(GKeyFile *config)
Packit 34410b
{
Packit 34410b
	GError *err = NULL;
Packit 34410b
	char *str;
Packit 34410b
	int val;
Packit 34410b
	gboolean boolean;
Packit 34410b
Packit 34410b
	if (!config)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	check_config(config);
Packit 34410b
Packit 34410b
	DBG("parsing %s", main_conf_file_path);
Packit 34410b
Packit 34410b
	val = g_key_file_get_integer(config, "General",
Packit 34410b
						"DiscoverableTimeout", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("discovto=%d", val);
Packit 34410b
		main_opts.discovto = val;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	boolean = g_key_file_get_boolean(config, "General",
Packit 34410b
						"AlwaysPairable", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("pairable=%s", boolean ? "true" : "false");
Packit 34410b
		main_opts.pairable = boolean;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	val = g_key_file_get_integer(config, "General",
Packit 34410b
						"PairableTimeout", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("pairto=%d", val);
Packit 34410b
		main_opts.pairto = val;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "General", "Privacy", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
		main_opts.privacy = 0x00;
Packit 34410b
	} else {
Packit 34410b
		DBG("privacy=%s", str);
Packit 34410b
Packit 34410b
		if (!strcmp(str, "device"))
Packit 34410b
			main_opts.privacy = 0x01;
Packit 34410b
		else if (!strcmp(str, "off"))
Packit 34410b
			main_opts.privacy = 0x00;
Packit 34410b
		else {
Packit 34410b
			DBG("Invalid privacy option: %s", str);
Packit 34410b
			main_opts.privacy = 0x00;
Packit 34410b
		}
Packit 34410b
Packit 34410b
		g_free(str);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "General", "Name", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("name=%s", str);
Packit 34410b
		g_free(main_opts.name);
Packit 34410b
		main_opts.name = str;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "General", "Class", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("class=%s", str);
Packit 34410b
		main_opts.class = strtol(str, NULL, 16);
Packit 34410b
		g_free(str);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "General", "DeviceID", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("deviceid=%s", str);
Packit 34410b
		parse_did(str);
Packit 34410b
		g_free(str);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	boolean = g_key_file_get_boolean(config, "General",
Packit 34410b
						"ReverseServiceDiscovery", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else
Packit 34410b
		main_opts.reverse_discovery = boolean;
Packit 34410b
Packit 34410b
	boolean = g_key_file_get_boolean(config, "General",
Packit 34410b
						"NameResolving", &err;;
Packit 34410b
	if (err)
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	else
Packit 34410b
		main_opts.name_resolv = boolean;
Packit 34410b
Packit 34410b
	boolean = g_key_file_get_boolean(config, "General",
Packit 34410b
						"DebugKeys", &err;;
Packit 34410b
	if (err)
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	else
Packit 34410b
		main_opts.debug_keys = boolean;
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "General", "ControllerMode", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("ControllerMode=%s", str);
Packit 34410b
		main_opts.mode = get_mode(str);
Packit 34410b
		g_free(str);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "General", "MultiProfile", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("MultiProfile=%s", str);
Packit 34410b
Packit 34410b
		if (!strcmp(str, "single"))
Packit 34410b
			mps = MPS_SINGLE;
Packit 34410b
		else if (!strcmp(str, "multiple"))
Packit 34410b
			mps = MPS_MULTIPLE;
Packit 34410b
Packit 34410b
		g_free(str);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	boolean = g_key_file_get_boolean(config, "General",
Packit 34410b
						"FastConnectable", &err;;
Packit 34410b
	if (err)
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	else
Packit 34410b
		main_opts.fast_conn = boolean;
Packit 34410b
Packit 34410b
	str = g_key_file_get_string(config, "GATT", "Cache", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		main_opts.gatt_cache = parse_gatt_cache(str);
Packit 34410b
		g_free(str);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	val = g_key_file_get_integer(config, "GATT", "KeySize", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		DBG("KeySize=%d", val);
Packit 34410b
Packit 34410b
		if (val >=7 && val <= 16)
Packit 34410b
			main_opts.key_size = val;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	val = g_key_file_get_integer(config, "GATT", "ExchangeMTU", &err;;
Packit 34410b
	if (err) {
Packit 34410b
		DBG("%s", err->message);
Packit 34410b
		g_clear_error(&err;;
Packit 34410b
	} else {
Packit 34410b
		/* Ensure the mtu is within a valid range. */
Packit 34410b
		val = MIN(val, BT_ATT_MAX_LE_MTU);
Packit 34410b
		val = MAX(val, BT_ATT_DEFAULT_LE_MTU);
Packit 34410b
		DBG("ExchangeMTU=%d", val);
Packit 34410b
		main_opts.gatt_mtu = val;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static void init_defaults(void)
Packit 34410b
{
Packit 34410b
	uint8_t major, minor;
Packit 34410b
Packit 34410b
	/* Default HCId settings */
Packit 34410b
	memset(&main_opts, 0, sizeof(main_opts));
Packit 34410b
	main_opts.name = g_strdup_printf("BlueZ %s", VERSION);
Packit 34410b
	main_opts.class = 0x000000;
Packit 34410b
	main_opts.pairto = DEFAULT_PAIRABLE_TIMEOUT;
Packit 34410b
	main_opts.discovto = DEFAULT_DISCOVERABLE_TIMEOUT;
Packit 34410b
	main_opts.reverse_discovery = TRUE;
Packit 34410b
	main_opts.name_resolv = TRUE;
Packit 34410b
	main_opts.debug_keys = FALSE;
Packit 34410b
Packit 34410b
	if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	main_opts.did_source = 0x0002;		/* USB */
Packit 34410b
	main_opts.did_vendor = 0x1d6b;		/* Linux Foundation */
Packit 34410b
	main_opts.did_product = 0x0246;		/* BlueZ */
Packit 34410b
	main_opts.did_version = (major << 8 | minor);
Packit 34410b
Packit 34410b
	main_opts.gatt_cache = BT_GATT_CACHE_ALWAYS;
Packit 34410b
	main_opts.gatt_mtu = BT_ATT_MAX_LE_MTU;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
Packit 34410b
				const gchar *message, gpointer user_data)
Packit 34410b
{
Packit 34410b
	int priority;
Packit 34410b
Packit 34410b
	if (log_level & (G_LOG_LEVEL_ERROR |
Packit 34410b
				G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING))
Packit 34410b
		priority = 0x03;
Packit 34410b
	else
Packit 34410b
		priority = 0x06;
Packit 34410b
Packit 34410b
	btd_log(0xffff, priority, "GLib: %s", message);
Packit 34410b
	btd_backtrace(0xffff);
Packit 34410b
}
Packit 34410b
Packit 34410b
void btd_exit(void)
Packit 34410b
{
Packit 34410b
	mainloop_quit();
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean quit_eventloop(gpointer user_data)
Packit 34410b
{
Packit 34410b
	btd_exit();
Packit 34410b
	return FALSE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void signal_callback(int signum, void *user_data)
Packit 34410b
{
Packit 34410b
	static bool terminated = false;
Packit 34410b
Packit 34410b
	switch (signum) {
Packit 34410b
	case SIGINT:
Packit 34410b
	case SIGTERM:
Packit 34410b
		if (!terminated) {
Packit 34410b
			info("Terminating");
Packit 34410b
			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
Packit 34410b
							quit_eventloop, NULL);
Packit 34410b
Packit 34410b
			mainloop_sd_notify("STATUS=Powering down");
Packit 34410b
			adapter_shutdown();
Packit 34410b
		}
Packit 34410b
Packit 34410b
		terminated = true;
Packit 34410b
		break;
Packit 34410b
	case SIGUSR2:
Packit 34410b
		__btd_toggle_debug();
Packit 34410b
		break;
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static char *option_debug = NULL;
Packit 34410b
static char *option_plugin = NULL;
Packit 34410b
static char *option_noplugin = NULL;
Packit 34410b
static char *option_configfile = NULL;
Packit 34410b
static gboolean option_compat = FALSE;
Packit 34410b
static gboolean option_detach = TRUE;
Packit 34410b
static gboolean option_version = FALSE;
Packit 34410b
static gboolean option_experimental = FALSE;
Packit 34410b
Packit 34410b
static void free_options(void)
Packit 34410b
{
Packit 34410b
	g_free(option_debug);
Packit 34410b
	option_debug = NULL;
Packit 34410b
Packit 34410b
	g_free(option_plugin);
Packit 34410b
	option_plugin = NULL;
Packit 34410b
Packit 34410b
	g_free(option_noplugin);
Packit 34410b
	option_noplugin = NULL;
Packit 34410b
Packit 34410b
	g_free(option_configfile);
Packit 34410b
	option_configfile = NULL;
Packit 34410b
}
Packit 34410b
Packit 34410b
static void disconnect_dbus(void)
Packit 34410b
{
Packit 34410b
	DBusConnection *conn = btd_get_dbus_connection();
Packit 34410b
Packit 34410b
	if (!conn || !dbus_connection_get_is_connected(conn))
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	g_dbus_detach_object_manager(conn);
Packit 34410b
	set_dbus_connection(NULL);
Packit 34410b
Packit 34410b
	dbus_connection_unref(conn);
Packit 34410b
}
Packit 34410b
Packit 34410b
static void disconnected_dbus(DBusConnection *conn, void *data)
Packit 34410b
{
Packit 34410b
	info("Disconnected from D-Bus. Exiting.");
Packit 34410b
	mainloop_quit();
Packit 34410b
}
Packit 34410b
Packit 34410b
static int connect_dbus(void)
Packit 34410b
{
Packit 34410b
	DBusConnection *conn;
Packit 34410b
	DBusError err;
Packit 34410b
Packit 34410b
	dbus_error_init(&err;;
Packit 34410b
Packit 34410b
	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err;;
Packit 34410b
	if (!conn) {
Packit 34410b
		if (dbus_error_is_set(&err)) {
Packit 34410b
			g_printerr("D-Bus setup failed: %s\n", err.message);
Packit 34410b
			dbus_error_free(&err;;
Packit 34410b
			return -EIO;
Packit 34410b
		}
Packit 34410b
		return -EALREADY;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	set_dbus_connection(conn);
Packit 34410b
Packit 34410b
	g_dbus_set_disconnect_function(conn, disconnected_dbus, NULL, NULL);
Packit 34410b
	g_dbus_attach_object_manager(conn);
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}
Packit 34410b
Packit 34410b
static gboolean parse_debug(const char *key, const char *value,
Packit 34410b
				gpointer user_data, GError **error)
Packit 34410b
{
Packit 34410b
	if (value)
Packit 34410b
		option_debug = g_strdup(value);
Packit 34410b
	else
Packit 34410b
		option_debug = g_strdup("*");
Packit 34410b
Packit 34410b
	return TRUE;
Packit 34410b
}
Packit 34410b
Packit 34410b
static GOptionEntry options[] = {
Packit 34410b
	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
Packit 34410b
				G_OPTION_ARG_CALLBACK, parse_debug,
Packit 34410b
				"Specify debug options to enable", "DEBUG" },
Packit 34410b
	{ "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
Packit 34410b
				"Specify plugins to load", "NAME,..," },
Packit 34410b
	{ "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
Packit 34410b
				"Specify plugins not to load", "NAME,..." },
Packit 34410b
	{ "configfile", 'f', 0, G_OPTION_ARG_STRING, &option_configfile,
Packit 34410b
			"Specify an explicit path to the config file", "FILE"},
Packit 34410b
	{ "compat", 'C', 0, G_OPTION_ARG_NONE, &option_compat,
Packit 34410b
				"Provide deprecated command line interfaces" },
Packit 34410b
	{ "experimental", 'E', 0, G_OPTION_ARG_NONE, &option_experimental,
Packit 34410b
				"Enable experimental interfaces" },
Packit 34410b
	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
Packit 34410b
				G_OPTION_ARG_NONE, &option_detach,
Packit 34410b
				"Run with logging in foreground" },
Packit 34410b
	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
Packit 34410b
				"Show version information and exit" },
Packit 34410b
	{ NULL },
Packit 34410b
};
Packit 34410b
Packit 34410b
int main(int argc, char *argv[])
Packit 34410b
{
Packit 34410b
	GOptionContext *context;
Packit 34410b
	GError *err = NULL;
Packit 34410b
	uint16_t sdp_mtu = 0;
Packit 34410b
	uint32_t sdp_flags = 0;
Packit 34410b
	int gdbus_flags = 0;
Packit 34410b
Packit 34410b
	init_defaults();
Packit 34410b
Packit 34410b
	context = g_option_context_new(NULL);
Packit 34410b
	g_option_context_add_main_entries(context, options, NULL);
Packit 34410b
Packit 34410b
	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
Packit 34410b
		if (err != NULL) {
Packit 34410b
			g_printerr("%s\n", err->message);
Packit 34410b
			g_error_free(err);
Packit 34410b
		} else
Packit 34410b
			g_printerr("An unknown error occurred\n");
Packit 34410b
		exit(1);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	g_option_context_free(context);
Packit 34410b
Packit 34410b
	if (option_version == TRUE) {
Packit 34410b
		printf("%s\n", VERSION);
Packit 34410b
		exit(0);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	umask(0077);
Packit 34410b
Packit 34410b
	btd_backtrace_init();
Packit 34410b
Packit 34410b
	mainloop_init();
Packit 34410b
Packit 34410b
	__btd_log_init(option_debug, option_detach);
Packit 34410b
Packit 34410b
	g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
Packit 34410b
							G_LOG_FLAG_RECURSION,
Packit 34410b
							log_handler, NULL);
Packit 34410b
Packit 34410b
	mainloop_sd_notify("STATUS=Starting up");
Packit 34410b
Packit 34410b
	if (option_configfile)
Packit 34410b
		main_conf_file_path = option_configfile;
Packit 34410b
	else
Packit 34410b
		main_conf_file_path = CONFIGDIR "/main.conf";
Packit 34410b
Packit 34410b
	main_conf = load_config(main_conf_file_path);
Packit 34410b
Packit 34410b
	parse_config(main_conf);
Packit 34410b
Packit 34410b
	if (connect_dbus() < 0) {
Packit 34410b
		error("Unable to get on D-Bus");
Packit 34410b
		exit(1);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (option_experimental)
Packit 34410b
		gdbus_flags = G_DBUS_FLAG_ENABLE_EXPERIMENTAL;
Packit 34410b
Packit 34410b
	g_dbus_set_flags(gdbus_flags);
Packit 34410b
Packit 34410b
	if (adapter_init() < 0) {
Packit 34410b
		error("Adapter handling initialization failed");
Packit 34410b
		exit(1);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	btd_device_init();
Packit 34410b
	btd_agent_init();
Packit 34410b
	btd_profile_init();
Packit 34410b
Packit 34410b
	if (main_opts.mode != BT_MODE_LE) {
Packit 34410b
		if (option_compat == TRUE)
Packit 34410b
			sdp_flags |= SDP_SERVER_COMPAT;
Packit 34410b
Packit 34410b
		start_sdp_server(sdp_mtu, sdp_flags);
Packit 34410b
Packit 34410b
		if (main_opts.did_source > 0)
Packit 34410b
			register_device_id(main_opts.did_source,
Packit 34410b
						main_opts.did_vendor,
Packit 34410b
						main_opts.did_product,
Packit 34410b
						main_opts.did_version);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (mps != MPS_OFF)
Packit 34410b
		register_mps(mps == MPS_MULTIPLE);
Packit 34410b
Packit 34410b
	/* Loading plugins has to be done after D-Bus has been setup since
Packit 34410b
	 * the plugins might wanna expose some paths on the bus. However the
Packit 34410b
	 * best order of how to init various subsystems of the Bluetooth
Packit 34410b
	 * daemon needs to be re-worked. */
Packit 34410b
	plugin_init(option_plugin, option_noplugin);
Packit 34410b
Packit 34410b
	/* no need to keep parsed option in memory */
Packit 34410b
	free_options();
Packit 34410b
Packit 34410b
	rfkill_init();
Packit 34410b
Packit 34410b
	DBG("Entering main loop");
Packit 34410b
Packit 34410b
	mainloop_sd_notify("STATUS=Running");
Packit 34410b
	mainloop_sd_notify("READY=1");
Packit 34410b
Packit 34410b
	mainloop_run_with_signal(signal_callback, NULL);
Packit 34410b
Packit 34410b
	mainloop_sd_notify("STATUS=Quitting");
Packit 34410b
Packit 34410b
	plugin_cleanup();
Packit 34410b
Packit 34410b
	btd_profile_cleanup();
Packit 34410b
	btd_agent_cleanup();
Packit 34410b
	btd_device_cleanup();
Packit 34410b
Packit 34410b
	adapter_cleanup();
Packit 34410b
Packit 34410b
	rfkill_exit();
Packit 34410b
Packit 34410b
	if (main_opts.mode != BT_MODE_LE)
Packit 34410b
		stop_sdp_server();
Packit 34410b
Packit 34410b
	if (main_conf)
Packit 34410b
		g_key_file_free(main_conf);
Packit 34410b
Packit 34410b
	disconnect_dbus();
Packit 34410b
Packit 34410b
	info("Exit");
Packit 34410b
Packit 34410b
	__btd_log_cleanup();
Packit 34410b
Packit 34410b
	return 0;
Packit 34410b
}