Commit c263f535 authored by Lubomir Rintel's avatar Lubomir Rintel 🥕
Browse files

config: add --configure-and-quit=initrd mode

We need a mode that:

* doesn't leave processes behind
* doesn't force an internal dhclient
* doesn't auto-generate default connections
* doesn't write out files into libdir, only /run

The original configure-and-quit mode doesn't really fit the initrd use. But
it's proobably not a good idea to just change its behavior.
parent e03d9ad1
......@@ -41,6 +41,7 @@
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "nm-config.h"
#include "nm-dhcp-dhclient-utils.h"
#include "nm-dhcp-manager.h"
#include "NetworkManagerUtils.h"
......@@ -120,8 +121,20 @@ get_dhclient_leasefile (int addr_family,
const char *uuid,
char **out_preferred_path)
{
char *rundir_path;
char *path;
/* First, see if the lease file is in /run */
rundir_path = g_strdup_printf (NMRUNDIR "/dhclient%s-%s-%s.lease",
_addr_family_to_path_part (addr_family),
uuid,
iface);
if (g_file_test (rundir_path, G_FILE_TEST_EXISTS)) {
NM_SET_OUT (out_preferred_path, g_strdup (rundir_path));
return rundir_path;
}
/* /var/lib/NetworkManager is the preferred leasefile path */
path = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s-%s.lease",
_addr_family_to_path_part (addr_family),
......@@ -133,6 +146,12 @@ get_dhclient_leasefile (int addr_family,
return path;
}
if (nm_config_get_configure_and_quit (nm_config_get ()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) {
g_free (path);
path = rundir_path;
} else {
g_free (rundir_path);
}
NM_SET_OUT (out_preferred_path, g_steal_pointer (&path));
/* If the leasefile we're looking for doesn't exist yet in the new location
......
......@@ -413,7 +413,7 @@ nm_dhcp_manager_init (NMDhcpManager *self)
NM_CONFIG_KEYFILE_KEY_MAIN_DHCP,
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
client = client_free;
if (nm_config_get_configure_and_quit (config)) {
if (nm_config_get_configure_and_quit (config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) {
client_factory = &_nm_dhcp_client_factory_internal;
if (client && !nm_streq (client, client_factory->name))
nm_log_info (LOGD_DHCP, "dhcp-init: Using internal DHCP client since configure-and-quit is set.");
......
......@@ -32,6 +32,7 @@
#include "nm-utils/unaligned.h"
#include "nm-utils.h"
#include "nm-config.h"
#include "nm-dhcp-utils.h"
#include "NetworkManagerUtils.h"
#include "platform/nm-platform.h"
......@@ -453,10 +454,30 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
static char *
get_leasefile_path (int addr_family, const char *iface, const char *uuid)
{
return g_strdup_printf (NMSTATEDIR "/internal%s-%s-%s.lease",
addr_family == AF_INET6 ? "6" : "",
uuid,
iface);
char *rundir_path;
char *statedir_path;
rundir_path = g_strdup_printf (NMRUNDIR "/internal%s-%s-%s.lease",
addr_family == AF_INET6 ? "6" : "",
uuid,
iface);
if (g_file_test (rundir_path, G_FILE_TEST_EXISTS))
return rundir_path;
statedir_path = g_strdup_printf (NMSTATEDIR "/internal%s-%s-%s.lease",
addr_family == AF_INET6 ? "6" : "",
uuid,
iface);
if ( g_file_test (statedir_path, G_FILE_TEST_EXISTS)
|| nm_config_get_configure_and_quit (nm_config_get ()) != NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) {
g_free (rundir_path);
return statedir_path;
} else {
g_free (statedir_path);
return rundir_path;
}
}
/*****************************************************************************/
......
......@@ -51,7 +51,8 @@ struct NMConfigCmdLineOptions {
char *state_file;
char *no_auto_default_file;
char *plugins;
gboolean configure_and_quit;
NMConfigConfigureAndQuitType configure_and_quit;
gboolean is_debug;
char *connectivity_uri;
......@@ -105,7 +106,7 @@ typedef struct {
char *log_level;
char *log_domains;
gboolean configure_and_quit;
NMConfigConfigureAndQuitType configure_and_quit;
char **atomic_section_prefixes;
......@@ -323,7 +324,7 @@ nm_config_get_log_domains (NMConfig *config)
return NM_CONFIG_GET_PRIVATE (config)->log_domains;
}
gboolean
NMConfigConfigureAndQuitType
nm_config_get_configure_and_quit (NMConfig *config)
{
return NM_CONFIG_GET_PRIVATE (config)->configure_and_quit;
......@@ -392,9 +393,16 @@ no_auto_default_to_file (const char *no_auto_default_file, const char *const*no_
gboolean
nm_config_get_no_auto_default_for_device (NMConfig *self, NMDevice *device)
{
NMConfigPrivate *priv;
g_return_val_if_fail (NM_IS_CONFIG (self), FALSE);
return nm_config_data_get_no_auto_default_for_device (NM_CONFIG_GET_PRIVATE (self)->config_data, device);
priv = NM_CONFIG_GET_PRIVATE (self);
if (priv->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD)
return TRUE;
return nm_config_data_get_no_auto_default_for_device (priv->config_data, device);
}
void
......@@ -457,7 +465,7 @@ _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli)
g_clear_pointer (&cli->intern_config_file, g_free);
g_clear_pointer (&cli->state_file, g_free);
g_clear_pointer (&cli->plugins, g_free);
cli->configure_and_quit = FALSE;
cli->configure_and_quit = NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED;
cli->is_debug = FALSE;
g_clear_pointer (&cli->connectivity_uri, g_free);
g_clear_pointer (&cli->connectivity_response, g_free);
......@@ -509,34 +517,72 @@ nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli)
g_free (cli);
}
static NMConfigConfigureAndQuitType
string_to_configure_and_quit (const char *value, GError **error)
{
NMConfigConfigureAndQuitType ret;
if (value == NULL)
return NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED;
if (strcmp (value, "initrd") == 0)
return NM_CONFIG_CONFIGURE_AND_QUIT_INITRD;
ret = nm_config_parse_boolean (value, NM_CONFIG_CONFIGURE_AND_QUIT_INVALID);
if (ret == NM_CONFIG_CONFIGURE_AND_QUIT_INVALID)
g_set_error (error, 1, 0, N_("'%s' is not valid"), value);
return ret;
}
static gboolean
parse_configure_and_quit (const char *option_name, const char *value, gpointer user_data, GError **error)
{
NMConfigCmdLineOptions *cli = user_data;
if (value == NULL)
cli->configure_and_quit = NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED;
else
cli->configure_and_quit = string_to_configure_and_quit (value, error);
if (cli->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_INVALID) {
g_prefix_error (error, N_("Bad '%s' option: "), option_name);
return FALSE;
}
return TRUE;
}
void
nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
GOptionContext *opt_ctx)
{
GOptionGroup *group;
GOptionEntry config_options[] = {
{ "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), DEFAULT_CONFIG_MAIN_FILE },
{ "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), DEFAULT_CONFIG_DIR },
{ "system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), DEFAULT_SYSTEM_CONFIG_DIR },
{ "intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), DEFAULT_INTERN_CONFIG_FILE },
{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &cli->state_file, N_("State file location"), DEFAULT_STATE_FILE },
{ "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), DEFAULT_NO_AUTO_DEFAULT_FILE },
{ "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), NM_CONFIG_DEFAULT_MAIN_PLUGINS },
{ "configure-and-quit", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_configure_and_quit, N_("Quit after initial configuration"), NULL },
{ "debug", 'd', 0, G_OPTION_ARG_NONE, &cli->is_debug, N_("Don't become a daemon, and log to stderr"), NULL },
/* These three are hidden for now, and should eventually just go away. */
{ "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
{ "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), G_STRINGIFY (NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL) },
{ "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE },
{ 0 },
};
g_return_if_fail (opt_ctx);
g_return_if_fail (cli);
{
GOptionEntry config_options[] = {
{ "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), DEFAULT_CONFIG_MAIN_FILE },
{ "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), DEFAULT_CONFIG_DIR },
{ "system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), DEFAULT_SYSTEM_CONFIG_DIR },
{ "intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), DEFAULT_INTERN_CONFIG_FILE },
{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &cli->state_file, N_("State file location"), DEFAULT_STATE_FILE },
{ "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), DEFAULT_NO_AUTO_DEFAULT_FILE },
{ "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), NM_CONFIG_DEFAULT_MAIN_PLUGINS },
{ "configure-and-quit", 0, 0, G_OPTION_ARG_NONE, &cli->configure_and_quit, N_("Quit after initial configuration"), NULL },
{ "debug", 'd', 0, G_OPTION_ARG_NONE, &cli->is_debug, N_("Don't become a daemon, and log to stderr"), NULL },
/* These three are hidden for now, and should eventually just go away. */
{ "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
{ "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), G_STRINGIFY (NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL) },
{ "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE },
{ 0 },
};
group = g_option_group_new ("nm", N_("NetworkManager options" ), N_("Show NetworkManager options"), cli, NULL);
g_option_context_add_main_entries (opt_ctx, config_options, NULL);
}
g_option_group_add_entries (group, config_options);
g_option_context_add_group (opt_ctx, group);
}
/*****************************************************************************/
......@@ -1046,19 +1092,36 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
/* Merge settings from command line. They overwrite everything read from
* config files. */
if (cli && cli->plugins) {
/* plugins is a string list. Set the value directly, so the user has to do proper escaping
* on the command line. */
g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", cli->plugins);
}
if (cli && cli->configure_and_quit)
g_key_file_set_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", TRUE);
if (cli && cli->connectivity_uri && cli->connectivity_uri[0])
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", cli->connectivity_uri);
if (cli && cli->connectivity_interval >= 0)
g_key_file_set_integer (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", cli->connectivity_interval);
if (cli && cli->connectivity_response && cli->connectivity_response[0])
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", cli->connectivity_response);
if (cli) {
if (cli->plugins) {
/* plugins is a string list. Set the value directly, so the user has to do proper escaping
* on the command line. */
g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", cli->plugins);
}
switch (cli->configure_and_quit) {
case NM_CONFIG_CONFIGURE_AND_QUIT_INVALID:
g_assert_not_reached ();
break;
case NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED:
/* do nothing */
break;
case NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED:
g_key_file_set_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", TRUE);
break;
case NM_CONFIG_CONFIGURE_AND_QUIT_INITRD:
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", "initrd");
break;
}
if (cli->connectivity_uri && cli->connectivity_uri[0])
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", cli->connectivity_uri);
if (cli->connectivity_interval >= 0)
g_key_file_set_integer (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", cli->connectivity_interval);
if (cli->connectivity_response && cli->connectivity_response[0])
g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", cli->connectivity_response);
}
if (out_config_description) {
GString *str;
......@@ -1837,6 +1900,9 @@ state_write (NMConfig *self)
GString *str;
GError *error = NULL;
if (priv->configure_and_quit != NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED)
return;
filename = state_get_filename (&priv->cli);
if (!filename) {
......@@ -2495,6 +2561,7 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
char *config_main_file = NULL;
char *config_description = NULL;
gs_strfreev char **no_auto_default = NULL;
gs_free char *configure_and_quit = NULL;
gboolean intern_config_needs_rewrite;
const char *s;
......@@ -2541,7 +2608,10 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
priv->log_level = nm_strstrip (g_key_file_get_string (keyfile, NM_CONFIG_KEYFILE_GROUP_LOGGING, "level", NULL));
priv->log_domains = nm_strstrip (g_key_file_get_string (keyfile, NM_CONFIG_KEYFILE_GROUP_LOGGING, "domains", NULL));
priv->configure_and_quit = nm_config_keyfile_get_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", FALSE);
configure_and_quit = nm_strstrip (g_key_file_get_string (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", NULL));
priv->configure_and_quit = string_to_configure_and_quit (configure_and_quit, error);
if (priv->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_INVALID)
return FALSE;
no_auto_default = no_auto_default_from_file (priv->no_auto_default_file);
......@@ -2549,7 +2619,8 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
keyfile,
(const char *const*) priv->atomic_section_prefixes,
&intern_config_needs_rewrite);
if (intern_config_needs_rewrite) {
if ( intern_config_needs_rewrite
&& priv->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED) {
intern_config_write (priv->intern_config_file, keyfile_intern, keyfile,
(const char *const*) priv->atomic_section_prefixes, NULL);
}
......
......@@ -101,6 +101,13 @@ typedef enum {
NM_CONFIG_STATE_PROPERTY_WWAN_ENABLED,
} NMConfigRunStatePropertyType;
typedef enum {
NM_CONFIG_CONFIGURE_AND_QUIT_INVALID = -1,
NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED = FALSE,
NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED = TRUE,
NM_CONFIG_CONFIGURE_AND_QUIT_INITRD,
} NMConfigConfigureAndQuitType;
typedef struct {
bool net_enabled;
bool wifi_enabled;
......@@ -127,7 +134,7 @@ NMConfigData *nm_config_get_data_orig (NMConfig *config);
gboolean nm_config_get_monitor_connection_files (NMConfig *config);
const char *nm_config_get_log_level (NMConfig *config);
const char *nm_config_get_log_domains (NMConfig *config);
gboolean nm_config_get_configure_and_quit (NMConfig *config);
NMConfigConfigureAndQuitType nm_config_get_configure_and_quit (NMConfig *config);
gboolean nm_config_get_is_debug (NMConfig *config);
gboolean nm_config_get_first_start (NMConfig *config);
......
......@@ -627,10 +627,10 @@ nm_config_data_get_value (const NMConfigData *config_data, const char *group, co
return NULL;
}
gboolean
NMConfigConfigureAndQuitType
nm_config_get_configure_and_quit (NMConfig *config)
{
return TRUE;
return NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED;
}
NMDBusManager *
......
......@@ -1632,7 +1632,7 @@ remove_device (NMManager *self,
nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_REMOVED);
nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_PLATFORM_INIT, TRUE, NM_DEVICE_STATE_REASON_REMOVED);
}
} else if (quitting && nm_config_get_configure_and_quit (priv->config)) {
} else if (quitting && nm_config_get_configure_and_quit (priv->config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) {
nm_device_spawn_iface_helper (device);
}
}
......
......@@ -2510,6 +2510,8 @@ nm_settings_connection_update_timestamp (NMSettingsConnection *self,
if (flush_to_disk == FALSE)
return;
if (nm_config_get_configure_and_quit (nm_config_get ()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD)
return;
/* Save timestamp to timestamps database file */
timestamps_file = g_key_file_new ();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment