mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-30 00:20:11 +01:00
core: preserve wifi and networking enabled/disabled states (bgo #582447)
With modifications by dcbw to create the state file if it doesn't exist, and a couple cleanups and formatting fixes.
This commit is contained in:
parent
df32cfbfd8
commit
dccdf5e1f3
4 changed files with 209 additions and 7 deletions
|
|
@ -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)");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
102
src/nm-manager.c
102
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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue