1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/* nm-dhcp-dhcpcd.c - dhcpcd specific hooks for NetworkManager
3    	 *
4    	 * Copyright (C) 2008 Roy Marples
5    	 * Copyright (C) 2010 Dan Williams <dcbw@redhat.com>
6    	 *
7    	 * This program is free software; you can redistribute it and/or modify
8    	 * it under the terms of the GNU General Public License as published by
9    	 * the Free Software Foundation; either version 2, or (at your option)
10   	 * any later version.
11   	 *
12   	 * This program is distributed in the hope that it will be useful,
13   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   	 * GNU General Public License for more details.
16   	 *
17   	 * You should have received a copy of the GNU General Public License along
18   	 * with this program; if not, write to the Free Software Foundation, Inc.,
19   	 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20   	 *
21   	 */
22   	
23   	
24   	#include <glib.h>
25   	#include <glib/gi18n.h>
26   	#include <dbus/dbus.h>
27   	#include <string.h>
28   	#include <stdlib.h>
29   	#include <errno.h>
30   	#include <unistd.h>
31   	#include <stdio.h>
32   	#include <netinet/in.h>
33   	#include <arpa/inet.h>
34   	
35   	#include "nm-dhcp-dhcpcd.h"
36   	#include "nm-dhcp-manager.h"
37   	#include "nm-utils.h"
38   	#include "nm-logging.h"
39   	#include "nm-posix-signals.h"
40   	
41   	G_DEFINE_TYPE (NMDHCPDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT)
42   	
43   	#define NM_DHCP_DHCPCD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_DHCPCD, NMDHCPDhcpcdPrivate))
44   	
45   	typedef struct {
46   		const char *path;
47   		char *pid_file;
48   	} NMDHCPDhcpcdPrivate;
49   	
50   	const char *
51   	nm_dhcp_dhcpcd_get_path (const char *try_first)
52   	{
53   		static const char *dhcpcd_paths[] = {
54   			"/sbin/dhcpcd",
55   			"/usr/sbin/dhcpcd",
56   			"/usr/pkg/sbin/dhcpcd",
57   			"/usr/local/sbin/dhcpcd",
58   			NULL
59   		};
60   		const char **path = dhcpcd_paths;
61   	
62   		if (strlen (try_first) && g_file_test (try_first, G_FILE_TEST_EXISTS))
63   			return try_first;
64   	
65   		while (*path != NULL) {
66   			if (g_file_test (*path, G_FILE_TEST_EXISTS))
67   				break;
68   			path++;
69   		}
70   	
71   		return *path;
72   	}
73   	
74   	GSList *
75   	nm_dhcp_dhcpcd_get_lease_config (const char *iface, const char *uuid, gboolean ipv6)
76   	{
77   		return NULL;
78   	}
79   	
80   	static void
81   	dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED)
82   	{
83   		/* We are in the child process at this point */
84   		pid_t pid = getpid ();
85   		setpgid (pid, pid);
86   	
87   		/*
88   		 * We blocked signals in main(). We need to restore original signal
89   		 * mask for dhcpcd here so that it can receive signals.
90   		 */
91   		nm_unblock_posix_signals (NULL);
92   	}
93   	
94   	static GPid
95   	ip4_start (NMDHCPClient *client,
96   	           NMSettingIP4Config *s_ip4,
97   	           guint8 *dhcp_anycast_addr,
98   	           const char *hostname)
99   	{
100  		NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
101  		GPtrArray *argv = NULL;
102  		GPid pid = -1;
103  		GError *error = NULL;
104  		char *pid_contents = NULL, *binary_name, *cmd_str;
105  		const char *iface, *uuid;
106  	
107  		g_return_val_if_fail (priv->pid_file == NULL, -1);
108  	
109  		iface = nm_dhcp_client_get_iface (client);
(1) Event returned_pointer: Pointer "uuid" returned by "nm_dhcp_client_get_uuid(client)" is never used.
110  		uuid = nm_dhcp_client_get_uuid (client);
111  	
112  		priv->pid_file = g_strdup_printf (NMSTATEDIR "/dhcpcd-%s.pid", iface);
113  	
114  		if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
115  			nm_log_warn (LOGD_DHCP4, "%s does not exist.", priv->path);
116  			return -1;
117  		}
118  	
119  		/* Kill any existing dhcpcd from the pidfile */
120  		binary_name = g_path_get_basename (priv->path);
121  		nm_dhcp_client_stop_existing (priv->pid_file, binary_name);
122  		g_free (binary_name);
123  	
124  		argv = g_ptr_array_new ();
125  		g_ptr_array_add (argv, (gpointer) priv->path);
126  	
127  		g_ptr_array_add (argv, (gpointer) "-B");	/* Don't background on lease (disable fork()) */
128  	
129  		g_ptr_array_add (argv, (gpointer) "-K");	/* Disable built-in carrier detection */
130  	
131  		g_ptr_array_add (argv, (gpointer) "-L");	/* Disable built-in IPv4LL since we use avahi-autoipd */
132  	
133  		g_ptr_array_add (argv, (gpointer) "-G");	/* Let NM handle routing */
134  	
135  		g_ptr_array_add (argv, (gpointer) "-c");	/* Set script file */
136  		g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
137  	
138  		if (hostname && strlen (hostname)) {
139  			g_ptr_array_add (argv, (gpointer) "-h");	/* Send hostname to DHCP server */
140  			g_ptr_array_add (argv, (gpointer) hostname );
141  		}
142  	
143  		g_ptr_array_add (argv, (gpointer) iface);
144  		g_ptr_array_add (argv, NULL);
145  	
146  		cmd_str = g_strjoinv (" ", (gchar **) argv->pdata);
147  		nm_log_dbg (LOGD_DHCP4, "running: %s", cmd_str);
148  		g_free (cmd_str);
149  	
150  		if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
151  		                    &dhcpcd_child_setup, NULL, &pid, &error)) {
152  			nm_log_warn (LOGD_DHCP4, "dhcpcd failed to start.  error: '%s'", error->message);
153  			g_error_free (error);
154  			pid = -1;
155  		} else
156  			nm_log_info (LOGD_DHCP4, "dhcpcd started with pid %d", pid);
157  	
158  		g_free (pid_contents);
159  		g_ptr_array_free (argv, TRUE);
160  		return pid;
161  	}
162  	
163  	static GPid
164  	ip6_start (NMDHCPClient *client,
165  	           NMSettingIP6Config *s_ip6,
166  	           guint8 *dhcp_anycast_addr,
167  	           const char *hostname,
168  	           gboolean info_only,
169  	           const GByteArray *duid)
170  	{
171  		nm_log_warn (LOGD_DHCP6, "the dhcpcd backend does not support IPv6.");
172  		return -1;
173  	}
174  	
175  	static void
176  	stop (NMDHCPClient *client, gboolean release, const GByteArray *duid)
177  	{
178  		NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client);
179  	
180  		/* Chain up to parent */
181  		NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release, duid);
182  	
183  		if (priv->pid_file)
184  			remove (priv->pid_file);
185  	
186  		/* FIXME: implement release... */
187  	}
188  	
189  	/***************************************************/
190  	
191  	static void
192  	nm_dhcp_dhcpcd_init (NMDHCPDhcpcd *self)
193  	{
194  		NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self);
195  	
196  		priv->path = nm_dhcp_dhcpcd_get_path (DHCPCD_PATH);
197  	}
198  	
199  	static void
200  	dispose (GObject *object)
201  	{
202  		NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (object);
203  	
204  		g_free (priv->pid_file);
205  	
206  		G_OBJECT_CLASS (nm_dhcp_dhcpcd_parent_class)->dispose (object);
207  	}
208  	
209  	static void
210  	nm_dhcp_dhcpcd_class_init (NMDHCPDhcpcdClass *dhcpcd_class)
211  	{
212  		NMDHCPClientClass *client_class = NM_DHCP_CLIENT_CLASS (dhcpcd_class);
213  		GObjectClass *object_class = G_OBJECT_CLASS (dhcpcd_class);
214  	
215  		g_type_class_add_private (dhcpcd_class, sizeof (NMDHCPDhcpcdPrivate));
216  	
217  		/* virtual methods */
218  		object_class->dispose = dispose;
219  	
220  		client_class->ip4_start = ip4_start;
221  		client_class->ip6_start = ip6_start;
222  		client_class->stop = stop;
223  	}
224  	
225