diff --git a/src/NetworkManager.c b/src/NetworkManager.c index f14c6cbf07..bb697c1ad5 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -56,6 +56,7 @@ #define NM_DEFAULT_PID_FILE LOCALSTATEDIR"/run/NetworkManager.pid" #define NM_DEFAULT_SYSTEM_CONF_FILE SYSCONFDIR"/NetworkManager/nm-system-settings.conf" +#define NM_DEFAULT_SYSTEM_STATE_FILE LOCALSTATEDIR"/lib/NetworkManager/NetworkManager.state" /* * Globals @@ -269,6 +270,94 @@ parse_config_file (const char *filename, char **plugins, GError **error) return TRUE; } +static gboolean +parse_state_file (const char *filename, + gboolean *net_enabled, + gboolean *wifi_enabled, + GError **error) +{ + GKeyFile *state_file; + GError *tmp_error = NULL; + gboolean wifi, net; + + g_return_val_if_fail (net_enabled != NULL, FALSE); + g_return_val_if_fail (wifi_enabled != NULL, FALSE); + + state_file = g_key_file_new (); + if (!state_file) { + g_set_error (error, 0, 0, + "Not enough memory to load state file."); + return FALSE; + } + + g_key_file_set_list_separator (state_file, ','); + if (!g_key_file_load_from_file (state_file, filename, G_KEY_FILE_KEEP_COMMENTS, &tmp_error)) { + /* This is kinda ugly; create the file and directory if it doesn't + * exist yet. We can't rely on distros necessarily creating the + * /var/lib/NetworkManager for us since we have to ensure that + * users upgrading NM get this working too. + */ + if ( tmp_error->domain == G_FILE_ERROR + && tmp_error->code == G_FILE_ERROR_NOENT) { + char *data, *dirname; + gsize len = 0; + gboolean ret = FALSE; + + /* try to create the directory if it doesn't exist */ + dirname = g_path_get_dirname (filename); + errno = 0; + if (mkdir (dirname, 0755) != 0) { + if (errno != EEXIST) { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES, + "Error creating state directory %s: %d", dirname, errno); + g_free (dirname); + return FALSE; + } + } + g_free (dirname); + + /* Write out the initial state to the state file */ + g_key_file_set_boolean (state_file, "main", "NetworkingEnabled", *net_enabled); + g_key_file_set_boolean (state_file, "main", "WirelessEnabled", *wifi_enabled); + + data = g_key_file_to_data (state_file, &len, NULL); + if (data) + ret = g_file_set_contents (filename, data, len, error); + g_free (data); + + return ret; + } else { + g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message); + g_clear_error (&tmp_error); + } + + /* Otherwise, file probably corrupt or inaccessible */ + return FALSE; + } + + /* Reading state bits of NetworkManager; an error leaves the passed-in state + * value unchanged. + */ + net = g_key_file_get_boolean (state_file, "main", "NetworkingEnabled", &tmp_error); + if (tmp_error) + g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message); + else + *net_enabled = net; + g_clear_error (&tmp_error); + + wifi = g_key_file_get_boolean (state_file, "main", "WirelessEnabled", error); + if (tmp_error) { + g_clear_error (error); + g_set_error_literal (error, tmp_error->domain, tmp_error->code, tmp_error->message); + } else + *wifi_enabled = wifi; + g_clear_error (&tmp_error); + + g_key_file_free (state_file); + + return TRUE; +} + /* * main * @@ -281,6 +370,8 @@ main (int argc, char *argv[]) gboolean g_fatal_warnings = FALSE; char *pidfile = NULL, *user_pidfile = NULL; char *config = NULL, *plugins = NULL; + char *state_file = NM_DEFAULT_SYSTEM_STATE_FILE; + gboolean wifi_enabled = TRUE, net_enabled = TRUE; gboolean success; NMPolicy *policy = NULL; NMVPNManager *vpn_manager = NULL; @@ -294,6 +385,7 @@ main (int argc, char *argv[]) { "no-daemon", 0, 0, G_OPTION_ARG_NONE, &become_daemon, "Don't become a daemon", NULL }, { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL }, { "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &user_pidfile, "Specify the location of a PID file", "filename" }, + { "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, "State file location", "/path/to/state.file" }, { "config", 0, 0, G_OPTION_ARG_FILENAME, &config, "Config file location", "/path/to/config.file" }, { "plugins", 0, 0, G_OPTION_ARG_STRING, &plugins, "List of plugins separated by ,", "plugin1,plugin2" }, {NULL} @@ -352,6 +444,17 @@ main (int argc, char *argv[]) } } + g_clear_error (&error); + + /* Parse the state file */ + if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &error)) { + g_warning ("State file %s parsing failed: (%d) %s.", + state_file, + error ? error->code : -1, + (error && error->message) ? error->message : "unknown"); + /* Not a hard failure */ + } + pidfile = g_strdup (user_pidfile ? user_pidfile : NM_DEFAULT_PID_FILE); /* Tricky: become_daemon is FALSE by default, so unless it's TRUE because @@ -419,7 +522,7 @@ main (int argc, char *argv[]) goto done; } - manager = nm_manager_get (config, plugins, &error); + manager = nm_manager_get (config, plugins, state_file, net_enabled, wifi_enabled, &error); if (manager == NULL) { nm_error ("Failed to initialize the network manager: %s", error && error->message ? error->message : "(unknown)"); diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c index 743f47cdf7..2eef45b216 100644 --- a/src/nm-device-olpc-mesh.c +++ b/src/nm-device-olpc-mesh.c @@ -909,7 +909,7 @@ check_companion_cb (gpointer user_data) if (priv->device_added_cb != 0) return FALSE; - manager = nm_manager_get (NULL, NULL, NULL); + manager = nm_manager_get (NULL, NULL, NULL, FALSE, FALSE, NULL); priv->device_added_cb = g_signal_connect (manager, "device-added", G_CALLBACK (device_added_cb), self); diff --git a/src/nm-manager.c b/src/nm-manager.c index e082ab0f5d..d13d674cca 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -149,6 +149,7 @@ typedef struct { typedef struct { char *config_file; + char *state_file; GSList *devices; NMState state; @@ -1100,11 +1101,62 @@ nm_manager_name_owner_changed (NMDBusManager *mgr, } } +/* Store value into key-file; supported types: boolean, int, string */ +static gboolean +write_value_to_state_file (const char *filename, + const char *group, + const char *key, + GType value_type, + gpointer value, + GError **error) +{ + GKeyFile *key_file; + char *data; + gsize len = 0; + gboolean ret = FALSE; + + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (group != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value_type == G_TYPE_BOOLEAN || + value_type == G_TYPE_INT || + value_type == G_TYPE_STRING, + FALSE); + + key_file = g_key_file_new (); + if (!key_file) + return FALSE; + + g_key_file_set_list_separator (key_file, ','); + g_key_file_load_from_file (key_file, filename, G_KEY_FILE_KEEP_COMMENTS, NULL); + switch (value_type) { + case G_TYPE_BOOLEAN: + g_key_file_set_boolean (key_file, group, key, *((gboolean *) value)); + break; + case G_TYPE_INT: + g_key_file_set_integer (key_file, group, key, *((gint *) value)); + break; + case G_TYPE_STRING: + g_key_file_set_string (key_file, group, key, *((const gchar **) value)); + break; + } + + data = g_key_file_to_data (key_file, &len, NULL); + if (data) { + ret = g_file_set_contents (filename, data, len, error); + g_free (data); + } + g_key_file_free (key_file); + + return ret; +} + static void manager_set_wireless_enabled (NMManager *manager, gboolean enabled) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); GSList *iter; + GError *error = NULL; if (priv->wireless_enabled == enabled) return; @@ -1117,6 +1169,19 @@ manager_set_wireless_enabled (NMManager *manager, gboolean enabled) g_object_notify (G_OBJECT (manager), NM_MANAGER_WIRELESS_ENABLED); + /* Update "WirelessEnabled" key in state file */ + if (priv->state_file) { + if (!write_value_to_state_file (priv->state_file, + "main", "WirelessEnabled", + G_TYPE_BOOLEAN, (gpointer) &priv->wireless_enabled, + &error)) { + g_warning ("Writing to state file %s failed: (%d) %s.", + priv->state_file, + error ? error->code : -1, + (error && error->message) ? error->message : "unknown"); + } + } + /* Don't touch devices if asleep/networking disabled */ if (priv->sleeping) return; @@ -2399,6 +2464,23 @@ impl_manager_sleep (NMManager *self, gboolean sleep, GError **error) priv->sleeping = sleep; + /* Update "NetworkingEnabled" key in state file */ + if (priv->state_file) { + GError *err = NULL; + gboolean networking_enabled = !sleep; + + if (!write_value_to_state_file (priv->state_file, + "main", "NetworkingEnabled", + G_TYPE_BOOLEAN, (gpointer) &networking_enabled, + &err)) { + g_warning ("Writing to state file %s failed: (%d) %s.", + priv->state_file, + err ? err->code : -1, + (err && err->message) ? err->message : "unknown"); + } + + } + if (sleep) { nm_info ("Sleeping..."); @@ -2569,9 +2651,10 @@ nm_manager_start (NMManager *self) break; } - nm_info ("Wireless now %s by radio killswitch", - (priv->wireless_hw_enabled && we) ? "enabled" : "disabled"); - manager_set_wireless_enabled (self, we); + nm_info ("Wireless %s by radio killswitch; %s by state file", + (priv->wireless_hw_enabled && we) ? "enabled" : "disabled", + (priv->wireless_enabled) ? "enabled" : "disabled"); + manager_set_wireless_enabled (self, priv->wireless_enabled && we); system_unmanaged_devices_changed_cb (priv->sys_settings, NULL, self); system_hostname_changed_cb (priv->sys_settings, NULL, self); @@ -2589,7 +2672,12 @@ nm_manager_start (NMManager *self) } NMManager * -nm_manager_get (const char *config_file, const char *plugins, GError **error) +nm_manager_get (const char *config_file, + const char *plugins, + const char *state_file, + gboolean initial_net_enabled, + gboolean initial_wifi_enabled, + GError **error) { static NMManager *singleton = NULL; NMManagerPrivate *priv; @@ -2615,6 +2703,12 @@ nm_manager_get (const char *config_file, const char *plugins, GError **error) priv->config_file = g_strdup (config_file); + priv->state_file = g_strdup (state_file); + + priv->sleeping = !initial_net_enabled; + + priv->wireless_enabled = initial_wifi_enabled; + g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS, G_CALLBACK (system_unmanaged_devices_changed_cb), singleton); g_signal_connect (priv->sys_settings, "notify::" NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME, diff --git a/src/nm-manager.h b/src/nm-manager.h index 8e48574e65..a17323d42f 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -74,7 +74,12 @@ typedef struct { GType nm_manager_get_type (void); -NMManager *nm_manager_get (const char *config_file, const char *plugins, GError **error); +NMManager *nm_manager_get (const char *config_file, + const char *plugins, + const char *state_file, + gboolean initial_net_enabled, + gboolean initial_wifi_enabled, + GError **error); void nm_manager_start (NMManager *manager);