int main(int argc, char *argv[])
{
	int exit_status;
	struct l_dbus *dbus;
	const char *config_dir;
	char **config_dirs;
	int i;

	for (;;) {
		int opt;

		opt = getopt_long(argc, argv, "Ei:I:p:P:d::vhl:",
							main_options, NULL);
		if (opt < 0)
			break;

		switch (opt) {
		case 'E':
			developeropt = true;
			break;
		case 'i':
			interfaces = optarg;
			break;
		case 'I':
			nointerfaces = optarg;
			break;
		case 'p':
			phys = optarg;
			break;
		case 'P':
			nophys = optarg;
			break;
		case 'd':
			if (optarg)
				debugopt = optarg;
			else if (argv[optind] && argv[optind][0] != '-')
				debugopt = argv[optind++];
			else
				debugopt = "*";
			break;
		case 'l':
			logger = optarg;
			break;
		case 'v':
			printf("%s\n", VERSION);
			return EXIT_SUCCESS;
		case 'h':
			usage();
			return EXIT_SUCCESS;
		default:
			return EXIT_FAILURE;
		}
	}

	if (argc - optind > 0) {
		fprintf(stderr, "Invalid command line parameters\n");
		return EXIT_FAILURE;
	}

	if (logger && !strcmp(logger, "syslog"))
		l_log_set_syslog();
	else if (logger && !strcmp(logger, "journal"))
		l_log_set_journal();
	else
		l_log_set_stderr();

	l_log_set_ident("iwd");

	if (check_crypto() < 0)
		return EXIT_FAILURE;

	if (!l_main_init())
		return EXIT_FAILURE;

	if (debugopt)
		l_debug_enable(debugopt);

#ifdef HAVE_BACKTRACE
	__iwd_backtrace_init();
#endif

	l_info("Wireless daemon version %s", VERSION);

	config_dir = getenv("CONFIGURATION_DIRECTORY");
	if (!config_dir)
		config_dir = DAEMON_CONFIGDIR;

	l_debug("Using configuration directory %s", config_dir);

	iwd_config = l_settings_new();

	config_dirs = l_strsplit(config_dir, ':');

	for (i = 0; config_dirs[i]; i++) {
		L_AUTO_FREE_VAR(char *, path) =
			l_strdup_printf("%s/%s", config_dirs[i], "main.conf");

		if (!l_settings_load_from_file(iwd_config, path))
			continue;

		l_info("Loaded configuration from %s", path);
		break;
	}

	l_strv_free(config_dirs);

	__eapol_set_config(iwd_config);
	__eap_set_config(iwd_config);

	exit_status = EXIT_FAILURE;

	if (!storage_create_dirs())
		goto failed_dirs;

	genl = l_genl_new();
	if (!genl) {
		l_error("Failed to open generic netlink socket");
		goto failed_genl;
	}

	if (getenv("IWD_GENL_DEBUG"))
		l_genl_set_debug(genl, do_debug, "[GENL] ", NULL);

	rtnl = l_netlink_new(NETLINK_ROUTE);
	if (!rtnl) {
		l_error("Failed to open route netlink socket");
		goto failed_rtnl;
	}

	if (getenv("IWD_RTNL_DEBUG"))
		l_netlink_set_debug(rtnl, do_debug, "[RTNL] ", NULL);

	dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
	if (!dbus) {
		l_error("Failed to initialize D-Bus");
		goto failed_dbus;
	}

	l_dbus_set_ready_handler(dbus, dbus_ready, dbus, NULL);
	l_dbus_set_disconnect_handler(dbus, dbus_disconnected, NULL, NULL);
	dbus_init(dbus);

	if (!setup_system_key())
		goto failed_storage;

	exit_status = l_main_run_with_signal(signal_handler, NULL);

	iwd_modules_exit();
	storage_exit();

failed_storage:
	dbus_exit();
	l_dbus_destroy(dbus);

failed_dbus:
	l_netlink_destroy(rtnl);

failed_rtnl:
	l_genl_unref(genl);

failed_genl:
	storage_cleanup_dirs();

failed_dirs:
	l_settings_free(iwd_config);
	l_timeout_remove(timeout);
	l_main_exit();

	return exit_status;
}
