core: merge branch 'th/main-order-bgo746254'

Some refactoring of the main() functions for NetworkManager and
nm-iface-helper. Most notably, start the D-Bus service earlier so
that NetworkManager starts faster.

https://bugzilla.gnome.org/show_bug.cgi?id=746254
This commit is contained in:
Thomas Haller
2015-03-20 11:43:40 +01:00
4 changed files with 327 additions and 258 deletions

View File

@@ -34,7 +34,9 @@
#include <glib-unix.h>
#include <gmodule.h>
#include "gsystem-local-alloc.h"
#include "main-utils.h"
#include "NetworkManagerUtils.h"
#include "nm-logging.h"
static gboolean
@@ -108,72 +110,82 @@ nm_main_utils_write_pidfile (const char *pidfile)
return success;
}
void
nm_main_utils_ensure_rundir ()
{
/* Setup runtime directory */
if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
fprintf (stderr, _("Cannot create '%s': %s"), NMRUNDIR, strerror (errno));
exit (1);
}
}
/**
* nm_main_utils_check_pidfile:
* nm_main_utils_ensure_not_running_pidfile:
* @pidfile: the pid file
* @name: the process name
*
* Checks whether the pidfile already exists and contains PID of a running
* process.
*
* Returns: %TRUE if the specified pidfile already exists and contains the PID
* of a running process named @name, or %FALSE if not
* Exits with code 1 if a conflicting process is running.
*/
gboolean
nm_main_utils_check_pidfile (const char *pidfile, const char *name)
void
nm_main_utils_ensure_not_running_pidfile (const char *pidfile)
{
char *contents = NULL;
gs_free char *contents = NULL;
gs_free char *proc_cmdline = NULL;
gsize len = 0;
glong pid;
char *proc_cmdline = NULL;
gboolean nm_running = FALSE;
const char *process_name;
const char *prgname = g_get_prgname ();
/* Setup runtime directory */
if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMRUNDIR, strerror (errno));
exit (1);
}
g_return_if_fail (prgname);
if (!pidfile || !*pidfile)
return;
if (!g_file_get_contents (pidfile, &contents, &len, NULL))
return FALSE;
return;
if (len <= 0)
goto done;
return;
errno = 0;
pid = strtol (contents, NULL, 10);
if (pid <= 0 || pid > 65536 || errno)
goto done;
return;
g_free (contents);
g_clear_pointer (&contents, g_free);
proc_cmdline = g_strdup_printf ("/proc/%ld/cmdline", pid);
if (!g_file_get_contents (proc_cmdline, &contents, &len, NULL))
goto done;
return;
process_name = strrchr (contents, '/');
if (process_name)
process_name++;
else
process_name = contents;
if (strcmp (process_name, name) == 0) {
if (strcmp (process_name, prgname) == 0) {
/* Check that the process exists */
if (kill (pid, 0) == 0) {
fprintf (stderr, _("%s is already running (pid %ld)\n"), name, pid);
nm_running = TRUE;
fprintf (stderr, _("%s is already running (pid %ld)\n"), prgname, pid);
exit (1);
}
}
}
done:
g_free (proc_cmdline);
g_free (contents);
return nm_running;
void
nm_main_utils_ensure_root ()
{
if (getuid () != 0) {
fprintf (stderr, _("You must be root to run %s!\n"), str_if_set (g_get_prgname (), ""));
exit (1);
}
}
gboolean
nm_main_utils_early_setup (const char *progname,
char **argv[],
int *argc,
char **argv[],
GOptionEntry *options,
void (*option_context_hook) (gpointer user_data, GOptionContext *opt_ctx),
gpointer option_context_hook_data,
@@ -183,6 +195,8 @@ nm_main_utils_early_setup (const char *progname,
GError *error = NULL;
gboolean success = FALSE;
int i;
const char *opt_fmt_log_level = NULL, *opt_fmt_log_domains = NULL;
const char **opt_loc_log_level = NULL, **opt_loc_log_domains = NULL;
/* Make GIO ignore the remote VFS service; otherwise it tries to use the
* session bus to contact the remote service, and NM shouldn't ever be
@@ -201,16 +215,16 @@ nm_main_utils_early_setup (const char *progname,
setlocale (LC_ALL, "");
textdomain (GETTEXT_PACKAGE);
if (getuid () != 0) {
fprintf (stderr, _("You must be root to run %s!\n"), progname);
exit (1);
}
for (i = 0; options[i].long_name; i++) {
if (!strcmp (options[i].long_name, "log-level"))
if (!strcmp (options[i].long_name, "log-level")) {
opt_fmt_log_level = options[i].description;
opt_loc_log_level = &options[i].description;
options[i].description = g_strdup_printf (options[i].description, nm_logging_all_levels_to_string ());
else if (!strcmp (options[i].long_name, "log-domains"))
} else if (!strcmp (options[i].long_name, "log-domains")) {
opt_fmt_log_domains = options[i].description;
opt_loc_log_domains = &options[i].description;
options[i].description = g_strdup_printf (options[i].description, nm_logging_all_domains_to_string ());
}
}
/* Parse options */
@@ -231,6 +245,15 @@ nm_main_utils_early_setup (const char *progname,
}
g_option_context_free (opt_ctx);
if (opt_loc_log_level) {
g_free ((char *) *opt_loc_log_level);
*opt_loc_log_level = opt_fmt_log_level;
}
if (opt_loc_log_domains) {
g_free ((char *) *opt_loc_log_domains);
*opt_loc_log_domains = opt_fmt_log_domains;
}
return success;
}

View File

@@ -23,15 +23,19 @@
#include <glib.h>
void nm_main_utils_ensure_root (void);
void nm_main_utils_setup_signals (GMainLoop *main_loop);
void nm_main_utils_ensure_rundir (void);
gboolean nm_main_utils_write_pidfile (const char *pidfile);
gboolean nm_main_utils_check_pidfile (const char *pidfile, const char *name);
void nm_main_utils_ensure_not_running_pidfile (const char *pidfile);
gboolean nm_main_utils_early_setup (const char *progname,
char **argv[],
int *argc,
char **argv[],
GOptionEntry *options,
void (*option_context_hook) (gpointer user_data, GOptionContext *opt_ctx),
gpointer option_context_hook_data,

View File

@@ -67,6 +67,20 @@
static GMainLoop *main_loop = NULL;
static gboolean configure_and_quit = FALSE;
static struct {
gboolean show_version;
gboolean become_daemon;
gboolean debug;
gboolean g_fatal_warnings;
gboolean run_from_build_dir;
char *opt_log_level;
char *opt_log_domains;
char *pidfile;
char *state_file;
} global_opt = {
.become_daemon = TRUE,
};
static gboolean
parse_state_file (const char *filename,
gboolean *net_enabled,
@@ -197,6 +211,37 @@ manager_configure_quit (NMManager *manager, gpointer user_data)
configure_and_quit = TRUE;
}
static void
do_early_setup (int *argc, char **argv[], NMConfigCmdLineOptions *config_cli)
{
GOptionEntry options[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL },
{ "debug", 'd', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL },
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" },
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains,
N_("Log domains separated by ',': any combination of [%s]"),
"PLATFORM,RFKILL,WIFI" },
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &global_opt.g_fatal_warnings, N_("Make all warnings fatal"), NULL },
{ "pid-file", 'p', 0, G_OPTION_ARG_FILENAME, &global_opt.pidfile, N_("Specify the location of a PID file"), N_("filename") },
{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &global_opt.state_file, N_("State file location"), N_("/path/to/state.file") },
{ "run-from-build-dir", 0, 0, G_OPTION_ARG_NONE, &global_opt.run_from_build_dir, "Run from build directory", NULL },
{NULL}
};
if (!nm_main_utils_early_setup ("NetworkManager",
argc,
argv,
options,
(void (*)(gpointer, GOptionContext *)) nm_config_cmd_line_options_add_to_entries,
config_cli,
_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use. It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
exit (1);
global_opt.pidfile = global_opt.pidfile ? global_opt.pidfile : g_strdup (NM_DEFAULT_PID_FILE);
global_opt.state_file = global_opt.state_file ? global_opt.state_file : g_strdup (NM_DEFAULT_SYSTEM_STATE_FILE);
}
/*
* main
*
@@ -204,75 +249,55 @@ manager_configure_quit (NMManager *manager, gpointer user_data)
int
main (int argc, char *argv[])
{
char *opt_log_level = NULL;
char *opt_log_domains = NULL;
gboolean become_daemon = TRUE, run_from_build_dir = FALSE;
gboolean debug = FALSE;
gboolean g_fatal_warnings = FALSE;
gs_free char *pidfile = NULL;
gs_free char *state_file = NULL;
gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
gboolean success, show_version = FALSE;
gboolean success = FALSE;
NMManager *manager = NULL;
gs_unref_object NMSettings *settings = NULL;
gs_unref_object NMConfig *config = NULL;
NMConfig *config;
GError *error = NULL;
gboolean wrote_pidfile = FALSE;
char *bad_domains = NULL;
NMConfigCmdLineOptions *config_cli;
GOptionEntry options[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &become_daemon, N_("Don't become a daemon"), NULL },
{ "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, N_("Don't become a daemon, and log to stderr"), NULL },
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &opt_log_level, N_("Log level: one of [%s]"), "INFO" },
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &opt_log_domains,
N_("Log domains separated by ',': any combination of [%s]"),
"PLATFORM,RFKILL,WIFI" },
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, N_("Make all warnings fatal"), NULL },
{ "pid-file", 'p', 0, G_OPTION_ARG_FILENAME, &pidfile, N_("Specify the location of a PID file"), N_("filename") },
{ "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, N_("State file location"), N_("/path/to/state.file") },
{ "run-from-build-dir", 0, 0, G_OPTION_ARG_NONE, &run_from_build_dir, "Run from build directory", NULL },
{NULL}
};
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
#endif
_nm_utils_is_manager_process = TRUE;
main_loop = g_main_loop_new (NULL, FALSE);
config_cli = nm_config_cmd_line_options_new ();
if (!nm_main_utils_early_setup ("NetworkManager",
&argv,
&argc,
options,
(void (*)(gpointer, GOptionContext *)) nm_config_cmd_line_options_add_to_entries,
config_cli,
_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use. It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
exit (1);
do_early_setup (&argc, &argv, config_cli);
if (show_version) {
if (global_opt.g_fatal_warnings) {
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
if (global_opt.show_version) {
fprintf (stdout, NM_DIST_VERSION "\n");
exit (0);
}
if (!nm_logging_setup (opt_log_level,
opt_log_domains,
&bad_domains,
&error)) {
fprintf (stderr,
_("%s. Please use --help to see a list of valid options.\n"),
error->message);
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);
} 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);
}
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 (run_from_build_dir) {
if (global_opt.run_from_build_dir) {
char *path, *slash;
int g;
@@ -294,19 +319,21 @@ main (int argc, char *argv[])
g_free (path);
}
/* Ensure state directory exists */
if (g_mkdir_with_parents (NMSTATEDIR, 0755) != 0) {
nm_log_err (LOGD_CORE, "Cannot create '%s': %s", NMSTATEDIR, strerror (errno));
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);
}
pidfile = pidfile ? pidfile : g_strdup (NM_DEFAULT_PID_FILE);
state_file = state_file ? state_file : g_strdup (NM_DEFAULT_SYSTEM_STATE_FILE);
/* check pid file */
if (nm_main_utils_check_pidfile (pidfile, "NetworkManager"))
exit (1);
/* Read the config file and CLI overrides */
config = nm_config_setup (config_cli, &error);
nm_config_cmd_line_options_free (config_cli);
@@ -318,10 +345,12 @@ main (int argc, char *argv[])
exit (1);
}
_init_nm_debug (nm_config_get_debug (config));
/* Initialize logging from config file *only* if not explicitly
* specified by commandline.
*/
if (opt_log_level == NULL && opt_log_domains == NULL) {
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,
@@ -337,17 +366,7 @@ main (int argc, char *argv[])
}
}
/* Parse the state file */
if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) {
fprintf (stderr, _("State file %s parsing failed: (%d) %s\n"),
state_file,
error ? error->code : -1,
(error && error->message) ? error->message : _("unknown"));
/* Not a hard failure */
}
g_clear_error (&error);
if (become_daemon && !debug) {
if (global_opt.become_daemon && !global_opt.debug) {
if (daemon (0, 0) < 0) {
int saved_errno;
@@ -357,27 +376,25 @@ main (int argc, char *argv[])
saved_errno);
exit (1);
}
wrote_pidfile = nm_main_utils_write_pidfile (pidfile);
wrote_pidfile = nm_main_utils_write_pidfile (global_opt.pidfile);
}
_init_nm_debug (nm_config_get_debug (config));
/* Set up unix signal handling - before creating threads, but after daemonizing! */
nm_main_utils_setup_signals (main_loop);
if (g_fatal_warnings) {
GLogLevelFlags fatal_mask;
nm_logging_syslog_openlog (global_opt.debug);
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
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, &wimax_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 */
}
nm_logging_syslog_openlog (debug);
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
#endif
g_clear_error (&error);
dbus_threads_init_default ();
@@ -386,9 +403,6 @@ main (int argc, char *argv[])
*/
dbus_glib_global_set_disable_legacy_property_access ();
nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
success = FALSE;
nm_log_info (LOGD_CORE, "Read config: %s", nm_config_data_get_config_description (nm_config_get_data (config)));
nm_log_info (LOGD_CORE, "WEXT support is %s",
#if HAVE_WEXT
@@ -398,6 +412,21 @@ main (int argc, char *argv[])
#endif
);
if (!nm_dbus_manager_get_connection (nm_dbus_manager_get ())) {
#if HAVE_DBUS_GLIB_100
nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available");
#else
nm_log_err (LOGD_CORE, "Failed to connect to D-Bus, exiting...");
goto done;
#endif
} else {
/* Start our DBus service */
if (!nm_dbus_manager_start_service (nm_dbus_manager_get ())) {
nm_log_err (LOGD_CORE, "failed to start the dbus service.");
goto done;
}
}
/* Set up platform interaction layer */
nm_linux_platform_setup ();
@@ -413,7 +442,7 @@ main (int argc, char *argv[])
}
manager = nm_manager_new (settings,
state_file,
global_opt.state_file,
net_enabled,
wifi_enabled,
wwan_enabled,
@@ -425,21 +454,6 @@ main (int argc, char *argv[])
goto done;
}
if (!nm_dbus_manager_get_connection (nm_dbus_manager_get ())) {
#if HAVE_DBUS_GLIB_100
nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available");
#else
nm_log_err (LOGD_CORE, "Failed to connect to D-Bus, exiting...");
goto done;
#endif
} else {
/* Start our DBus service */
if (!nm_dbus_manager_start_service (nm_dbus_manager_get ())) {
nm_log_err (LOGD_CORE, "failed to start the dbus service.");
goto done;
}
}
g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
nm_manager_start (manager);
@@ -469,8 +483,8 @@ done:
nm_logging_syslog_closelog ();
if (pidfile && wrote_pidfile)
unlink (pidfile);
if (global_opt.pidfile && wrote_pidfile)
unlink (global_opt.pidfile);
nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
exit (success ? 0 : 1);

