From 78dd4fc9f249f1a288462318a087d3c41a63465c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 23 Mar 2010 14:22:10 -0700 Subject: [PATCH] dhcp: make client selection more forgiving If your distributor forgot to set up the client path for you, this makes NM look in the right places and allows you to use either client if it's installed, no matter what NM was configured with. --- src/dhcp-manager/nm-dhcp-dhclient.c | 35 ++++++++- src/dhcp-manager/nm-dhcp-dhclient.h | 2 + src/dhcp-manager/nm-dhcp-dhcpcd.c | 37 +++++++-- src/dhcp-manager/nm-dhcp-dhcpcd.h | 2 + src/dhcp-manager/nm-dhcp-manager.c | 114 ++++++++++++++++++---------- src/dhcp-manager/nm-dhcp-manager.h | 12 +++ 6 files changed, 155 insertions(+), 47 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index ac8f29a109..9ea31ef7aa 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -54,11 +54,35 @@ G_DEFINE_TYPE (NMDHCPDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT) #define ACTION_SCRIPT_PATH LIBEXECDIR "/nm-dhcp-client.action" typedef struct { + const char *path; char *conf_file; char *lease_file; char *pid_file; } NMDHCPDhclientPrivate; +const char * +nm_dhcp_dhclient_get_path (const char *try_first) +{ + static const char *dhclient_paths[] = { + "/sbin/dhclient", + "/usr/sbin/dhclient", + "/usr/pkg/sbin/dhclient", + "/usr/local/sbin/dhclient", + NULL + }; + const char **path = dhclient_paths; + + if (strlen (try_first) && g_file_test (try_first, G_FILE_TEST_EXISTS)) + return try_first; + + while (*path != NULL) { + if (g_file_test (*path, G_FILE_TEST_EXISTS)) + break; + path++; + } + + return *path; +} static char * get_leasefile_for_iface (const char * iface, const char *uuid, gboolean ipv6) @@ -478,13 +502,13 @@ dhclient_start (NMDHCPClient *client, return -1; } - if (!g_file_test (DHCLIENT_PATH, G_FILE_TEST_EXISTS)) { - nm_warning (DHCLIENT_PATH " does not exist."); + if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) { + nm_warning ("%s does not exist.", priv->path); return -1; } /* Kill any existing dhclient from the pidfile */ - binary_name = g_path_get_basename (DHCLIENT_PATH); + binary_name = g_path_get_basename (priv->path); nm_dhcp_client_stop_existing (priv->pid_file, binary_name); g_free (binary_name); @@ -495,7 +519,7 @@ dhclient_start (NMDHCPClient *client, } argv = g_ptr_array_new (); - g_ptr_array_add (argv, (gpointer) DHCLIENT_PATH); + g_ptr_array_add (argv, (gpointer) priv->path); g_ptr_array_add (argv, (gpointer) "-d"); @@ -710,6 +734,9 @@ out: static void nm_dhcp_dhclient_init (NMDHCPDhclient *self) { + NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); + + priv->path = nm_dhcp_dhclient_get_path (DHCLIENT_PATH); } static void diff --git a/src/dhcp-manager/nm-dhcp-dhclient.h b/src/dhcp-manager/nm-dhcp-dhclient.h index db9f73d254..be242de057 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.h +++ b/src/dhcp-manager/nm-dhcp-dhclient.h @@ -43,5 +43,7 @@ GType nm_dhcp_dhclient_get_type (void); GSList *nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid); +const char *nm_dhcp_dhclient_get_path (const char *try_first); + #endif /* NM_DHCP_DHCLIENT_H */ diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 1e014e70b5..6895498a23 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -42,9 +42,33 @@ G_DEFINE_TYPE (NMDHCPDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_DHCPCD) #define ACTION_SCRIPT_PATH LIBEXECDIR "/nm-dhcp-client.action" typedef struct { + const char *path; char *pid_file; } NMDHCPDhcpcdPrivate; +const char * +nm_dhcp_dhcpcd_get_path (const char *try_first) +{ + static const char *dhcpcd_paths[] = { + "/sbin/dhcpcd", + "/usr/sbin/dhcpcd", + "/usr/pkg/sbin/dhcpcd", + "/usr/local/sbin/dhcpcd", + NULL + }; + const char **path = dhcpcd_paths; + + if (strlen (try_first) && g_file_test (try_first, G_FILE_TEST_EXISTS)) + return try_first; + + while (*path != NULL) { + if (g_file_test (*path, G_FILE_TEST_EXISTS)) + break; + path++; + } + + return *path; +} GSList * nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid) @@ -83,18 +107,18 @@ real_ip4_start (NMDHCPClient *client, return -1; } - if (!g_file_test (DHCPCD_PATH, G_FILE_TEST_EXISTS)) { - nm_warning (DHCPCD_PATH " does not exist."); + if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) { + nm_warning ("%s does not exist.", priv->path); return -1; } - /* Kill any existing dhclient from the pidfile */ - binary_name = g_path_get_basename (DHCPCD_PATH); + /* Kill any existing dhcpcd from the pidfile */ + binary_name = g_path_get_basename (priv->path); nm_dhcp_client_stop_existing (priv->pid_file, binary_name); g_free (binary_name); argv = g_ptr_array_new (); - g_ptr_array_add (argv, (gpointer) DHCPCD_PATH); + g_ptr_array_add (argv, (gpointer) priv->path); g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ @@ -230,6 +254,9 @@ out: static void nm_dhcp_dhcpcd_init (NMDHCPDhcpcd *self) { + NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self); + + priv->path = nm_dhcp_dhcpcd_get_path (DHCPCD_PATH); } static void diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.h b/src/dhcp-manager/nm-dhcp-dhcpcd.h index 9a98129419..586c569786 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.h +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.h @@ -43,5 +43,7 @@ GType nm_dhcp_dhcpcd_get_type (void); GSList *nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid); +const char *nm_dhcp_dhcpcd_get_path (const char *try_first); + #endif /* NM_DHCP_DHCPCD_H */ diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index 374c663681..765606788f 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -44,6 +44,35 @@ #include "nm-dbus-glib-types.h" #include "nm-glib-compat.h" +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GQuark +nm_dhcp_manager_error_quark (void) +{ + static GQuark ret = 0; + + if (ret == 0) + ret = g_quark_from_static_string ("nm_dhcp_manager_error"); + + return ret; +} + +GType +nm_dhcp_manager_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + ENUM_ENTRY (NM_DHCP_MANAGER_ERROR_BAD_CLIENT, "BadClient"), + ENUM_ENTRY (NM_DHCP_MANAGER_ERROR_INTERNAL, "InternalError"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMDhcpManagerError", values); + } + return etype; +} + #define NM_DHCP_CLIENT_DBUS_SERVICE "org.freedesktop.nm_dhcp_client" #define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client" @@ -233,15 +262,48 @@ out: static GType get_client_type (const char *client, GError **error) { - g_return_val_if_fail (client != NULL, 0); + const char *dhclient_path = NULL; + const char *dhcpcd_path = NULL; - if (!strcmp (client, "dhclient") && strlen (DHCLIENT_PATH)) + dhclient_path = nm_dhcp_dhclient_get_path (DHCLIENT_PATH); + dhcpcd_path = nm_dhcp_dhcpcd_get_path (DHCPCD_PATH); + + if (!client) { + if (dhclient_path) + return NM_TYPE_DHCP_DHCLIENT; + else if (dhcpcd_path) + return NM_TYPE_DHCP_DHCPCD; + else { + g_set_error_literal (error, + NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT, + _("no usable DHCP client could be found.")); + return 0; + } + } + + if (!strcmp (client, "dhclient")) { + if (!dhclient_path) { + g_set_error_literal (error, + NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT, + _("'dhclient' could be found.")); + return 0; + } return NM_TYPE_DHCP_DHCLIENT; - else if (!strcmp (client, "dhcpcd") && strlen (DHCPCD_PATH)) - return NM_TYPE_DHCP_DHCPCD; - else - g_set_error (error, 0, 0, "unknown or missing DHCP client '%s'", client); + } + if (!strcmp (client, "dhcpcd")) { + if (!dhcpcd_path) { + g_set_error_literal (error, + NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT, + _("'dhcpcd' could be found.")); + return 0; + } + return NM_TYPE_DHCP_DHCPCD; + } + + g_set_error (error, + NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT, + _("unsupported DHCP client '%s'"), client); return 0; } @@ -250,32 +312,19 @@ nm_dhcp_manager_new (const char *client, GError **error) { NMDHCPManagerPrivate *priv; DBusGConnection *g_connection; + GType client_type; - /* Set some defaults based on build-time options */ - if (!client) { - if (strlen (DHCLIENT_PATH) && g_file_test (DHCLIENT_PATH, G_FILE_TEST_EXISTS)) - client = "dhclient"; - else if (strlen (DHCPCD_PATH) && g_file_test (DHCPCD_PATH, G_FILE_TEST_EXISTS)) - client = "dhcpcd"; - else { - g_set_error_literal (error, 0, 0, - "no suitable DHCP client; see 'man NetworkManager'" - " to specify one."); - return NULL; - } - } + client_type = get_client_type (client, error); + if (!client_type) + return NULL; g_warn_if_fail (singleton == NULL); - g_return_val_if_fail (client != NULL, NULL); singleton = g_object_new (NM_TYPE_DHCP_MANAGER, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (singleton); - /* Figure out which DHCP client to use */ - priv->client_type = get_client_type (client, error); - if (!priv->client_type) - goto error; - + /* Client-specific setup */ + priv->client_type = client_type; if (priv->client_type == NM_TYPE_DHCP_DHCLIENT) priv->get_lease_config_func = nm_dhcp_dhclient_get_lease_config; else if (priv->client_type == NM_TYPE_DHCP_DHCPCD) @@ -286,10 +335,7 @@ nm_dhcp_manager_new (const char *client, GError **error) priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_object_unref); - if (!priv->clients) { - g_set_error_literal (error, 0, 0, "not enough memory to initialize DHCP manager"); - goto error; - } + g_assert (priv->clients); priv->dbus_mgr = nm_dbus_manager_get (); g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); @@ -297,10 +343,7 @@ nm_dhcp_manager_new (const char *client, GError **error) NM_DHCP_CLIENT_DBUS_SERVICE, "/", NM_DHCP_CLIENT_DBUS_IFACE); - if (!priv->proxy) { - g_set_error_literal (error, 0, 0, "not enough memory to initialize DHCP manager proxy"); - goto error; - } + g_assert (priv->proxy); dbus_g_proxy_add_signal (priv->proxy, "Event", @@ -313,11 +356,6 @@ nm_dhcp_manager_new (const char *client, GError **error) NULL); return singleton; - -error: - g_object_unref (singleton); - singleton = NULL; - return singleton; } #define STATE_ID_TAG "state-id" diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index df78f1885a..9d83d09605 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -33,6 +33,18 @@ #include "nm-dhcp4-config.h" #include "nm-hostname-provider.h" +enum { + NM_DHCP_MANAGER_ERROR_BAD_CLIENT = 0, + NM_DHCP_MANAGER_ERROR_INTERNAL = 1, +}; + +#define NM_DHCP_MANAGER_ERROR (nm_dhcp_manager_error_quark ()) +#define NN_TYPE_DHCP_MANAGER_ERROR (nm_dhcp_manager_error_get_type ()) + +GQuark nm_dhcp_manager_error_quark (void); +GType nm_dhcp_manager_error_get_type (void); + + #define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type ()) #define NM_DHCP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_MANAGER, NMDHCPManager)) #define NM_DHCP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_MANAGER, NMDHCPManagerClass))