blob: f33dbc43c2914b2e7dea5140f0453f166c42875b [file] [log] [blame]
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001/*
2 * ifupdown for busybox
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00003 * Copyright (c) 2002 Glenn McGrath <bug1@optushome.com.au>
4 *
5 * Based on ifupdown v 0.6.4 by Anthony Towns
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00006 * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au>
7 *
Glenn L McGrath398ff9d2002-12-06 11:51:46 +00008 * Changes to upstream version
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00009 * Remove checks for kernel version, assume kernel version 2.2.0 or better.
Glenn L McGrath398ff9d2002-12-06 11:51:46 +000010 * Lines in the interfaces file cannot wrap.
Glenn L McGrath8e49caa2002-12-08 01:23:39 +000011 * To adhere to the FHS, the default state file is /var/run/ifstate.
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000012 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27
28#include <sys/stat.h>
29#include <sys/utsname.h>
30#include <sys/wait.h>
31
32#include <ctype.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <fnmatch.h>
36#include <getopt.h>
37#include <stdarg.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
Glenn L McGrath9af8a722002-11-11 07:03:02 +000043#include "libbb.h"
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000044
Glenn L McGrath8e49caa2002-12-08 01:23:39 +000045#define MAX_OPT_DEPTH 10
46#define EUNBALBRACK 10001
47#define EUNDEFVAR 10002
48#define EUNBALPER 10000
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000049
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000050typedef struct interface_defn_s interface_defn_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000051
52typedef int (execfn)(char *command);
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000053typedef int (command_set)(interface_defn_t *ifd, execfn *e);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000054
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000055typedef struct method_s {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000056 char *name;
57 command_set *up;
58 command_set *down;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000059} method_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000060
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000061typedef struct address_family_s {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000062 char *name;
63 int n_methods;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000064 method_t *method;
65} address_family_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000066
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000067typedef struct mapping_defn_s {
68 struct mapping_defn_s *next;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000069
70 int max_matches;
71 int n_matches;
72 char **match;
73
74 char *script;
75
76 int max_mappings;
77 int n_mappings;
78 char **mapping;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000079} mapping_defn_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000080
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000081typedef struct variable_s {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000082 char *name;
83 char *value;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000084} variable_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000085
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000086struct interface_defn_s {
87 struct interface_defn_s *next;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000088
89 char *iface;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000090 address_family_t *address_family;
91 method_t *method;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000092
93 int automatic;
94
95 int max_options;
96 int n_options;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +000097 variable_t *option;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000098};
99
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000100typedef struct interfaces_file_s {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000101 llist_t *autointerfaces;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000102 interface_defn_t *ifaces;
103 mapping_defn_t *mappings;
104} interfaces_file_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000105
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000106static char no_act = 0;
107static char verbose = 0;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000108static char **environ = NULL;
109
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000110static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length)
111{
112 if (*pos + str_length >= *len) {
113 char *newbuf;
114
115 newbuf = xrealloc(*buf, *len * 2 + str_length + 1);
116 *buf = newbuf;
117 *len = *len * 2 + str_length + 1;
118 }
119
120 while (str_length-- >= 1) {
121 (*buf)[(*pos)++] = *str;
122 str++;
123 }
124 (*buf)[*pos] = '\0';
125}
126
127static int strncmpz(char *l, char *r, size_t llen)
128{
129 int i = strncmp(l, r, llen);
130
131 if (i == 0) {
132 return(-r[llen]);
133 } else {
134 return(i);
135 }
136}
137
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000138static char *get_var(char *id, size_t idlen, interface_defn_t *ifd)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000139{
140 int i;
141
142 if (strncmpz(id, "iface", idlen) == 0) {
143 return (ifd->iface);
144 } else {
145 for (i = 0; i < ifd->n_options; i++) {
146 if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
147 return (ifd->option[i].value);
148 }
149 }
150 }
151
152 return(NULL);
153}
154
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000155static char *parse(char *command, interface_defn_t *ifd)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000156{
157
158 char *result = NULL;
159 size_t pos = 0, len = 0;
160 size_t old_pos[MAX_OPT_DEPTH] = { 0 };
161 int okay[MAX_OPT_DEPTH] = { 1 };
162 int opt_depth = 1;
163
164 while (*command) {
165 switch (*command) {
166
167 default:
168 addstr(&result, &len, &pos, command, 1);
169 command++;
170 break;
171 case '\\':
172 if (command[1]) {
173 addstr(&result, &len, &pos, command + 1, 1);
174 command += 2;
175 } else {
176 addstr(&result, &len, &pos, command, 1);
177 command++;
178 }
179 break;
180 case '[':
181 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
182 old_pos[opt_depth] = pos;
183 okay[opt_depth] = 1;
184 opt_depth++;
185 command += 2;
186 } else {
187 addstr(&result, &len, &pos, "[", 1);
188 command++;
189 }
190 break;
191 case ']':
192 if (command[1] == ']' && opt_depth > 1) {
193 opt_depth--;
194 if (!okay[opt_depth]) {
195 pos = old_pos[opt_depth];
196 result[pos] = '\0';
197 }
198 command += 2;
199 } else {
200 addstr(&result, &len, &pos, "]", 1);
201 command++;
202 }
203 break;
204 case '%':
205 {
206 char *nextpercent;
207 char *varvalue;
208
209 command++;
210 nextpercent = strchr(command, '%');
211 if (!nextpercent) {
212 errno = EUNBALPER;
213 free(result);
214 return (NULL);
215 }
216
217 varvalue = get_var(command, nextpercent - command, ifd);
218
219 if (varvalue) {
220 addstr(&result, &len, &pos, varvalue, xstrlen(varvalue));
221 } else {
222 okay[opt_depth - 1] = 0;
223 }
224
225 command = nextpercent + 1;
226 }
227 break;
228 }
229 }
230
231 if (opt_depth > 1) {
232 errno = EUNBALBRACK;
233 free(result);
234 return(NULL);
235 }
236
237 if (!okay[0]) {
238 errno = EUNDEFVAR;
239 free(result);
240 return(NULL);
241 }
242
243 return(result);
244}
245
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000246static int execute(char *command, interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000247{
248 char *out;
249 int ret;
250
251 out = parse(command, ifd);
252 if (!out) {
253 return(0);
254 }
255
256 ret = (*exec) (out);
257
258 free(out);
259 return(ret);
260}
261
262#ifdef CONFIG_FEATURE_IFUPDOWN_IPX
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000263static int static_up_ipx(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000264{
265 if (!execute("ipx_interface add %iface% %frame% %netnum%", ifd, exec)) {
266 return(0);
267 }
268 return(1);
269}
270
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000271static int static_down_ipx(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000272{
273 if (!execute("ipx_interface del %iface% %frame%", ifd, exec)) {
274 return(0);
275 }
276 return(1);
277}
278
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000279static int dynamic_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000280{
281 if (!execute("ipx_interface add %iface% %frame%", ifd, exec)) {
282 return(0);
283 }
284 return(1);
285}
286
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000287static int dynamic_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000288{
289 if (!execute("ipx_interface del %iface% %frame%", ifd, exec)) {
290 return(0);
291 }
292 return(1);
293}
294
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000295static method_t methods_ipx[] = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000296 { "dynamic", dynamic_up, dynamic_down, },
297 { "static", static_up_ipx, static_down_ipx, },
298};
299
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000300address_family_t addr_ipx = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000301 "ipx",
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000302 sizeof(methods_ipx) / sizeof(method_t),
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000303 methods_ipx
304};
305#endif /* IFUP_FEATURE_IPX */
306
307#ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000308static int loopback_up6(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000309{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000310#ifdef CONFIG_FEATURE_IFUPDOWN_IP
311 if (!execute("ip link set %iface% up", ifd, exec))
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000312 return(0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000313 if (!execute("ip addr add ::1 dev %iface%", ifd, exec))
314 return(0);
315#else
316 if (!execute("ifconfig %iface% add ::1", ifd, exec))
317 return(0);
318#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000319 return(1);
320}
321
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000322static int loopback_down6(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000323{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000324#ifdef CONFIG_FEATURE_IFUPDOWN_IP
325 if (!execute("ip link set %iface% down", ifd, exec))
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000326 return(0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000327#else
328 if (!execute("ifconfig %iface% del ::1", ifd, exec))
329 return(0);
330#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000331 return(1);
332}
333
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000334static int static_up6(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000335{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000336#ifdef CONFIG_FEATURE_IFUPDOWN_IP
337 if (!execute("ip link set %iface% up", ifd, exec))
338 return(0);
339 if (!execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec))
340 return(0);
341 if (!execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec))
342 return(0);
343#else
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000344 if (!execute("ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up", ifd, exec)) {
345 return(0);
346 }
347 if (!execute("ifconfig %iface% add %address%/%netmask%", ifd, exec)) {
348 return(0);
349 }
350 if (!execute("[[ route -A inet6 add ::/0 gw %gateway% ]]", ifd, exec)) {
351 return(0);
352 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000353#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000354 return(1);
355}
356
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000357static int static_down6(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000358{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000359#ifdef CONFIG_FEATURE_IFUPDOWN_IP
360 if (!execute("ip link set %iface% down", ifd, exec))
361 return(0);
362#else
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000363 if (!execute("ifconfig %iface% down", ifd, exec)) {
364 return(0);
365 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000366#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000367 return(1);
368}
369
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000370#ifdef CONFIG_FEATURE_IFUPDOWN_IP
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000371static int v4tunnel_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000372{
373 if (!execute("ip tunnel add %iface% mode sit remote %endpoint% [[local %local%]] [[ttl %ttl%]]", ifd, exec)) {
374 return(0);
375 }
376 if (!execute("ip link set %iface% up", ifd, exec)) {
377 return(0);
378 }
379 if (!execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec)) {
380 return(0);
381 }
382 if (!execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec)) {
383 return(0);
384 }
385 return(1);
386}
387
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000388static int v4tunnel_down(interface_defn_t * ifd, execfn * exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000389{
390 if (!execute("ip tunnel del %iface%", ifd, exec)) {
391 return(0);
392 }
393 return(1);
394}
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000395#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000396
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000397static method_t methods6[] = {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000398#ifdef CONFIG_FEATURE_IFUPDOWN_IP
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000399 { "v4tunnel", v4tunnel_up, v4tunnel_down, },
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000400#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000401 { "static", static_up6, static_down6, },
402 { "loopback", loopback_up6, loopback_down6, },
403};
404
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000405address_family_t addr_inet6 = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000406 "inet6",
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000407 sizeof(methods6) / sizeof(method_t),
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000408 methods6
409};
410#endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */
411
412#ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000413static int loopback_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000414{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000415#ifdef CONFIG_FEATURE_IFUPDOWN_IP
416 if (!execute("ip link set %iface% up", ifd, exec))
417 return(0);
418 if (!execute("ip addr add 127.0.0.1 dev %iface%", ifd, exec))
419 return(0);
420#else
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000421 if (!execute("ifconfig %iface% 127.0.0.1 up", ifd, exec)) {
422 return(0);
423 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000424#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000425 return(1);
426}
427
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000428static int loopback_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000429{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000430#ifdef CONFIG_FEATURE_IFUPDOWN_IP
431 if (!execute("ip -f inet addr flush dev %iface%", ifd, exec))
432 return(0);
433 if (!execute("ip link set %iface% down", ifd, exec))
434 return(0);
435#else
Glenn L McGrath1d658262002-12-07 00:48:54 +0000436 if (!execute("ifconfig %iface% 127.0.0.1 down", ifd, exec)) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000437 return(0);
438 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000439#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000440 return(1);
441}
442
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000443static int static_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000444{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000445#ifdef CONFIG_FEATURE_IFUPDOWN_IP
446 if (!execute("ip link set %iface% up", ifd, exec))
447 return(0);
448 if (!execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec))
449 return(0);
450 if (!execute("[[ ip route add default via %gateway% dev %iface% ]]", ifd, exec))
451 return(0);
452#else
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000453 if (!execute("ifconfig %iface% %address% netmask %netmask% [[broadcast %broadcast%]] [[pointopoint %pointopoint%]] [[media %media%]] [[mtu %mtu%]] [[hw %hwaddress%]] up",
454 ifd, exec)) {
455 return(0);
456 }
457 if (!execute("[[ route add default gw %gateway% %iface% ]]", ifd, exec)) {
458 return(0);
459 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000460#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000461 return(1);
462}
463
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000464static int static_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000465{
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000466#ifdef CONFIG_FEATURE_IFUPDOWN_IP
467 if (!execute("[[ ip route del default via %gateway% dev %iface% ]]", ifd, exec))
468 return(0);
469 if (!execute("ip -f inet addr flush dev %iface%", ifd, exec))
470 return(0);
471 if (!execute("ip link set %iface% down", ifd, exec))
472 return(0);
473#else
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000474 if (!execute("[[ route del default gw %gateway% %iface% ]]", ifd, exec)) {
475 return(0);
476 }
477 if (!execute("ifconfig %iface% down", ifd, exec)) {
478 return(0);
479 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000480#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000481 return(1);
482}
483
Glenn L McGrath49a28b32002-11-10 13:17:08 +0000484static int execable(char *program)
485{
486 struct stat buf;
487 if (0 == stat(program, &buf)) {
488 if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) {
489 return(1);
490 }
491 }
492 return(0);
493}
494
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000495static int dhcp_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000496{
497 if (execable("/sbin/dhclient")) {
498 if (!execute("dhclient -pf /var/run/dhclient.%iface%.pid %iface%", ifd, exec)) {
499 return(0);
500 }
501 } else if (execable("/sbin/pump")) {
502 if (!execute("pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]]", ifd, exec)) {
503 return(0);
504 }
505 } else if (execable("/sbin/udhcpc")) {
506 if (!execute("udhcpc -n -p /var/run/udhcpc.%iface%.pid -i %iface% [[-H %hostname%]] [[-c %clientid%]]", ifd, exec)) {
507 return 0;
508 }
509 } else if (execable("/sbin/dhcpcd")) {
510 if (!execute("dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] [[-l %leasetime%]] %iface%", ifd, exec)) {
511 return(0);
512 }
513 }
514 return(1);
515}
516
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000517static int dhcp_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000518{
519 if (execable("/sbin/dhclient")) {
Glenn L McGrathd1431072002-11-19 09:58:56 +0000520 if (!execute("kill -9 `cat /var/run/udhcpc.%iface%.pid`", ifd, exec)) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000521 return(0);
522 }
523 } else if (execable("/sbin/pump")) {
524 if (!execute("pump -i %iface% -k", ifd, exec)) {
525 return(0);
526 }
527 } else if (execable("/sbin/udhcpc")) {
Glenn L McGrathd1431072002-11-19 09:58:56 +0000528 if (!execute("kill -9 `cat /var/run/udhcpc.%iface%.pid`", ifd, exec)) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000529 return(0);
530 }
531 } else if (execable("/sbin/dhcpcd")) {
532 if (!execute("dhcpcd -k %iface%", ifd, exec)) {
533 return(0);
534 }
535 }
536 if (!execute("ifconfig %iface% down", ifd, exec)) {
537 return(0);
538 }
539 return(1);
540}
541
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000542static int bootp_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000543{
544 if (!execute("bootpc [[--bootfile %bootfile%]] --dev %iface% [[--server %server%]] [[--hwaddr %hwaddr%]] --returniffail --serverbcast", ifd, exec)) {
545 return 0;
546 }
547 return 1;
548}
549
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000550static int bootp_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000551{
552 if (!execute("ifconfig down %iface%", ifd, exec)) {
553 return 0;
554 }
555 return 1;
556}
557
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000558static int ppp_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000559{
560 if (!execute("pon [[%provider%]]", ifd, exec)) {
561 return 0;
562 }
563 return 1;
564}
565
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000566static int ppp_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000567{
568 if (!execute("poff [[%provider%]]", ifd, exec)) {
569 return 0;
570 }
571 return 1;
572}
573
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000574static int wvdial_up(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000575{
576 if (!execute("/sbin/start-stop-daemon --start -x /usr/bin/wvdial -p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]", ifd, exec)) {
577 return 0;
578 }
579 return 1;
580}
581
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000582static int wvdial_down(interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000583{
584 if (!execute ("/sbin/start-stop-daemon --stop -x /usr/bin/wvdial -p /var/run/wvdial.%iface% -s 2", ifd, exec)) {
585 return 0;
586 }
587 return 1;
588}
589
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000590static method_t methods[] = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000591 { "wvdial", wvdial_up, wvdial_down, },
592 { "ppp", ppp_up, ppp_down, },
593 { "static", static_up, static_down, },
594 { "bootp", bootp_up, bootp_down, },
595 { "dhcp", dhcp_up, dhcp_down, },
596 { "loopback", loopback_up, loopback_down, },
597};
598
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000599address_family_t addr_inet = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000600 "inet",
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000601 sizeof(methods) / sizeof(method_t),
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000602 methods
603};
604
605#endif /* ifdef CONFIG_FEATURE_IFUPDOWN_IPV4 */
606
Glenn L McGrath85737042003-01-14 23:26:57 +0000607static char *next_word(char **buf)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000608{
Glenn L McGrath85737042003-01-14 23:26:57 +0000609 unsigned short length;
610 char *word;
611
612 if ((buf == NULL) || (*buf == NULL) || (**buf == '\0')) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000613 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000614 }
615
Glenn L McGrath85737042003-01-14 23:26:57 +0000616 /* Skip over leading whitespace */
617 word = *buf + strspn(*buf, " \t\n");
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000618
Glenn L McGrath85737042003-01-14 23:26:57 +0000619 /* Find the length of this word */
620 length = strcspn(word, " \t\n");
621 if (length == 0) {
622 return(NULL);
623 }
624 *buf = word + length;
625 **buf = '\0';
626 (*buf)++;
627
628 return word;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000629}
630
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000631static address_family_t *get_address_family(address_family_t *af[], char *name)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000632{
633 int i;
634
635 for (i = 0; af[i]; i++) {
636 if (strcmp(af[i]->name, name) == 0) {
637 return af[i];
638 }
639 }
640 return NULL;
641}
642
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000643static method_t *get_method(address_family_t *af, char *name)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000644{
645 int i;
646
647 for (i = 0; i < af->n_methods; i++) {
648 if (strcmp(af->method[i].name, name) == 0) {
649 return &af->method[i];
650 }
651 }
652 return(NULL);
653}
654
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000655static int duplicate_if(interface_defn_t *ifa, interface_defn_t *ifb)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000656{
657 if (strcmp(ifa->iface, ifb->iface) != 0) {
658 return(0);
659 }
660 if (ifa->address_family != ifb->address_family) {
661 return(0);
662 }
663 return(1);
664}
665
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000666static const llist_t *find_list_string(const llist_t *list, const char *string)
667{
668 while (list) {
669 if (strcmp(list->data, string) == 0) {
670 return(list);
671 }
672 list = list->link;
673 }
674 return(NULL);
675}
676
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000677static interfaces_file_t *read_interfaces(char *filename)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000678{
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000679#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000680 mapping_defn_t *currmap = NULL;
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000681#endif
Glenn L McGrath85737042003-01-14 23:26:57 +0000682 interface_defn_t *currif = NULL;
683 interfaces_file_t *defn;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000684 FILE *f;
Glenn L McGrath85737042003-01-14 23:26:57 +0000685 char *firstword;
686 char *buf;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000687
688 enum { NONE, IFACE, MAPPING } currently_processing = NONE;
689
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000690 defn = xmalloc(sizeof(interfaces_file_t));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000691 defn->autointerfaces = NULL;
692 defn->mappings = NULL;
693 defn->ifaces = NULL;
Glenn L McGrath85737042003-01-14 23:26:57 +0000694
695 f = xfopen(filename, "r");
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000696
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000697 while ((buf = get_line_from_file(f)) != NULL) {
Glenn L McGrath85737042003-01-14 23:26:57 +0000698 char *buf_ptr = buf;
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000699
Glenn L McGrath85737042003-01-14 23:26:57 +0000700 /* Ignore comments */
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000701 if (buf[0] == '#') {
702 continue;
703 }
Glenn L McGrath85737042003-01-14 23:26:57 +0000704
705 firstword = next_word(&buf_ptr);
706 if (firstword == NULL) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000707 continue; /* blank line */
708 }
709
710 if (strcmp(firstword, "mapping") == 0) {
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000711#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000712 currmap = xmalloc(sizeof(mapping_defn_t));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000713 currmap->max_matches = 0;
714 currmap->n_matches = 0;
715 currmap->match = NULL;
716
Glenn L McGrath85737042003-01-14 23:26:57 +0000717 while ((firstword = next_word(&buf_ptr)) != NULL) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000718 if (currmap->max_matches == currmap->n_matches) {
719 currmap->max_matches = currmap->max_matches * 2 + 1;
720 currmap->match = xrealloc(currmap->match, sizeof(currmap->match) * currmap->max_matches);
721 }
722
723 currmap->match[currmap->n_matches++] = xstrdup(firstword);
724 }
725 currmap->max_mappings = 0;
726 currmap->n_mappings = 0;
727 currmap->mapping = NULL;
728 currmap->script = NULL;
729 {
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000730 mapping_defn_t **where = &defn->mappings;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000731 while (*where != NULL) {
732 where = &(*where)->next;
733 }
734 *where = currmap;
735 currmap->next = NULL;
736 }
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000737#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000738 currently_processing = MAPPING;
739 } else if (strcmp(firstword, "iface") == 0) {
740 {
Glenn L McGrath85737042003-01-14 23:26:57 +0000741 char *iface_name;
742 char *address_family_name;
743 char *method_name;
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000744 address_family_t *addr_fams[] = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000745#ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
746 &addr_inet,
747#endif
748#ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
749 &addr_inet6,
750#endif
751#ifdef CONFIG_FEATURE_IFUPDOWN_IPX
752 &addr_ipx,
753#endif
754 NULL
755 };
756
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000757 currif = xmalloc(sizeof(interface_defn_t));
Glenn L McGrath85737042003-01-14 23:26:57 +0000758 iface_name = next_word(&buf_ptr);
759 address_family_name = next_word(&buf_ptr);
760 method_name = next_word(&buf_ptr);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000761
Glenn L McGrath85737042003-01-14 23:26:57 +0000762 if (buf_ptr == NULL) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000763 error_msg("too few parameters for line \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000764 return NULL;
765 }
766
Glenn L McGrath85737042003-01-14 23:26:57 +0000767 if (buf_ptr[0] != '\0') {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000768 error_msg("too many parameters \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000769 return NULL;
770 }
771
772 currif->iface = xstrdup(iface_name);
773
774 currif->address_family = get_address_family(addr_fams, address_family_name);
775 if (!currif->address_family) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000776 error_msg("unknown address type \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000777 return NULL;
778 }
779
780 currif->method = get_method(currif->address_family, method_name);
781 if (!currif->method) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000782 error_msg("unknown method \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000783 return NULL;
784 }
785
786 currif->automatic = 1;
787 currif->max_options = 0;
788 currif->n_options = 0;
789 currif->option = NULL;
790
791
792 {
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000793 interface_defn_t **where = &defn->ifaces;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000794
795 while (*where != NULL) {
796 if (duplicate_if(*where, currif)) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000797 error_msg("duplicate interface \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000798 return NULL;
799 }
800 where = &(*where)->next;
801 }
802
803 *where = currif;
804 currif->next = NULL;
805 }
806 }
807 currently_processing = IFACE;
808 } else if (strcmp(firstword, "auto") == 0) {
Glenn L McGrath85737042003-01-14 23:26:57 +0000809 while ((firstword = next_word(&buf_ptr)) != NULL) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000810
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000811 /* Check the interface isnt already listed */
812 if (find_list_string(defn->autointerfaces, firstword)) {
813 perror_msg_and_die("interface declared auto twice \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000814 }
815
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000816 /* Add the interface to the list */
817 defn->autointerfaces = llist_add_to(defn->autointerfaces, strdup(firstword));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000818 }
819 currently_processing = NONE;
820 } else {
821 switch (currently_processing) {
822 case IFACE:
823 {
824 int i;
825
Glenn L McGrath85737042003-01-14 23:26:57 +0000826 if (xstrlen(buf_ptr) == 0) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000827 error_msg("option with empty value \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000828 return NULL;
829 }
830
831 if (strcmp(firstword, "up") != 0
832 && strcmp(firstword, "down") != 0
833 && strcmp(firstword, "pre-up") != 0
834 && strcmp(firstword, "post-down") != 0) {
835 for (i = 0; i < currif->n_options; i++) {
836 if (strcmp(currif->option[i].name, firstword) == 0) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000837 error_msg("duplicate option \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000838 return NULL;
839 }
840 }
841 }
842 }
843 if (currif->n_options >= currif->max_options) {
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000844 variable_t *opt;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000845
846 currif->max_options = currif->max_options + 10;
847 opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
848 currif->option = opt;
849 }
850 currif->option[currif->n_options].name = xstrdup(firstword);
Glenn L McGrath85737042003-01-14 23:26:57 +0000851 currif->option[currif->n_options].value = xstrdup(next_word(&buf_ptr));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000852 if (!currif->option[currif->n_options].name) {
853 perror(filename);
854 return NULL;
855 }
856 if (!currif->option[currif->n_options].value) {
857 perror(filename);
858 return NULL;
859 }
860 currif->n_options++;
861 break;
862 case MAPPING:
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000863#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000864 if (strcmp(firstword, "script") == 0) {
865 if (currmap->script != NULL) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000866 error_msg("duplicate script in mapping \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000867 return NULL;
868 } else {
Glenn L McGrath85737042003-01-14 23:26:57 +0000869 currmap->script = xstrdup(next_word(&buf_ptr));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000870 }
871 } else if (strcmp(firstword, "map") == 0) {
872 if (currmap->max_mappings == currmap->n_mappings) {
873 currmap->max_mappings = currmap->max_mappings * 2 + 1;
874 currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
875 }
Glenn L McGrath85737042003-01-14 23:26:57 +0000876 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000877 currmap->n_mappings++;
878 } else {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000879 error_msg("misplaced option \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000880 return NULL;
881 }
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000882#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000883 break;
884 case NONE:
885 default:
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000886 error_msg("misplaced option \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000887 return NULL;
888 }
889 }
Glenn L McGrath85737042003-01-14 23:26:57 +0000890 free(buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000891 }
892 if (ferror(f) != 0) {
Glenn L McGrath85737042003-01-14 23:26:57 +0000893 perror_msg_and_die("%s", filename);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000894 }
895 fclose(f);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000896
897 return defn;
898}
899
900static int check(char *str)
901{
902 return (str != NULL);
903}
904
905static char *setlocalenv(char *format, char *name, char *value)
906{
907 char *result;
908 char *here;
909 char *there;
910
911 result = xmalloc(xstrlen(format) + xstrlen(name) + xstrlen(value) + 1);
912
913 sprintf(result, format, name, value);
914
915 for (here = there = result; *there != '=' && *there; there++) {
916 if (*there == '-')
917 *there = '_';
918 if (isalpha(*there))
919 *there = toupper(*there);
920
921 if (isalnum(*there) || *there == '_') {
922 *here = *there;
923 here++;
924 }
925 }
926 memmove(here, there, xstrlen(there) + 1);
927
928 return result;
929}
930
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000931static void set_environ(interface_defn_t *iface, char *mode)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000932{
933 char **environend;
934 int i;
935 const int n_env_entries = iface->n_options + 5;
936 char **ppch;
937
938 if (environ != NULL) {
939 for (ppch = environ; *ppch; ppch++) {
940 free(*ppch);
941 *ppch = NULL;
942 }
943 free(environ);
944 environ = NULL;
945 }
946 environ = xmalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
947 environend = environ;
948 *environend = NULL;
949
950 for (i = 0; i < iface->n_options; i++) {
951 if (strcmp(iface->option[i].name, "up") == 0
952 || strcmp(iface->option[i].name, "down") == 0
953 || strcmp(iface->option[i].name, "pre-up") == 0
954 || strcmp(iface->option[i].name, "post-down") == 0) {
955 continue;
956 }
957 *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
958 *environend = NULL;
959 }
960
961 *(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
962 *environend = NULL;
963 *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
964 *environend = NULL;
965 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
966 *environend = NULL;
967 *(environend++) = setlocalenv("%s=%s", "MODE", mode);
968 *environend = NULL;
969 *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
970 *environend = NULL;
971}
972
973static int doit(char *str)
974{
975 if (verbose || no_act) {
976 error_msg("%s", str);
977 }
978 if (!no_act) {
979 pid_t child;
980 int status;
981
982 fflush(NULL);
983 switch (child = fork()) {
984 case -1: /* failure */
985 return 0;
986 case 0: /* child */
987 execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
988 exit(127);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000989 }
990 waitpid(child, &status, 0);
991 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
992 return 0;
993 }
994 }
995 return (1);
996}
997
Glenn L McGrath0325a1c2002-12-07 07:45:42 +0000998static int execute_all(interface_defn_t *ifd, execfn *exec, const char *opt)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000999{
1000 int i;
Glenn L McGrath9af8a722002-11-11 07:03:02 +00001001 char *buf;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001002
1003 for (i = 0; i < ifd->n_options; i++) {
1004 if (strcmp(ifd->option[i].name, opt) == 0) {
1005 if (!(*exec) (ifd->option[i].value)) {
1006 return 0;
1007 }
1008 }
1009 }
1010
Glenn L McGrath9af8a722002-11-11 07:03:02 +00001011 buf = xmalloc(xstrlen(opt) + 19);
1012 sprintf(buf, "/etc/network/if-%s.d", opt);
Glenn L McGrath2e51a142003-01-20 23:50:59 +00001013 run_parts(&buf, 2);
Glenn L McGrath9af8a722002-11-11 07:03:02 +00001014 free(buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001015 return (1);
1016}
1017
Glenn L McGrath0325a1c2002-12-07 07:45:42 +00001018static int iface_up(interface_defn_t *iface)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001019{
1020 if (!iface->method->up(iface, check)) {
1021 return (-1);
1022 }
1023
1024 set_environ(iface, "start");
1025 if (!execute_all(iface, doit, "pre-up")) {
1026 return (0);
1027 }
1028 if (!iface->method->up(iface, doit)) {
1029 return (0);
1030 }
1031 if (!execute_all(iface, doit, "up")) {
1032 return (0);
1033 }
1034
1035 return (1);
1036}
1037
Glenn L McGrath0325a1c2002-12-07 07:45:42 +00001038static int iface_down(interface_defn_t *iface)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001039{
1040 if (!iface->method->down(iface, check)) {
1041 return (-1);
1042 }
1043 set_environ(iface, "stop");
1044 if (!execute_all(iface, doit, "down")) {
1045 return (0);
1046 }
1047 if (!iface->method->down(iface, doit)) {
1048 return (0);
1049 }
1050 if (!execute_all(iface, doit, "post-down")) {
1051 return (0);
1052 }
1053 return (1);
1054}
1055
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001056#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001057static int popen2(FILE **in, FILE **out, char *command, ...)
1058{
1059 va_list ap;
1060 char *argv[11] = { command };
1061 int argc;
1062 int infd[2], outfd[2];
1063 pid_t pid;
1064
1065 argc = 1;
1066 va_start(ap, command);
1067 while ((argc < 10) && (argv[argc] = va_arg(ap, char *))) {
1068 argc++;
1069 }
1070 argv[argc] = NULL; /* make sure */
1071 va_end(ap);
1072
1073 if (pipe(infd) != 0) {
1074 return 0;
1075 }
1076
1077 if (pipe(outfd) != 0) {
1078 close(infd[0]);
1079 close(infd[1]);
1080 return 0;
1081 }
1082
1083 fflush(NULL);
1084 switch (pid = fork()) {
1085 case -1: /* failure */
1086 close(infd[0]);
1087 close(infd[1]);
1088 close(outfd[0]);
1089 close(outfd[1]);
1090 return 0;
1091 case 0: /* child */
1092 dup2(infd[0], 0);
1093 dup2(outfd[1], 1);
1094 close(infd[0]);
1095 close(infd[1]);
1096 close(outfd[0]);
1097 close(outfd[1]);
1098 execvp(command, argv);
1099 exit(127);
1100 default: /* parent */
1101 *in = fdopen(infd[1], "w");
1102 *out = fdopen(outfd[0], "r");
1103 close(infd[0]);
1104 close(outfd[1]);
1105 return pid;
1106 }
1107 /* unreached */
1108}
1109
Glenn L McGrath0325a1c2002-12-07 07:45:42 +00001110static int run_mapping(char *physical, char *logical, int len, mapping_defn_t * map)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001111{
1112 FILE *in, *out;
1113 int i, status;
1114 pid_t pid;
1115
1116
1117 pid = popen2(&in, &out, map->script, physical, NULL);
1118 if (pid == 0) {
1119 return 0;
1120 }
1121 for (i = 0; i < map->n_mappings; i++) {
1122 fprintf(in, "%s\n", map->mapping[i]);
1123 }
1124 fclose(in);
1125 waitpid(pid, &status, 0);
1126 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1127 if (fgets(logical, len, out)) {
1128 char *pch = logical + xstrlen(logical) - 1;
1129
1130 while (pch >= logical && isspace(*pch))
1131 *(pch--) = '\0';
1132 }
1133 }
1134 fclose(out);
1135
1136 return 1;
1137}
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001138#endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001139
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001140static llist_t *find_iface_state(llist_t *state_list, const char *iface)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001141{
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001142 unsigned short iface_len = xstrlen(iface);
1143 llist_t *search = state_list;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001144
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001145 while (search) {
1146 if ((strncmp(search->data, iface, iface_len) == 0) &&
1147 (search->data[iface_len] == '=')) {
1148 return(search);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001149 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001150 search = search->link;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001151 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001152 return(NULL);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001153}
1154
1155extern int ifupdown_main(int argc, char **argv)
1156{
Glenn L McGrath0325a1c2002-12-07 07:45:42 +00001157 int (*cmds) (interface_defn_t *) = NULL;
1158 interfaces_file_t *defn;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001159 FILE *state_fp = NULL;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001160 llist_t *state_list = NULL;
1161 llist_t *target_list = NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001162 char *interfaces = "/etc/network/interfaces";
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001163 const char *statefile = "/var/run/ifstate";
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001164
Glenn L McGrath398ff9d2002-12-06 11:51:46 +00001165#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001166 int run_mappings = 1;
Glenn L McGrath398ff9d2002-12-06 11:51:46 +00001167#endif
1168 int do_all = 0;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001169 int force = 0;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001170 int i;
1171
1172 if (applet_name[2] == 'u') {
1173 /* ifup command */
1174 cmds = iface_up;
1175 } else {
1176 /* ifdown command */
1177 cmds = iface_down;
1178 }
1179
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001180#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001181 while ((i = getopt(argc, argv, "i:hvnamf")) != -1) {
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001182#else
1183 while ((i = getopt(argc, argv, "i:hvnaf")) != -1) {
1184#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001185 switch (i) {
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001186 case 'i': /* interfaces */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001187 interfaces = xstrdup(optarg);
1188 break;
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001189 case 'v': /* verbose */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001190 verbose = 1;
1191 break;
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001192 case 'a': /* all */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001193 do_all = 1;
1194 break;
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001195 case 'n': /* no-act */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001196 no_act = 1;
1197 break;
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001198#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001199 case 'm': /* no-mappings */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001200 run_mappings = 0;
1201 break;
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001202#endif
Glenn L McGrath49a28b32002-11-10 13:17:08 +00001203 case 'f': /* force */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001204 force = 1;
1205 break;
1206 default:
1207 show_usage();
1208 break;
1209 }
1210 }
1211
1212 if (argc - optind > 0) {
1213 if (do_all) {
1214 show_usage();
1215 }
1216 } else {
1217 if (!do_all) {
1218 show_usage();
1219 }
1220 }
1221
1222 defn = read_interfaces(interfaces);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001223
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001224 if (no_act) {
1225 state_fp = fopen(statefile, "r");
1226 } else {
1227 state_fp = xfopen(statefile, "a+");
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001228 }
1229
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001230 /* Read the previous state from the state file */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001231 if (state_fp != NULL) {
Glenn L McGrath398ff9d2002-12-06 11:51:46 +00001232 char *start;
1233 while ((start = get_line_from_file(state_fp)) != NULL) {
1234 char *end_ptr;
1235 /* We should only need to check for a single character */
1236 end_ptr = start + strcspn(start, " \t\n");
1237 *end_ptr = '\0';
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001238 state_list = llist_add_to(state_list, start);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001239 }
1240 }
1241
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001242 /* Create a list of interfaces to work on */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001243 if (do_all) {
1244 if (cmds == iface_up) {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001245 target_list = defn->autointerfaces;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001246 } else if (cmds == iface_down) {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001247 const llist_t *list = state_list;
1248 while (list) {
1249 target_list = llist_add_to(target_list, strdup(list->data));
1250 list = list->link;
1251 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001252 }
1253 } else {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001254 target_list = llist_add_to(target_list, argv[optind]);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001255 }
1256
1257
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001258 /* Update the interfaces */
1259 while (target_list) {
Glenn L McGrath0325a1c2002-12-07 07:45:42 +00001260 interface_defn_t *currif;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001261 char *iface;
1262 char *liface;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001263 char *pch;
1264 int okay = 0;
1265
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001266 iface = strdup(target_list->data);
1267 target_list = target_list->link;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001268
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001269 pch = strchr(iface, '=');
1270 if (pch) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001271 *pch = '\0';
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001272 liface = strdup(pch + 1);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001273 } else {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001274 liface = strdup(iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001275 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001276
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001277 if (!force) {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001278 const llist_t *iface_state = find_iface_state(state_list, iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001279
1280 if (cmds == iface_up) {
1281 /* ifup */
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001282 if (iface_state) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001283 error_msg("interface %s already configured", iface);
1284 continue;
1285 }
1286 } else {
1287 /* ifdown */
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001288 if (iface_state == NULL) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001289 error_msg("interface %s not configured", iface);
1290 continue;
1291 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001292 pch = strchr(iface_state->data, '=');
1293 liface = strdup(pch + 1);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001294 }
1295 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001296
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001297#ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001298 if ((cmds == iface_up) && run_mappings) {
Glenn L McGrath0325a1c2002-12-07 07:45:42 +00001299 mapping_defn_t *currmap;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001300
1301 for (currmap = defn->mappings; currmap; currmap = currmap->next) {
1302
1303 for (i = 0; i < currmap->n_matches; i++) {
1304 if (fnmatch(currmap->match[i], liface, 0) != 0)
1305 continue;
1306 if (verbose) {
1307 error_msg("Running mapping script %s on %s", currmap->script, liface);
1308 }
1309 run_mapping(iface, liface, sizeof(liface), currmap);
1310 break;
1311 }
1312 }
1313 }
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001314#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001315
1316 for (currif = defn->ifaces; currif; currif = currif->next) {
1317 if (strcmp(liface, currif->iface) == 0) {
1318 char *oldiface = currif->iface;
1319
1320 okay = 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001321 currif->iface = iface;
1322
1323 if (verbose) {
1324 error_msg("Configuring interface %s=%s (%s)", iface, liface, currif->address_family->name);
1325 }
1326
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001327 /* Call the cmds function pointer, does either iface_up() or iface_down() */
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001328 if (cmds(currif) == -1) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001329 printf
1330 ("Don't seem to be have all the variables for %s/%s.\n",
1331 liface, currif->address_family->name);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001332 }
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001333
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001334 currif->iface = oldiface;
1335 }
1336 }
1337
1338 if (!okay && !force) {
1339 error_msg("Ignoring unknown interface %s=%s.", iface, liface);
1340 } else {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001341 llist_t *iface_state = find_iface_state(state_list, iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001342
1343 if (cmds == iface_up) {
1344 char *newiface = xmalloc(xstrlen(iface) + 1 + xstrlen(liface) + 1);
1345 sprintf(newiface, "%s=%s", iface, liface);
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001346 if (iface_state == NULL) {
1347 state_list = llist_add_to(state_list, newiface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001348 } else {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001349 free(iface_state->data);
1350 iface_state->data = newiface;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001351 }
1352 } else if (cmds == iface_down) {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001353 /* Remove an interface from the linked list */
1354 if (iface_state) {
1355 /* This needs to be done better */
1356 free(iface_state->data);
1357 free(iface_state->link);
1358 if (iface_state->link) {
1359 iface_state->data = iface_state->link->data;
1360 iface_state->link = iface_state->link->link;
1361 } else {
1362 iface_state->data = NULL;
1363 iface_state->link = NULL;
1364 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001365 }
1366 }
1367 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001368 }
1369
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001370 /* Actually write the new state */
1371 if (state_fp != NULL && !no_act) {
1372 if (ftruncate(fileno(state_fp), 0) < 0) {
1373 error_msg_and_die("failed to truncate statefile %s: %s", statefile, strerror(errno));
1374 }
1375
1376 rewind(state_fp);
1377
1378 while (state_list) {
1379 if (state_list->data) {
1380 fputs(state_list->data, state_fp);
1381 fputc('\n', state_fp);
1382 }
1383 state_list = state_list->link;
1384 }
1385 fflush(state_fp);
1386 }
1387
1388 /* Cleanup */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001389 if (state_fp != NULL) {
1390 fclose(state_fp);
1391 state_fp = NULL;
1392 }
1393
1394 return 0;
1395}