Beispiel #1
0
/*
 * main
 *
 */
int
main (int argc, char *argv[])
{
	gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE;
	gboolean success = FALSE;
	NMConfig *config;
	GError *error = NULL;
	gboolean wrote_pidfile = FALSE;
	char *bad_domains = NULL;
	NMConfigCmdLineOptions *config_cli;

	nm_g_type_init ();

	/* Known to cause a possible deadlock upon GDBus initialization:
	 * https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
	g_type_ensure (G_TYPE_SOCKET);
	g_type_ensure (G_TYPE_DBUS_CONNECTION);
	g_type_ensure (NM_TYPE_BUS_MANAGER);

	_nm_utils_is_manager_process = TRUE;

	main_loop = g_main_loop_new (NULL, FALSE);

	config_cli = nm_config_cmd_line_options_new ();
	do_early_setup (&argc, &argv, config_cli);

	if (global_opt.g_fatal_warnings)
		_set_g_fatal_warnings ();

	if (global_opt.show_version) {
		fprintf (stdout, NM_DIST_VERSION "\n");
		exit (0);
	}

	nm_main_utils_ensure_root ();

	nm_main_utils_ensure_not_running_pidfile (global_opt.pidfile);

	/* Ensure state directory exists */
	if (g_mkdir_with_parents (NMSTATEDIR, 0755) != 0) {
		fprintf (stderr, "Cannot create '%s': %s", NMSTATEDIR, strerror (errno));
		exit (1);
	}

	nm_main_utils_ensure_rundir ();

	/* When running from the build directory, determine our build directory
	 * base and set helper paths in the build tree */
	if (global_opt.run_from_build_dir) {
		char *path, *slash;
		int g;

		/* exe is <basedir>/src/.libs/lt-NetworkManager, so chop off
		 * the last three components */
		path = realpath ("/proc/self/exe", NULL);
		g_assert (path != NULL);
		for (g = 0; g < 3; ++g) {
			slash = strrchr (path, '/');
			g_assert (slash != NULL);
			*slash = '\0';
		}

		/* don't free these strings, we need them for the entire
		 * process lifetime */
		nm_dhcp_helper_path = g_strdup_printf ("%s/src/dhcp-manager/nm-dhcp-helper", path);

		g_free (path);
	}

	if (!nm_logging_setup (global_opt.opt_log_level,
	                       global_opt.opt_log_domains,
	                       &bad_domains,
	                       &error)) {
		fprintf (stderr,
		         _("%s.  Please use --help to see a list of valid options.\n"),
		         error->message);
		exit (1);
	} else if (bad_domains) {
		fprintf (stderr,
		         _("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
		         bad_domains);
		g_clear_pointer (&bad_domains, g_free);
	}

	/* Read the config file and CLI overrides */
	config = nm_config_setup (config_cli, NULL, &error);
	nm_config_cmd_line_options_free (config_cli);
	config_cli = NULL;
	if (config == NULL) {
		fprintf (stderr, _("Failed to read configuration: (%d) %s\n"),
		         error ? error->code : -1,
		         (error && error->message) ? error->message : _("unknown"));
		exit (1);
	}

	_init_nm_debug (nm_config_get_debug (config));

	/* Initialize logging from config file *only* if not explicitly
	 * specified by commandline.
	 */
	if (global_opt.opt_log_level == NULL && global_opt.opt_log_domains == NULL) {
		if (!nm_logging_setup (nm_config_get_log_level (config),
		                       nm_config_get_log_domains (config),
		                       &bad_domains,
		                       &error)) {
			fprintf (stderr, _("Error in configuration file: %s.\n"),
			         error->message);
			exit (1);
		} else if (bad_domains) {
			fprintf (stderr,
			         _("Ignoring unrecognized log domain(s) '%s' from config files.\n"),
			         bad_domains);
			g_clear_pointer (&bad_domains, g_free);
		}
	}

	if (global_opt.become_daemon && !nm_config_get_is_debug (config)) {
		if (daemon (0, 0) < 0) {
			int saved_errno;

			saved_errno = errno;
			fprintf (stderr, _("Could not daemonize: %s [error %u]\n"),
			         g_strerror (saved_errno),
			         saved_errno);
			exit (1);
		}
		wrote_pidfile = nm_main_utils_write_pidfile (global_opt.pidfile);
	}

	/* Set up unix signal handling - before creating threads, but after daemonizing! */
	nm_main_utils_setup_signals (main_loop);

	nm_logging_syslog_openlog (nm_config_get_is_debug (config)
	                           ? "debug"
	                           : nm_config_data_get_value_cached (NM_CONFIG_GET_DATA_ORIG,
	                                                              NM_CONFIG_KEYFILE_GROUP_LOGGING,
	                                                              NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
	                                                              NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY));

	nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");

	/* Parse the state file */
	if (!parse_state_file (global_opt.state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &error)) {
		nm_log_err (LOGD_CORE, "State file %s parsing failed: (%d) %s",
		            global_opt.state_file,
		            error ? error->code : -1,
		            (error && error->message) ? error->message : _("unknown"));
		/* Not a hard failure */
	}
	g_clear_error (&error);

	nm_log_info (LOGD_CORE, "Read config: %s", nm_config_data_get_config_description (nm_config_get_data (config)));
	nm_config_data_log (nm_config_get_data (config), "CONFIG: ");
	nm_log_dbg (LOGD_CORE, "WEXT support is %s",
#if HAVE_WEXT
	             "enabled"
#else
	             "disabled"
#endif
	             );

	nm_auth_manager_setup (nm_config_get_auth_polkit (config));

	nm_manager_setup (global_opt.state_file,
	                  net_enabled,
	                  wifi_enabled,
	                  wwan_enabled);

	if (!nm_bus_manager_get_connection (nm_bus_manager_get ())) {
		nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available");
	} else {
		/* Start our DBus service */
		if (!nm_bus_manager_start_service (nm_bus_manager_get ())) {
			nm_log_err (LOGD_CORE, "failed to start the dbus service.");
			goto done;
		}
	}

	/* Set up platform interaction layer */
	nm_linux_platform_setup ();

	NM_UTILS_KEEP_ALIVE (config, NM_PLATFORM_GET, "NMConfig-depends-on-NMPlatform");

	nm_dispatcher_init ();

	g_signal_connect (nm_manager_get (), NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);

	if (!nm_manager_start (nm_manager_get (), &error)) {
		nm_log_err (LOGD_CORE, "failed to initialize: %s", error->message);
		goto done;
	}

	/* Make sure the loopback interface is up. If interface is down, we bring
	 * it up and kernel will assign it link-local IPv4 and IPv6 addresses. If
	 * it was already up, we assume is in clean state.
	 *
	 * TODO: it might be desirable to check the list of addresses and compare
	 * it with a list of expected addresses (one of the protocol families
	 * could be disabled). The 'lo' interface is sometimes used for assigning
	 * global addresses so their availability doesn't depend on the state of
	 * physical interfaces.
	 */
	nm_log_dbg (LOGD_CORE, "setting up local loopback");
	nm_platform_link_set_up (NM_PLATFORM_GET, 1, NULL);

	success = TRUE;

	if (configure_and_quit == FALSE)
		g_main_loop_run (main_loop);

	nm_manager_stop (nm_manager_get ());

done:
	if (global_opt.pidfile && wrote_pidfile)
		unlink (global_opt.pidfile);

	nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
	exit (success ? 0 : 1);
}
static void
start_dnsmasq (NMDnsDnsmasq *self)
{
	NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self);
	const char *dm_binary;
	const char *argv[15];
	GPid pid = 0;
	guint idx = 0;
	NMBusManager *dbus_mgr;
	GDBusConnection *connection;

	if (priv->running) {
		/* the dnsmasq process is running. Nothing to do. */
		return;
	}

	if (nm_dns_plugin_child_pid ((NMDnsPlugin *) self) > 0) {
		/* if we already have a child process spawned, don't do
		 * it again. */
		return;
	}

	dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, NULL);
	if (!dm_binary) {
		_LOGW ("could not find dnsmasq binary");
		return;
	}

	argv[idx++] = dm_binary;
	argv[idx++] = "--no-resolv";  /* Use only commandline */
	argv[idx++] = "--keep-in-foreground";
	argv[idx++] = "--no-hosts"; /* don't use /etc/hosts to resolve */
	argv[idx++] = "--bind-interfaces";
	argv[idx++] = "--pid-file=" PIDFILE;
	argv[idx++] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */
	argv[idx++] = "--cache-size=400";
	argv[idx++] = "--conf-file=/dev/null"; /* avoid loading /etc/dnsmasq.conf */
	argv[idx++] = "--proxy-dnssec"; /* Allow DNSSEC to pass through */
	argv[idx++] = "--enable-dbus=" DNSMASQ_DBUS_SERVICE;

	/* dnsmasq exits if the conf dir is not present */
	if (g_file_test (CONFDIR, G_FILE_TEST_IS_DIR))
		argv[idx++] = "--conf-dir=" CONFDIR;

	argv[idx++] = NULL;
	nm_assert (idx <= G_N_ELEMENTS (argv));

	/* And finally spawn dnsmasq */
	pid = nm_dns_plugin_child_spawn (NM_DNS_PLUGIN (self), argv, PIDFILE, "bin/dnsmasq");
	if (!pid)
		return;

	if (   priv->dnsmasq
	    || priv->dnsmasq_cancellable) {
		/* we already have a proxy or are about to create it.
		 * We are done. */
		return;
	}

	dbus_mgr = nm_bus_manager_get ();
	g_return_if_fail (dbus_mgr);

	connection = nm_bus_manager_get_connection (dbus_mgr);
	g_return_if_fail (connection);

	priv->dnsmasq_cancellable = g_cancellable_new ();
	g_dbus_proxy_new (connection,
	                  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
	                  NULL,
	                  DNSMASQ_DBUS_SERVICE,
	                  DNSMASQ_DBUS_PATH,
	                  DNSMASQ_DBUS_SERVICE,
	                  priv->dnsmasq_cancellable,
	                  dnsmasq_proxy_cb,
	                  self);
}