[PATCH] dhcp-manager: add udhcpc support



Signed-off-by: Yegor Yefremov <yegorslists googlemail com>
---
 configure.ac                       |   9 ++
 src/Makefile.am                    |   3 +
 src/dhcp-manager/nm-dhcp-manager.c |  18 ++++
 src/dhcp-manager/nm-dhcp-udhcpc.c  | 203 +++++++++++++++++++++++++++++++++++++
 src/dhcp-manager/nm-dhcp-udhcpc.h  |  46 +++++++++
 5 files changed, 279 insertions(+)
 create mode 100644 src/dhcp-manager/nm-dhcp-udhcpc.c
 create mode 100644 src/dhcp-manager/nm-dhcp-udhcpc.h

diff --git a/configure.ac b/configure.ac
index f13dc9a..49b9c0c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -551,9 +551,11 @@ AM_CONDITIONAL(WITH_MODEM_MANAGER_1, test "${with_modem_manager_1}" = "yes")
 # DHCP client support
 AC_ARG_WITH([dhclient], AS_HELP_STRING([--with-dhclient=yes|no|path], [Enable dhclient 4.x support]))
 AC_ARG_WITH([dhcpcd], AS_HELP_STRING([--with-dhcpcd=yes|no|path], [Enable dhcpcd 4.x support]))
+AC_ARG_WITH([udhcpc], AS_HELP_STRING([--with-udhcpc=yes|no|path], [Enable udhcpc support]))
 # Default to "yes"
 AS_IF([test -z "$with_dhclient"], with_dhclient=yes)
 AS_IF([test -z "$with_dhcpcd"], with_dhcpcd=yes)
+AS_IF([test -z "$with_udhcpc"], with_udhcpc=yes)
 # Search and check the executables
 if test "$with_dhclient" = "yes"; then
        AC_PATH_PROGS(with_dhclient, dhclient, no, /sbin:/usr/sbin:/usr/local/sbin)
@@ -575,6 +577,9 @@ if test "$with_dhcpcd" = "yes"; then
                fi
        fi
 fi
+if test "$with_udhcpc" = "yes"; then
+       AC_PATH_PROGS(with_udhcpc, udhcpc, no, /sbin:/usr/sbin:/usr/local/sbin)
+fi
 # Fallback
 if test "$with_dhclient" = "no" -a "$with_dhcpcd" = "no"; then
        AC_MSG_WARN([Could not find a suitable DHCP client, falling back to dhclient])
@@ -587,6 +592,9 @@ fi
 if test "$with_dhcpcd" != "no"; then
        AC_SUBST(DHCPCD_PATH, $with_dhcpcd)
 fi
+if test "$with_udhcpc" != "no"; then
+       AC_SUBST(UDHCPC_PATH, $with_udhcpc)
+fi
 
 # resolvconf and netconfig support
 AC_ARG_WITH(resolvconf, AS_HELP_STRING([--with-resolvconf=yes|no|path], [Enable resolvconf support]))
@@ -876,6 +884,7 @@ echo
 echo "DHCP clients:"
 echo "  dhclient: $with_dhclient"
 echo "  dhcpcd: $with_dhcpcd"
+echo "  udhcpc: $with_udhcpc"
 echo
 
 echo "Miscellaneous:"
diff --git a/src/Makefile.am b/src/Makefile.am
index f3fcfba..a5f5b06 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -103,6 +103,8 @@ nm_sources = \
        dhcp-manager/nm-dhcp-dhcpcd.h \
        dhcp-manager/nm-dhcp-manager.c \
        dhcp-manager/nm-dhcp-manager.h \
+       dhcp-manager/nm-dhcp-udhcpc.c \
+       dhcp-manager/nm-dhcp-udhcpc.h \
        \
        dns-manager/nm-dns-dnsmasq.c \
        dns-manager/nm-dns-dnsmasq.h \
@@ -348,6 +350,7 @@ AM_CPPFLAGS += \
        \
        -DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
        -DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \
+       -DUDHCPC_PATH=\"$(UDHCPC_PATH)\" \
        -DPPPD_PLUGIN_DIR=\"$(PPPD_PLUGIN_DIR)\" \
        \
        $(NULL)
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index 3ac220d..372da6f 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -37,6 +37,7 @@
 #include "nm-dhcp-manager.h"
 #include "nm-dhcp-dhclient.h"
 #include "nm-dhcp-dhcpcd.h"
+#include "nm-dhcp-udhcpc.h"
 #include "nm-logging.h"
 #include "nm-dbus-manager.h"
 #include "nm-hostname-provider.h"
