diff --git a/configure.ac b/configure.ac index 28734d6e7..5206bd07b 100644 --- a/configure.ac +++ b/configure.ac @@ -286,67 +286,73 @@ else fi AC_SUBST(PPPD_PLUGIN_DIR) -# DHCP client -AC_ARG_WITH([dhcp-client], AS_HELP_STRING([--with-dhcp-client=dhcpcd|dhclient], [path to the chosen dhcp client])) +# dhclient support +AC_ARG_WITH([dhclient], AS_HELP_STRING([--with-dhclient=yes|no|path], [Enable dhclient 4.x support])) # If a full path is given, use that and do not test if it works or not. -case "${with_dhcp_client}" in +case "${with_dhclient}" in /*) - DHCP_CLIENT_PATH="${with_dhcp_client}" - AC_MSG_NOTICE(using the DHCP client ${DHCP_CLIENT_PATH}) + DHCLIENT_PATH="${with_dhclient}" + AC_MSG_NOTICE(using dhclient at ${DHCLIENT_PATH}) + ;; + no) AC_MSG_NOTICE(dhclient support disabled) + ;; + *) + AC_MSG_CHECKING(for dhclient) + # NM only works with ISC dhclient - other derivatives don't have + # the same userland. NM also requires dhclient 4.x since older + # versions do not have IPv6 support. + for path in /sbin /usr/sbin /usr/pkg/sbin /usr/local/sbin; do + test -x "${path}/dhclient" || continue + case `"$path/dhclient" --version 2>&1` in + "isc-dhclient-4"*) DHCLIENT_PATH="$path/dhclient"; break;; + esac + done + if test -n "${DHCLIENT_PATH}"; then + AC_MSG_RESULT($DHCLIENT_PATH) + else + AC_MSG_RESULT(no) + fi ;; esac -if test -z "$DHCP_CLIENT_PATH" -a \( -z "$with_dhcp_client" -o x`basename "$with_dhcp_client"` = "xdhclient" \); then - # We only work with ISC dhclient - the FreeBSD and OpenBSD derivatives don't have the same userland. - AC_MSG_CHECKING(for dhclient) - for client in "$with_dhcp_client" /sbin/dhclient /usr/pkg/sbin/dhclient /usr/local/sbin/dhclient; do - test -x "$client" || continue - case `"$client" --version 2>&1` in - "isc-dhclient-"*) DHCP_CLIENT_PATH="$client"; break;; - esac - done - if test -z "$DHCP_CLIENT_PATH"; then - AC_MSG_RESULT(no) - if test -n "$with_dhcp_client"; then - AC_MSG_ERROR([Could not find ISC dhclient]) + +# dhcpcd support +AC_ARG_WITH([dhcpcd], AS_HELP_STRING([--with-dhcpcd=yes|no|path], [Enable dhcpcd 4.x support])) +# If a full path is given, use that and do not test if it works or not. +case "${with_dhcpcd}" in + /*) + DHCPCD_PATH="${with_dhcpcd}" + AC_MSG_NOTICE(using dhcpcd at ${DHCPCD_PATH}) + ;; + no) AC_MSG_NOTICE(dhcpcd support disabled) + ;; + *) + AC_MSG_CHECKING(for dhcpcd) + # We fully work with upstream dhcpcd-4 + for path in /sbin /usr/sbin /usr/pkg/sbin /usr/local/sbin; do + test -x "${path}/dhclient" || continue + case `"$path/dhcpcd" --version 2>/dev/null` in + "dhcpcd "[123]*);; + "dhcpcd "*) DHCP_CLIENT_PATH="$path/dhcpcd"; break;; + esac + done + if test -n "${DHCPCD_PATH}"; then + AC_MSG_RESULT($DHCPCD_PATH) + else + AC_MSG_RESULT(no) fi - else - AC_MSG_RESULT($DHCP_CLIENT_PATH) - fi -fi -if test -z "$DHCP_CLIENT_PATH" -a \( -z "$with_dhcp_client" -o x`basename "$with_dhcp_client"` = "xdhcpcd" \); then - test -n "$DHCP_CLIENT_PATH" && echo bar - # We fully work with upstream dhcpcd-4 - AC_MSG_CHECKING([for dhcpcd]) - for client in "$with_dhcp_client" /sbin/dhcpcd /usr/pkg/sbin/dhcpcd /usr/local/sbin/dhcpcd; do - test -x "$client" || continue - case `"$client" --version 2>/dev/null` in - "dhcpcd "[123]*);; - "dhcpcd "*) DHCP_CLIENT_PATH="$client"; break;; - esac - done - if test -z "$DHCP_CLIENT_PATH"; then - AC_MSG_RESULT(no) - if test -n "$with_dhcp_client"; then - AC_MSG_ERROR([Could not find dhcpcd-4 or newer]) - fi - else - AC_MSG_RESULT($DHCP_CLIENT_PATH) - fi -fi -if test -z "$DHCP_CLIENT_PATH"; then + ;; +esac + +if test -z "$DHCPCD_PATH" -a -z "$DHCLIENT_PATH"; then # DHCP clients are not a build time dependency, only runtime. # dhclient has been the longtime default for NM and it's in /sbin # in most distros, so use it. AC_MSG_WARN([Could not find a suitable DHCP client]) - DHCP_CLIENT_PATH=/sbin/dhclient + DHCLIENT_PATH=/sbin/dhclient AC_MSG_WARN([Falling back to ISC dhclient, ${DHCP_CLIENT_PATH}]) fi -AC_SUBST(DHCP_CLIENT_PATH) -DHCP_CLIENT=`basename "$DHCP_CLIENT_PATH"` -if test "$DHCP_CLIENT" != "dhclient" -a "$DHCP_CLIENT" != "dhcpcd"; then - AC_MSG_ERROR([No backend for the DHCP client ${DHCP_CLIENT}]) -fi -AC_SUBST(DHCP_CLIENT) +AC_SUBST(DHCLIENT_PATH) +AC_SUBST(DHCPCD_PATH) # resolvconf support AC_ARG_WITH([resolvconf], @@ -492,12 +498,25 @@ NetworkManager.pc AC_OUTPUT echo -echo Distribution targeting: ${with_distro} +echo Distribution target: ${with_distro} echo 'if this is not correct, please specifiy your distro with --with-distro=DISTRO' +echo + +if test -n "${DHCLIENT_PATH}"; then + echo ISC dhclient support: ${DHCLIENT_PATH} +else + echo ISC dhclient support: no +fi + +if test -n "${DHCPCD_PATH}"; then + echo dhcpcd support: ${DHCPCD_PATH} +else + echo dhcpcd support: no +fi + echo echo Building documentation: ${with_docs} -echo echo Building tests: ${with_tests} echo diff --git a/src/NetworkManager.c b/src/NetworkManager.c index 09a4320c7..a6639b8c8 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -302,7 +302,10 @@ done: } static gboolean -parse_config_file (const char *filename, char **plugins, GError **error) +parse_config_file (const char *filename, + char **plugins, + char **dhcp_client, + GError **error) { GKeyFile *config; @@ -321,6 +324,8 @@ parse_config_file (const char *filename, char **plugins, GError **error) if (*error) return FALSE; + *dhcp_client = g_key_file_get_value (config, "main", "dhcp", NULL); + g_key_file_free (config); return TRUE; } @@ -435,7 +440,7 @@ main (int argc, char *argv[]) gboolean become_daemon = FALSE; gboolean g_fatal_warnings = FALSE; char *pidfile = NULL, *user_pidfile = NULL; - char *config = NULL, *plugins = NULL; + char *config = NULL, *plugins = NULL, *dhcp = NULL; char *state_file = NM_DEFAULT_SYSTEM_STATE_FILE; gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE; gboolean success; @@ -498,7 +503,7 @@ main (int argc, char *argv[]) /* Parse the config file */ if (config) { - if (!parse_config_file (config, &plugins, &error)) { + if (!parse_config_file (config, &plugins, &dhcp, &error)) { g_warning ("Config file %s invalid: (%d) %s.", config, error ? error->code : -1, @@ -507,7 +512,7 @@ main (int argc, char *argv[]) } } else { config = NM_DEFAULT_SYSTEM_CONF_FILE; - if (!parse_config_file (config, &plugins, &error)) { + if (!parse_config_file (config, &plugins, &dhcp, &error)) { g_warning ("Default config file %s invalid: (%d) %s.", config, error ? error->code : -1, @@ -620,9 +625,9 @@ main (int argc, char *argv[]) goto done; } - dhcp_mgr = nm_dhcp_manager_get (); + dhcp_mgr = nm_dhcp_manager_new (dhcp ? dhcp : "dhclient", &error); if (!dhcp_mgr) { - nm_warning ("Failed to start the DHCP manager."); + nm_warning ("Failed to start the DHCP manager: %s.", error->message); goto done; } diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am index 711c2a505..ff9041c39 100644 --- a/src/dhcp-manager/Makefile.am +++ b/src/dhcp-manager/Makefile.am @@ -27,7 +27,8 @@ libdhcp_manager_la_CPPFLAGS = \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -DLOCALSTATEDIR=\"$(localstatedir)\" \ - -DDHCP_CLIENT_PATH=\"$(DHCP_CLIENT_PATH)\" + -DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \ + -DDHCPCD_PATH=\"$(DHCPCD_PATH)\" libdhcp_manager_la_LIBADD = \ $(top_builddir)/marshallers/libmarshallers.la \ diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 0e5d81229..5cf77737e 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -114,9 +114,5 @@ NMIP4Config *nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test) /* Backend helpers */ void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name); -/* Implemented by the backends */ -GSList *nm_dhcp_backend_get_lease_config (const char *iface, - const char *uuid); - #endif /* NM_DHCP_CLIENT_H */ diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index c47d155b0..7eec31d31 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -110,7 +110,7 @@ add_lease_option (GHashTable *hash, char *line) } GSList * -nm_dhcp_backend_get_lease_config (const char *iface, const char *uuid) +nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid) { GSList *parsed = NULL, *iter, *leases = NULL; char *contents = NULL; @@ -469,13 +469,13 @@ real_ip4_start (NMDHCPClient *client, return -1; } - if (!g_file_test (DHCP_CLIENT_PATH, G_FILE_TEST_EXISTS)) { - nm_warning (DHCP_CLIENT_PATH " does not exist."); + if (!g_file_test (DHCLIENT_PATH, G_FILE_TEST_EXISTS)) { + nm_warning (DHCLIENT_PATH " does not exist."); return -1; } /* Kill any existing dhclient from the pidfile */ - binary_name = g_path_get_basename (DHCP_CLIENT_PATH); + binary_name = g_path_get_basename (DHCLIENT_PATH); nm_dhcp_client_stop_existing (priv->pid_file, binary_name); g_free (binary_name); @@ -492,7 +492,7 @@ real_ip4_start (NMDHCPClient *client, } argv = g_ptr_array_new (); - g_ptr_array_add (argv, (gpointer) DHCP_CLIENT_PATH); + g_ptr_array_add (argv, (gpointer) DHCLIENT_PATH); g_ptr_array_add (argv, (gpointer) "-d"); diff --git a/src/dhcp-manager/nm-dhcp-dhclient.h b/src/dhcp-manager/nm-dhcp-dhclient.h index bad6452f7..db9f73d25 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.h +++ b/src/dhcp-manager/nm-dhcp-dhclient.h @@ -41,5 +41,7 @@ typedef struct { GType nm_dhcp_dhclient_get_type (void); +GSList *nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid); + #endif /* NM_DHCP_DHCLIENT_H */ diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index ba210eda6..fb1fd1bf1 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -47,7 +47,7 @@ typedef struct { GSList * -nm_dhcp_backend_get_lease_config (const char *iface, const char *uuid) +nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid) { return NULL; } @@ -83,18 +83,18 @@ real_ip4_start (NMDHCPClient *client, return -1; } - if (!g_file_test (DHCP_CLIENT_PATH, G_FILE_TEST_EXISTS)) { - nm_warning (DHCP_CLIENT_PATH " does not exist."); + if (!g_file_test (DHCPCD_PATH, G_FILE_TEST_EXISTS)) { + nm_warning (DHCPCD_PATH " does not exist."); return -1; } /* Kill any existing dhclient from the pidfile */ - binary_name = g_path_get_basename (DHCP_CLIENT_PATH); + binary_name = g_path_get_basename (DHCPCD_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) DHCP_CLIENT_PATH); + g_ptr_array_add (argv, (gpointer) DHCPCD_PATH); g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.h b/src/dhcp-manager/nm-dhcp-dhcpcd.h index f564bc7f7..9a9812941 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.h +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.h @@ -41,5 +41,7 @@ typedef struct { GType nm_dhcp_dhcpcd_get_type (void); +GSList *nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid); + #endif /* NM_DHCP_DHCPCD_H */ diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index f1a84cdd4..59fc2536d 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -36,6 +36,7 @@ #include "nm-dhcp-manager.h" #include "nm-dhcp-dhclient.h" +#include "nm-dhcp-dhcpcd.h" #include "nm-marshal.h" #include "nm-utils.h" #include "nm-dbus-manager.h" @@ -46,8 +47,14 @@ #define NM_DHCP_CLIENT_DBUS_SERVICE "org.freedesktop.nm_dhcp_client" #define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client" +static NMDHCPManager *singleton = NULL; + +typedef GSList * (*GetLeaseConfigFunc) (const char *iface, const char *uuid); + typedef struct { - guint32 next_id; + GType client_type; + GetLeaseConfigFunc get_lease_config_func; + NMDBusManager * dbus_mgr; GHashTable * clients; DBusGProxy * proxy; @@ -219,23 +226,36 @@ out: g_free (reason); } -static NMDHCPManager * -nm_dhcp_manager_new (void) +NMDHCPManager * +nm_dhcp_manager_new (const char *client, GError **error) { - NMDHCPManager *manager; NMDHCPManagerPrivate *priv; DBusGConnection *g_connection; - manager = g_object_new (NM_TYPE_DHCP_MANAGER, NULL); - priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); + 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 */ + if (!strcmp (client, "dhclient") && strlen (DHCLIENT_PATH)) { + priv->client_type = NM_TYPE_DHCP_DHCLIENT; + priv->get_lease_config_func = nm_dhcp_dhclient_get_lease_config; + } else if (!strcmp (client, "dhcpcd") && strlen (DHCPCD_PATH)) { + priv->client_type = NM_TYPE_DHCP_DHCPCD; + priv->get_lease_config_func = nm_dhcp_dhcpcd_get_lease_config; + } else { + g_set_error (error, 0, 0, "unknown or missing DHCP client '%s'", client); + goto error; + } priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_object_unref); if (!priv->clients) { - nm_warning ("Error: not enough memory to initialize DHCP manager tables"); - g_object_unref (manager); - return NULL; + g_set_error_literal (error, 0, 0, "not enough memory to initialize DHCP manager"); + goto error; } priv->dbus_mgr = nm_dbus_manager_get (); @@ -245,9 +265,8 @@ nm_dhcp_manager_new (void) "/", NM_DHCP_CLIENT_DBUS_IFACE); if (!priv->proxy) { - nm_warning ("Error: could not init DHCP manager proxy"); - g_object_unref (manager); - return NULL; + g_set_error_literal (error, 0, 0, "not enough memory to initialize DHCP manager proxy"); + goto error; } dbus_g_proxy_add_signal (priv->proxy, @@ -256,11 +275,16 @@ nm_dhcp_manager_new (void) G_TYPE_INVALID); dbus_g_proxy_connect_signal (priv->proxy, "Event", - G_CALLBACK (nm_dhcp_manager_handle_event), - manager, - NULL); + G_CALLBACK (nm_dhcp_manager_handle_event), + singleton, + NULL); - return manager; + return singleton; + +error: + g_object_unref (singleton); + singleton = NULL; + return singleton; } #define STATE_ID_TAG "state-id" @@ -416,7 +440,7 @@ nm_dhcp_manager_get_lease_config (NMDHCPManager *self, g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (uuid != NULL, NULL); - return nm_dhcp_backend_get_lease_config (iface, uuid); + return NM_DHCP_MANAGER_GET_PRIVATE (self)->get_lease_config_func (iface, uuid); } NMIP4Config * @@ -443,23 +467,13 @@ nm_dhcp_manager_test_ip4_options_to_config (const char *iface, NMDHCPManager * nm_dhcp_manager_get (void) { - static NMDHCPManager *singleton = NULL; - - if (!singleton) - singleton = nm_dhcp_manager_new (); - else - g_object_ref (singleton); - - g_assert (singleton); - return singleton; + g_warn_if_fail (singleton != NULL); + return g_object_ref (singleton); } static void nm_dhcp_manager_init (NMDHCPManager *manager) { - NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); - - priv->next_id = 1; } static void @@ -468,10 +482,12 @@ dispose (GObject *object) NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (object); GList *values, *iter; - values = g_hash_table_get_values (priv->clients); - for (iter = values; iter; iter = g_list_next (iter)) - remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data)); - g_list_free (values); + if (priv->clients) { + values = g_hash_table_get_values (priv->clients); + for (iter = values; iter; iter = g_list_next (iter)) + remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data)); + g_list_free (values); + } G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object); } @@ -486,9 +502,12 @@ finalize (GObject *object) priv->hostname_provider = NULL; } - g_hash_table_destroy (priv->clients); - g_object_unref (priv->proxy); - g_object_unref (priv->dbus_mgr); + if (priv->clients) + g_hash_table_destroy (priv->clients); + if (priv->proxy) + g_object_unref (priv->proxy); + if (priv->dbus_mgr) + g_object_unref (priv->dbus_mgr); G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object); } diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index 7c82ca59a..441d9fce1 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -70,4 +70,7 @@ NMIP4Config *nm_dhcp_manager_test_ip4_options_to_config (const char *iface, GHashTable *options, const char *reason); +/* Only for NetworkManager.c */ +NMDHCPManager *nm_dhcp_manager_new (const char *client, GError **error); + #endif /* NM_DHCP_MANAGER_H */