View File

@@ -34,6 +34,10 @@
#include <sys/stat.h>
#include <signal.h>
/* Cannot include <net/if.h> due to conflict with <linux/if.h>.
* Forward declare if_nametoindex. */
extern unsigned int if_nametoindex (const char *__ifname);
#include "gsystem-local-alloc.h"
#include "NetworkManagerUtils.h"
#include "nm-linux-platform.h"
@@ -51,13 +55,32 @@
#define NMIH_PID_FILE_FMT NMRUNDIR "/nm-iface-helper-%d.pid"
static GMainLoop *main_loop = NULL;
static char *ifname = NULL;
static int ifindex = -1;
static gboolean slaac_required = FALSE;
static gboolean dhcp4_required = FALSE;
static int tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
static guint32 priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4;
static guint32 priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6;
static struct {
gboolean slaac;
gboolean show_version;
gboolean become_daemon;
gboolean debug;
gboolean g_fatal_warnings;
gboolean slaac_required;
gboolean dhcp4_required;
int tempaddr;
char *ifname;
char *uuid;
char *dhcp4_address;
char *dhcp4_clientid;
char *dhcp4_hostname;
char *iid_str;
char *opt_log_level;
char *opt_log_domains;
guint32 priority_v4;
guint32 priority_v6;
} global_opt = {
.tempaddr = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN,
.priority_v4 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
.priority_v6 = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
};
static void
dhcp4_state_changed (NMDhcpClient *client,
@@ -71,7 +94,7 @@ dhcp4_state_changed (NMDhcpClient *client,
g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d", ifname, state);
nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d", global_opt.ifname, state);
switch (state) {
case NM_DHCP_STATE_BOUND:
@@ -81,8 +104,8 @@ dhcp4_state_changed (NMDhcpClient *client,
nm_ip4_config_subtract (existing, last_config);
nm_ip4_config_merge (existing, ip4_config);
if (!nm_ip4_config_commit (existing, ifindex, priority_v4))
nm_log_warn (LOGD_DHCP4, "(%s): failed to apply DHCPv4 config", ifname);
if (!nm_ip4_config_commit (existing, ifindex, global_opt.priority_v4))
nm_log_warn (LOGD_DHCP4, "(%s): failed to apply DHCPv4 config", global_opt.ifname);
if (last_config) {
g_object_unref (last_config);
@@ -93,11 +116,11 @@ dhcp4_state_changed (NMDhcpClient *client,
case NM_DHCP_STATE_TIMEOUT:
case NM_DHCP_STATE_DONE:
case NM_DHCP_STATE_FAIL:
if (dhcp4_required) {
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed, quitting...", ifname);
if (global_opt.dhcp4_required) {
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed, quitting...", global_opt.ifname);
g_main_loop_quit (main_loop);
} else
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed", ifname);
nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 timed out or failed", global_opt.ifname);
break;
default:
break;
@@ -128,8 +151,8 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
if (system_support)
ifa_flags = IFA_F_NOPREFIXROUTE;
if (tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|| tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
if (global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|| global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
{
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
ifa_flags |= IFA_F_MANAGETEMPADDR;
@@ -193,7 +216,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
route.plen = discovered_route->plen;
route.gateway = discovered_route->gateway;
route.source = NM_IP_CONFIG_SOURCE_RDISC;
route.metric = priority_v6;
route.metric = global_opt.priority_v6;
nm_ip6_config_add_route (ip6_config, &route);
}
@@ -210,23 +233,23 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
char val[16];
g_snprintf (val, sizeof (val), "%d", rdisc->hop_limit);
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "hop_limit"), val);
nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "hop_limit"), val);
}
if (changed & NM_RDISC_CONFIG_MTU) {
char val[16];
g_snprintf (val, sizeof (val), "%d", rdisc->mtu);
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "mtu"), val);
nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "mtu"), val);
}
existing = nm_ip6_config_capture (ifindex, FALSE, tempaddr);
existing = nm_ip6_config_capture (ifindex, FALSE, global_opt.tempaddr);
if (last_config)
nm_ip6_config_subtract (existing, last_config);
nm_ip6_config_merge (existing, ip6_config);
if (!nm_ip6_config_commit (existing, ifindex))
nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", ifname);
nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", global_opt.ifname);
if (last_config) {
g_object_unref (last_config);
@@ -238,11 +261,11 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
static void
rdisc_ra_timeout (NMRDisc *rdisc, gpointer user_data)
{
if (slaac_required) {
nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed, quitting...", ifname);
if (global_opt.slaac_required) {
nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed, quitting...", global_opt.ifname);
g_main_loop_quit (main_loop);
} else
nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed", ifname);
nm_log_warn (LOGD_IP6, "(%s): IPv6 timed out or failed", global_opt.ifname);
}
static gboolean
@@ -260,15 +283,63 @@ setup_signals (void)
g_unix_signal_add (SIGTERM, quit_handler, NULL);
}
static void
do_early_setup (int *argc, char **argv[])
{
gint64 priority64_v4 = -1;
gint64 priority64_v6 = -1;
GOptionEntry options[] = {
/* Interface/IP config */
{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &global_opt.ifname, N_("The interface to manage"), N_("eth0") },
{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &global_opt.uuid, N_("Connection UUID"), N_("661e8cd0-b618-46b8-9dc9-31a52baaa16b") },
{ "slaac", 's', 0, G_OPTION_ARG_NONE, &global_opt.slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &global_opt.slaac_required, N_("Whether SLAAC must be successful"), NULL },
{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &global_opt.tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
{ "dhcp4", 'd', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_address, N_("Current DHCPv4 address"), NULL },
{ "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &global_opt.dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL },
{ "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL },
{ "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") },
{ "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") },
{ "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") },
{ "iid", 'e', 0, G_OPTION_ARG_STRING, &global_opt.iid_str, N_("Hex-encoded Interface Identifier"), N_("") },
/* Logging/debugging */
{ "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL },
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL },
{ "debug", 'b', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL },
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" },
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains,
N_("Log domains separated by ',': any combination of [%s]"),
"PLATFORM,RFKILL,WIFI" },
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &global_opt.g_fatal_warnings, N_("Make all warnings fatal"), NULL },
{NULL}
};
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
#endif
setpgid (getpid (), getpid ());
if (!nm_main_utils_early_setup ("nm-iface-helper",
argc,
argv,
options,
NULL,
NULL,
_("nm-iface-helper is a small, standalone process that manages a single network interface.")))
exit (1);
if (priority64_v4 >= 0 && priority64_v4 <= G_MAXUINT32)
global_opt.priority_v4 = (guint32) priority64_v4;
if (priority64_v6 >= 0 && priority64_v6 <= G_MAXUINT32)
global_opt.priority_v6 = (guint32) priority64_v6;
}
int
main (int argc, char *argv[])
{
char *opt_log_level = NULL;
char *opt_log_domains = NULL;
gboolean debug = FALSE, g_fatal_warnings = FALSE, become_daemon = FALSE;
gboolean show_version = FALSE, slaac = FALSE;
char *bad_domains = NULL, *dhcp4_hostname = NULL, *uuid = NULL;
char *iid_str = NULL, *dhcp4_clientid = NULL, *dhcp4_address = NULL;
char *bad_domains = NULL;
GError *error = NULL;
gboolean wrote_pidfile = FALSE;
gs_free char *pidfile = NULL;
@@ -278,59 +349,47 @@ main (int argc, char *argv[])
size_t hwaddr_len = 0;
gconstpointer tmp;
gs_free NMUtilsIPv6IfaceId *iid = NULL;
gint64 priority64_v4 = -1;
gint64 priority64_v6 = -1;
GOptionEntry options[] = {
/* Interface/IP config */
{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &ifname, N_("The interface to manage"), N_("eth0") },
{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &uuid, N_("Connection UUID"), N_("661e8cd0-b618-46b8-9dc9-31a52baaa16b") },
{ "slaac", 's', 0, G_OPTION_ARG_NONE, &slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &slaac_required, N_("Whether SLAAC must be successful"), NULL },
{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
{ "dhcp4", 'd', 0, G_OPTION_ARG_STRING, &dhcp4_address, N_("Current DHCPv4 address"), NULL },
{ "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL },
{ "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL },
{ "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") },
{ "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") },
{ "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") },
{ "iid", 'e', 0, G_OPTION_ARG_STRING, &iid_str, N_("Hex-encoded Interface Identifier"), N_("") },
/* Logging/debugging */
{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
{ "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &become_daemon, N_("Don't become a daemon"), NULL },
{ "debug", 'b', 0, G_OPTION_ARG_NONE, &debug, N_("Don't become a daemon, and log to stderr"), NULL },
{ "log-level", 0, 0, G_OPTION_ARG_STRING, &opt_log_level, N_("Log level: one of [%s]"), "INFO" },
{ "log-domains", 0, 0, G_OPTION_ARG_STRING, &opt_log_domains,
N_("Log domains separated by ',': any combination of [%s]"),
"PLATFORM,RFKILL,WIFI" },
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, N_("Make all warnings fatal"), NULL },
{NULL}
};
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
#endif
setpgid (getpid (), getpid ());
if (!nm_main_utils_early_setup ("nm-iface-helper",
&argv,
&argc,
options,
NULL,
NULL,
_("nm-iface-helper is a small, standalone process that manages a single network interface.")))
exit (1);
do_early_setup (&argc, &argv);
if (show_version) {
if (global_opt.g_fatal_warnings) {
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
if (global_opt.show_version) {
fprintf (stdout, NM_DIST_VERSION "\n");
exit (0);
}
if (!ifname || !uuid) {
nm_main_utils_ensure_root ();
if (!global_opt.ifname || !global_opt.uuid) {
fprintf (stderr, _("An interface name and UUID are required\n"));
exit (1);
}
if (!nm_logging_setup (opt_log_level,
opt_log_domains,
ifindex = if_nametoindex (global_opt.ifname);
if (ifindex <= 0) {
fprintf (stderr, _("Failed to find interface index for %s (%s)\n"), global_opt.ifname, strerror (errno));
exit (1);
}
pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, ifindex);
nm_main_utils_ensure_not_running_pidfile (pidfile);
nm_main_utils_ensure_rundir ();
if (!nm_logging_setup (global_opt.opt_log_level,
global_opt.opt_log_domains,
&bad_domains,
&error)) {
fprintf (stderr,
@@ -344,14 +403,7 @@ main (int argc, char *argv[])
g_clear_pointer (&bad_domains, g_free);
}
pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, ifindex);
g_assert (pidfile);
/* check pid file */
if (nm_main_utils_check_pidfile (pidfile, "nm-iface-helper"))
exit (1);
if (become_daemon && !debug) {
if (global_opt.become_daemon && !global_opt.debug) {
if (daemon (0, 0) < 0) {
int saved_errno;
@@ -369,70 +421,46 @@ main (int argc, char *argv[])
main_loop = g_main_loop_new (NULL, FALSE);
setup_signals ();
if (g_fatal_warnings) {
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
nm_logging_syslog_openlog (debug);
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
#endif
nm_logging_syslog_openlog (global_opt.debug);
nm_log_info (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");
/* Set up platform interaction layer */
nm_linux_platform_setup ();
ifindex = nm_platform_link_get_ifindex (ifname);
if (ifindex <= 0) {
fprintf (stderr, _("Failed to find interface index for %s\n"), ifname);
exit (1);
}
tmp = nm_platform_link_get_address (ifindex, &hwaddr_len);
if (tmp) {
hwaddr = g_byte_array_sized_new (hwaddr_len);
g_byte_array_append (hwaddr, tmp, hwaddr_len);
}
if (iid_str) {
if (global_opt.iid_str) {
GBytes *bytes;
gsize ignored = 0;
bytes = nm_utils_hexstr2bin (iid_str);
bytes = nm_utils_hexstr2bin (global_opt.iid_str);
if (!bytes || g_bytes_get_size (bytes) != sizeof (*iid)) {
fprintf (stderr, _("(%s): Invalid IID %s\n"), ifname, iid_str);
fprintf (stderr, _("(%s): Invalid IID %s\n"), global_opt.ifname, global_opt.iid_str);
exit (1);
}
iid = g_bytes_unref_to_data (bytes, &ignored);
}
if (priority64_v4 >= 0 && priority64_v4 <= G_MAXUINT32)
priority_v4 = (guint32) priority64_v4;
if (priority64_v6 >= 0 && priority64_v6 <= G_MAXUINT32)
priority_v6 = (guint32) priority64_v6;
if (dhcp4_address) {
nm_platform_sysctl_set (nm_utils_ip4_property_path (ifname, "promote_secondaries"), "1");
if (global_opt.dhcp4_address) {
nm_platform_sysctl_set (nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries"), "1");
dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
ifname,
global_opt.ifname,
ifindex,
hwaddr,
uuid,
priority_v4,
!!dhcp4_hostname,
dhcp4_hostname,
dhcp4_clientid,
global_opt.uuid,
global_opt.priority_v4,
!!global_opt.dhcp4_hostname,
global_opt.dhcp4_hostname,
global_opt.dhcp4_clientid,
45,
NULL,
dhcp4_address);
global_opt.dhcp4_address);
g_assert (dhcp4_client);
g_signal_connect (dhcp4_client,
NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
@@ -440,19 +468,19 @@ main (int argc, char *argv[])
NULL);
}
if (slaac) {
if (global_opt.slaac) {
nm_platform_link_set_user_ipv6ll_enabled (ifindex, TRUE);
rdisc = nm_lndp_rdisc_new (ifindex, ifname);
rdisc = nm_lndp_rdisc_new (ifindex, global_opt.ifname);
g_assert (rdisc);
if (iid)
nm_rdisc_set_iid (rdisc, *iid);
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra"), "1");
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_defrtr"), "0");
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_pinfo"), "0");
nm_platform_sysctl_set (nm_utils_ip6_property_path (ifname, "accept_ra_rtr_pref"), "0");
nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra"), "1");
nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr"), "0");
nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo"), "0");
nm_platform_sysctl_set (nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref"), "0");
g_signal_connect (rdisc,
NM_RDISC_CONFIG_CHANGED,