@@ -292,6 +293,7 @@ get_client_type (const char *client, GError **error)
 {
        const char *dhclient_path = NULL;
        const char *dhcpcd_path = NULL;
+       const char *udhcpc_path = NULL;
 
        /* If a client was disabled at build-time, its *_PATH define will be
         * an empty string.
@@ -303,11 +305,17 @@ get_client_type (const char *client, GError **error)
        if (DHCPCD_PATH && strlen (DHCPCD_PATH))
                dhcpcd_path = nm_dhcp_dhcpcd_get_path (DHCPCD_PATH);
 
+       /* coverity[array_null] */
+       if (UDHCPC_PATH && strlen (UDHCPC_PATH))
+               udhcpc_path = nm_dhcp_udhcpc_get_path (UDHCPC_PATH);
+
        if (!client) {
                if (dhclient_path)
                        return NM_TYPE_DHCP_DHCLIENT;
                else if (dhcpcd_path)
                        return NM_TYPE_DHCP_DHCPCD;
+               else if (udhcpc_path)
+                       return NM_TYPE_DHCP_UDHCPC;
                else {
                        g_set_error_literal (error,
                                             NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
@@ -336,6 +344,16 @@ get_client_type (const char *client, GError **error)
                return NM_TYPE_DHCP_DHCPCD;
        }
 
+       if (!strcmp (client, "udhcpc")) {
+               if (!udhcpc_path) {
+                       g_set_error_literal (error,
+                                            NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
+                                            _("'udhcpc' could be found."));
+                       return G_TYPE_INVALID;
+               }
+               return NM_TYPE_DHCP_UDHCPC;
+       }
+
        g_set_error (error,
                     NM_DHCP_MANAGER_ERROR, NM_DHCP_MANAGER_ERROR_BAD_CLIENT,
                     _("unsupported DHCP client '%s'"), client);
diff --git a/src/dhcp-manager/nm-dhcp-udhcpc.c b/src/dhcp-manager/nm-dhcp-udhcpc.c
new file mode 100644
index 0000000..9a9c1c1
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-udhcpc.c
@@ -0,0 +1,203 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-dhcp-udhcpc.c - udhcpc specific hooks for NetworkManager
+ *
+ * Copyright (C) 2008 Roy Marples
+ * Copyright (C) 2010 Dan Williams <dcbw redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "nm-dhcp-udhcpc.h"
+#include "nm-dhcp-manager.h"
+#include "nm-utils.h"
+#include "nm-logging.h"
+#include "nm-posix-signals.h"
+
+G_DEFINE_TYPE (NMDHCPUdhcpc, nm_dhcp_udhcpc, NM_TYPE_DHCP_CLIENT)
+
+#define NM_DHCP_UDHCPC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_UDHCPC, 
NMDHCPUdhcpcPrivate))
+
+typedef struct {
+       const char *path;
+       char *pid_file;
+} NMDHCPUdhcpcPrivate;
+
+const char *
+nm_dhcp_udhcpc_get_path (const char *try_first)
+{
+       static const char *udhcpc_paths[] = {
+               "/sbin/udhcpc",
+               "/usr/sbin/udhcpc",
+               "/usr/pkg/sbin/udhcpc",
+               "/usr/local/sbin/udhcpc",
+               NULL
+       };
+       const char **path = udhcpc_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 void
+udhcpc_child_setup (gpointer user_data G_GNUC_UNUSED)
+{
+       /* We are in the child process at this point */
+       pid_t pid = getpid ();
+       setpgid (pid, pid);
+
+       /*
+        * We blocked signals in main(). We need to restore original signal
+        * mask for dhclient here so that it can receive signals.
+        */
+       nm_unblock_posix_signals (NULL);
+}
+
+static GPid
+ip4_start (NMDHCPClient *client,
+           NMSettingIP4Config *s_ip4,
+           guint8 *dhcp_anycast_addr,
+           const char *hostname)
+{
+       NMDHCPUdhcpcPrivate *priv = NM_DHCP_UDHCPC_GET_PRIVATE (client);
+       GPtrArray *argv = NULL;
+       GPid pid = -1;
+       GError *error = NULL;
+       char *pid_contents = NULL, *binary_name, *cmd_str, *hostname_opt;
+       const char *iface;
+
+       g_return_val_if_fail (priv->pid_file == NULL, -1);
+
+       iface = nm_dhcp_client_get_iface (client);
+
+       /* Specify pidfile*/
+       priv->pid_file = g_strdup_printf (RUNDIR "/udhcpc-%s.pid", iface);
+
+       if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
+               nm_log_warn (LOGD_DHCP4, "%s does not exist.", priv->path);
+               return -1;
+       }
+
+       /* Kill any existing udhcpc 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) priv->path);
+
+       g_ptr_array_add (argv, (gpointer) "-p");        /* Specify pidfile*/
+       g_ptr_array_add (argv, (gpointer) priv->pid_file);
+
+       g_ptr_array_add (argv, (gpointer) "-f");        /* Don't background on lease (disable fork()) */
+
+       if (hostname && strlen (hostname)) {
+               g_ptr_array_add (argv, (gpointer) "-x");        /* Send hostname to DHCP server */
+               hostname_opt = g_strdup_printf ("hostname:", hostname);
+               g_ptr_array_add (argv, (gpointer) hostname_opt );
+       }
+
+       g_ptr_array_add (argv, (gpointer) "-i");        /* Specify interface */
+       g_ptr_array_add (argv, (gpointer) iface);
+       g_ptr_array_add (argv, NULL);
+
+       cmd_str = g_strjoinv (" ", (gchar **) argv->pdata);
+       nm_log_dbg (LOGD_DHCP4, "running: %s", cmd_str);
+       g_free (cmd_str);
+
+       if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
+                           &udhcpc_child_setup, NULL, &pid, &error)) {
+               nm_log_warn (LOGD_DHCP4, "udhcpc failed to start.  error: '%s'", error->message);
+               g_error_free (error);
+               pid = -1;
+       } else
+               nm_log_info (LOGD_DHCP4, "udhcpc started with pid %d", pid);
+
+       g_free (pid_contents);
+       g_ptr_array_free (argv, TRUE);
+       return pid;
+}
+
+static void
+stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
+{
+       NMDHCPUdhcpcPrivate *priv = NM_DHCP_UDHCPC_GET_PRIVATE (client);
+
+       /* Chain up to parent */
+       NM_DHCP_CLIENT_CLASS (nm_dhcp_udhcpc_parent_class)->stop (client, release, duid);
+
+       if (priv->pid_file) {
+               if (remove (priv->pid_file) == -1)
+                       nm_log_dbg (LOGD_DHCP, "Could not remove dhcp pid file \"%s\": %d (%s)", 
priv->pid_file, errno, g_strerror (errno));
+       }
+
+       /* FIXME: implement release... */
+}
+
+/***************************************************/
+
+static void
+nm_dhcp_udhcpc_init (NMDHCPUdhcpc *self)
+{
+       NMDHCPUdhcpcPrivate *priv = NM_DHCP_UDHCPC_GET_PRIVATE (self);
+
+       priv->path = UDHCPC_PATH;
+}
+
+static void
+dispose (GObject *object)
+{
+       NMDHCPUdhcpcPrivate *priv = NM_DHCP_UDHCPC_GET_PRIVATE (object);
+
+       g_free (priv->pid_file);
+
+       G_OBJECT_CLASS (nm_dhcp_udhcpc_parent_class)->dispose (object);
+}
+
+static void
+nm_dhcp_udhcpc_class_init (NMDHCPUdhcpcClass *udhcpc_class)
+{
+       NMDHCPClientClass *client_class = NM_DHCP_CLIENT_CLASS (udhcpc_class);
+       GObjectClass *object_class = G_OBJECT_CLASS (udhcpc_class);
+
+       g_type_class_add_private (udhcpc_class, sizeof (NMDHCPUdhcpcPrivate));
+
+       /* virtual methods */
+       object_class->dispose = dispose;
+
+       client_class->ip4_start = ip4_start;
+       client_class->stop = stop;
+}
diff --git a/src/dhcp-manager/nm-dhcp-udhcpc.h b/src/dhcp-manager/nm-dhcp-udhcpc.h
new file mode 100644
index 0000000..bafa3bc
--- /dev/null
+++ b/src/dhcp-manager/nm-dhcp-udhcpc.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2005 - 2010 Red Hat, Inc.
+ */
+
+#ifndef NM_DHCP_UDHCPC_H
+#define NM_DHCP_UDHCPC_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "nm-dhcp-client.h"
+
+#define NM_TYPE_DHCP_UDHCPC            (nm_dhcp_udhcpc_get_type ())
+#define NM_DHCP_UDHCPC(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_UDHCPC, 
NMDHCPUdhcpc))
+#define NM_DHCP_UDHCPC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_UDHCPC, 
NMDHCPUdhcpcClass))
+#define NM_IS_DHCP_UDHCPC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_UDHCPC))
+#define NM_IS_DHCP_UDHCPC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_UDHCPC))
+#define NM_DHCP_UDHCPC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_UDHCPC, 
NMDHCPUdhcpcClass))
+
+typedef struct {
+       NMDHCPClient parent;
+} NMDHCPUdhcpc;
+
+typedef struct {
+       NMDHCPClientClass parent;
+} NMDHCPUdhcpcClass;
+
+GType nm_dhcp_udhcpc_get_type (void);
+
+const char *nm_dhcp_udhcpc_get_path (const char *try_first);
+
+#endif
-- 
1.8.3.2



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]