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