blob: c4d72524dc664edacfac3d71d96cce972b4441d9 [file] [log] [blame]
Eric Andersen8320b422003-04-02 10:13:26 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00002/*
3 * ifupdown for busybox
Denis Vlasenko0beaff82007-09-21 13:16:32 +00004 * Copyright (c) 2002 Glenn McGrath
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00006 *
7 * Based on ifupdown v 0.6.4 by Anthony Towns
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00008 * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au>
9 *
Glenn L McGrath398ff9d2002-12-06 11:51:46 +000010 * Changes to upstream version
Glenn L McGrath8e49caa2002-12-08 01:23:39 +000011 * Remove checks for kernel version, assume kernel version 2.2.0 or better.
Glenn L McGrath398ff9d2002-12-06 11:51:46 +000012 * Lines in the interfaces file cannot wrap.
Denis Vlasenko2a86a612007-07-19 21:49:30 +000013 * To adhere to the FHS, the default state file is /var/run/ifstate
14 * (defined via CONFIG_IFUPDOWN_IFSTATE_PATH) and can be overridden by build
15 * configuration.
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000016 *
Rob Landley1b751c82005-10-28 09:24:33 +000017 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000018 */
19
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000020#include <sys/utsname.h>
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000021#include <fnmatch.h>
22#include <getopt.h>
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000023
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000024#include "libbb.h"
25
Glenn L McGrath8e49caa2002-12-08 01:23:39 +000026#define MAX_OPT_DEPTH 10
27#define EUNBALBRACK 10001
28#define EUNDEFVAR 10002
29#define EUNBALPER 10000
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000030
Denis Vlasenkofcfe8342006-12-18 21:02:00 +000031#if ENABLE_FEATURE_IFUPDOWN_MAPPING
Eric Andersen233b1702003-06-05 19:37:01 +000032#define MAX_INTERFACE_LENGTH 10
33#endif
Eric Andersen8320b422003-04-02 10:13:26 +000034
Denis Vlasenkofcfe8342006-12-18 21:02:00 +000035#define debug_noise(args...) /*fprintf(stderr, args)*/
Eric Andersen8320b422003-04-02 10:13:26 +000036
37/* Forward declaration */
38struct interface_defn_t;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000039
Denis Vlasenko097c3242006-11-27 16:59:15 +000040typedef int execfn(char *command);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000041
Denis Vlasenko89ef65f2007-01-29 23:43:18 +000042struct method_t {
43 const char *name;
Rob Landleye813ddb2006-02-28 03:53:14 +000044 int (*up)(struct interface_defn_t *ifd, execfn *e);
45 int (*down)(struct interface_defn_t *ifd, execfn *e);
Eric Andersen8320b422003-04-02 10:13:26 +000046};
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000047
Denis Vlasenko89ef65f2007-01-29 23:43:18 +000048struct address_family_t {
49 const char *name;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000050 int n_methods;
Denis Vlasenko05341252006-09-26 20:35:30 +000051 const struct method_t *method;
Eric Andersen8320b422003-04-02 10:13:26 +000052};
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000053
Denis Vlasenko89ef65f2007-01-29 23:43:18 +000054struct mapping_defn_t {
Eric Andersen8320b422003-04-02 10:13:26 +000055 struct mapping_defn_t *next;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000056
57 int max_matches;
58 int n_matches;
59 char **match;
60
61 char *script;
62
63 int max_mappings;
64 int n_mappings;
65 char **mapping;
Eric Andersen8320b422003-04-02 10:13:26 +000066};
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000067
Denis Vlasenko89ef65f2007-01-29 23:43:18 +000068struct variable_t {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000069 char *name;
70 char *value;
Eric Andersen8320b422003-04-02 10:13:26 +000071};
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000072
Denis Vlasenko89ef65f2007-01-29 23:43:18 +000073struct interface_defn_t {
Denis Vlasenko05341252006-09-26 20:35:30 +000074 const struct address_family_t *address_family;
75 const struct method_t *method;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000076
Rob Landleye813ddb2006-02-28 03:53:14 +000077 char *iface;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000078 int max_options;
79 int n_options;
Eric Andersen8320b422003-04-02 10:13:26 +000080 struct variable_t *option;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000081};
82
Denis Vlasenko89ef65f2007-01-29 23:43:18 +000083struct interfaces_file_t {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +000084 llist_t *autointerfaces;
Eric Andersen8320b422003-04-02 10:13:26 +000085 llist_t *ifaces;
86 struct mapping_defn_t *mappings;
87};
Glenn L McGrath021fa7d2002-11-09 09:34:15 +000088
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +000089#define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:"
90enum {
91 OPT_do_all = 0x1,
92 OPT_no_act = 0x2,
93 OPT_verbose = 0x4,
94 OPT_force = 0x8,
95 OPT_no_mappings = 0x10,
96};
Denis Vlasenkoc12f5302006-10-06 09:49:47 +000097#define DO_ALL (option_mask32 & OPT_do_all)
98#define NO_ACT (option_mask32 & OPT_no_act)
99#define VERBOSE (option_mask32 & OPT_verbose)
100#define FORCE (option_mask32 & OPT_force)
101#define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +0000102
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000103static char **my_environ;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000104
Denis Vlasenko89ef65f2007-01-29 23:43:18 +0000105static const char *startup_PATH;
Denis Vlasenko2f4399c2006-09-27 14:14:51 +0000106
Mike Frysingerb049c0e2006-06-20 23:03:27 +0000107#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
108
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000109static void addstr(char **bufp, const char *str, size_t str_length)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000110{
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000111 /* xasprintf trick will be smaller, but we are often
112 * called with str_length == 1 - don't want to have
113 * THAT much of malloc/freeing! */
114 char *buf = *bufp;
115 int len = (buf ? strlen(buf) : 0);
116 str_length++;
117 buf = xrealloc(buf, len + str_length);
118 /* copies at most str_length-1 chars! */
119 safe_strncpy(buf + len, str, str_length);
120 *bufp = buf;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000121}
122
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000123static int strncmpz(const char *l, const char *r, size_t llen)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000124{
125 int i = strncmp(l, r, llen);
126
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000127 if (i == 0)
Denis Vlasenko05341252006-09-26 20:35:30 +0000128 return -r[llen];
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000129 return i;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000130}
131
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000132static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000133{
134 int i;
135
136 if (strncmpz(id, "iface", idlen) == 0) {
Eric Andersen8320b422003-04-02 10:13:26 +0000137 char *result;
138 static char label_buf[20];
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000139 safe_strncpy(label_buf, ifd->iface, sizeof(label_buf));
Eric Andersen8320b422003-04-02 10:13:26 +0000140 result = strchr(label_buf, ':');
141 if (result) {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000142 *result = '\0';
Eric Andersen8320b422003-04-02 10:13:26 +0000143 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000144 return label_buf;
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000145 }
146 if (strncmpz(id, "label", idlen) == 0) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000147 return ifd->iface;
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000148 }
149 for (i = 0; i < ifd->n_options; i++) {
150 if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
151 return ifd->option[i].value;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000152 }
153 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000154 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000155}
156
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000157#if ENABLE_FEATURE_IFUPDOWN_IP
158static int count_netmask_bits(const char *dotted_quad)
159{
160// int result;
161// unsigned a, b, c, d;
162// /* Found a netmask... Check if it is dotted quad */
163// if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
164// return -1;
165// if ((a|b|c|d) >> 8)
166// return -1; /* one of numbers is >= 256 */
167// d |= (a << 24) | (b << 16) | (c << 8); /* IP */
168// d = ~d; /* 11110000 -> 00001111 */
169
170 /* Shorter version */
171 int result;
172 struct in_addr ip;
173 unsigned d;
174
175 if (inet_aton(dotted_quad, &ip) == 0)
176 return -1; /* malformed dotted IP */
177 d = ntohl(ip.s_addr); /* IP in host order */
178 d = ~d; /* 11110000 -> 00001111 */
179 if (d & (d+1)) /* check that it is in 00001111 form */
180 return -1; /* no it is not */
181 result = 32;
182 while (d) {
183 d >>= 1;
184 result--;
185 }
186 return result;
187}
188#endif
189
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000190static char *parse(const char *command, struct interface_defn_t *ifd)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000191{
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000192 size_t old_pos[MAX_OPT_DEPTH] = { 0 };
193 int okay[MAX_OPT_DEPTH] = { 1 };
194 int opt_depth = 1;
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000195 char *result = NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000196
197 while (*command) {
198 switch (*command) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000199 default:
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000200 addstr(&result, command, 1);
Denis Vlasenko05341252006-09-26 20:35:30 +0000201 command++;
202 break;
203 case '\\':
204 if (command[1]) {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000205 addstr(&result, command + 1, 1);
Denis Vlasenko05341252006-09-26 20:35:30 +0000206 command += 2;
207 } else {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000208 addstr(&result, command, 1);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000209 command++;
Denis Vlasenko05341252006-09-26 20:35:30 +0000210 }
211 break;
212 case '[':
213 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000214 old_pos[opt_depth] = result ? strlen(result) : 0;
Denis Vlasenko05341252006-09-26 20:35:30 +0000215 okay[opt_depth] = 1;
216 opt_depth++;
217 command += 2;
218 } else {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000219 addstr(&result, "[", 1);
Denis Vlasenko05341252006-09-26 20:35:30 +0000220 command++;
221 }
222 break;
223 case ']':
224 if (command[1] == ']' && opt_depth > 1) {
225 opt_depth--;
226 if (!okay[opt_depth]) {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000227 result[old_pos[opt_depth]] = '\0';
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000228 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000229 command += 2;
230 } else {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000231 addstr(&result, "]", 1);
Denis Vlasenko05341252006-09-26 20:35:30 +0000232 command++;
233 }
234 break;
235 case '%':
236 {
237 char *nextpercent;
238 char *varvalue;
239
240 command++;
241 nextpercent = strchr(command, '%');
242 if (!nextpercent) {
243 errno = EUNBALPER;
244 free(result);
245 return NULL;
Eric Andersen8320b422003-04-02 10:13:26 +0000246 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000247
248 varvalue = get_var(command, nextpercent - command, ifd);
249
250 if (varvalue) {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000251 addstr(&result, varvalue, strlen(varvalue));
Eric Andersen8320b422003-04-02 10:13:26 +0000252 } else {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000253#if ENABLE_FEATURE_IFUPDOWN_IP
Denis Vlasenko05341252006-09-26 20:35:30 +0000254 /* Sigh... Add a special case for 'ip' to convert from
255 * dotted quad to bit count style netmasks. */
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000256 if (strncmp(command, "bnmask", 6) == 0) {
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000257 unsigned res;
Denis Vlasenko05341252006-09-26 20:35:30 +0000258 varvalue = get_var("netmask", 7, ifd);
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000259 if (varvalue) {
260 res = count_netmask_bits(varvalue);
261 if (res > 0) {
262 const char *argument = utoa(res);
263 addstr(&result, argument, strlen(argument));
264 command = nextpercent + 1;
265 break;
266 }
Eric Andersen8320b422003-04-02 10:13:26 +0000267 }
Eric Andersen8320b422003-04-02 10:13:26 +0000268 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000269#endif
270 okay[opt_depth - 1] = 0;
Eric Andersen8320b422003-04-02 10:13:26 +0000271 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000272
273 command = nextpercent + 1;
274 }
275 break;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000276 }
277 }
278
279 if (opt_depth > 1) {
280 errno = EUNBALBRACK;
281 free(result);
Denis Vlasenko05341252006-09-26 20:35:30 +0000282 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000283 }
284
285 if (!okay[0]) {
286 errno = EUNDEFVAR;
287 free(result);
Denis Vlasenko05341252006-09-26 20:35:30 +0000288 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000289 }
290
Denis Vlasenko05341252006-09-26 20:35:30 +0000291 return result;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000292}
293
Denis Vlasenko05341252006-09-26 20:35:30 +0000294/* execute() returns 1 for success and 0 for failure */
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000295static int execute(const char *command, struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000296{
297 char *out;
298 int ret;
299
300 out = parse(command, ifd);
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000301 if (!out) {
Denis Vlasenko2375d752006-12-19 23:15:46 +0000302 /* parse error? */
Denis Vlasenko05341252006-09-26 20:35:30 +0000303 return 0;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000304 }
Denis Vlasenko2375d752006-12-19 23:15:46 +0000305 /* out == "": parsed ok but not all needed variables known, skip */
306 ret = out[0] ? (*exec)(out) : 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000307
308 free(out);
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000309 if (ret != 1) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000310 return 0;
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000311 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000312 return 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000313}
Bernhard Reutner-Fischerd42ef282005-12-14 14:13:15 +0000314#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000315
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000316#if ENABLE_FEATURE_IFUPDOWN_IPV6
Eric Andersen8320b422003-04-02 10:13:26 +0000317static int loopback_up6(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000318{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000319#if ENABLE_FEATURE_IFUPDOWN_IP
Eric Andersen8320b422003-04-02 10:13:26 +0000320 int result;
Denis Vlasenko05341252006-09-26 20:35:30 +0000321 result = execute("ip addr add ::1 dev %iface%", ifd, exec);
Eric Andersen8a931792003-07-03 10:20:29 +0000322 result += execute("ip link set %iface% up", ifd, exec);
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000323 return ((result == 2) ? 2 : 0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000324#else
Denis Vlasenko05341252006-09-26 20:35:30 +0000325 return execute("ifconfig %iface% add ::1", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000326#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000327}
328
Eric Andersen8320b422003-04-02 10:13:26 +0000329static int loopback_down6(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000330{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000331#if ENABLE_FEATURE_IFUPDOWN_IP
Denis Vlasenko05341252006-09-26 20:35:30 +0000332 return execute("ip link set %iface% down", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000333#else
Denis Vlasenko05341252006-09-26 20:35:30 +0000334 return execute("ifconfig %iface% del ::1", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000335#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000336}
337
Eric Andersen8320b422003-04-02 10:13:26 +0000338static int static_up6(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000339{
Eric Andersen8320b422003-04-02 10:13:26 +0000340 int result;
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000341#if ENABLE_FEATURE_IFUPDOWN_IP
342 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
343 result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
344 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
345 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000346#else
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000347 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
Eric Andersen8320b422003-04-02 10:13:26 +0000348 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000349 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000350#endif
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000351 return ((result == 3) ? 3 : 0);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000352}
353
Eric Andersen8320b422003-04-02 10:13:26 +0000354static int static_down6(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000355{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000356#if ENABLE_FEATURE_IFUPDOWN_IP
Denis Vlasenko05341252006-09-26 20:35:30 +0000357 return execute("ip link set %iface% down", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000358#else
Denis Vlasenko05341252006-09-26 20:35:30 +0000359 return execute("ifconfig %iface% down", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000360#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000361}
362
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000363#if ENABLE_FEATURE_IFUPDOWN_IP
Eric Andersen8320b422003-04-02 10:13:26 +0000364static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000365{
Eric Andersen8320b422003-04-02 10:13:26 +0000366 int result;
367 result = execute("ip tunnel add %iface% mode sit remote "
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000368 "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd, exec);
Eric Andersen8a931792003-07-03 10:20:29 +0000369 result += execute("ip link set %iface% up", ifd, exec);
Glenn L McGrath62b031f2003-08-29 07:47:52 +0000370 result += execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec);
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000371 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000372 return ((result == 4) ? 4 : 0);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000373}
374
Eric Andersen8320b422003-04-02 10:13:26 +0000375static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000376{
Denis Vlasenko05341252006-09-26 20:35:30 +0000377 return execute("ip tunnel del %iface%", ifd, exec);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000378}
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000379#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000380
Denis Vlasenko05341252006-09-26 20:35:30 +0000381static const struct method_t methods6[] = {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000382#if ENABLE_FEATURE_IFUPDOWN_IP
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000383 { "v4tunnel", v4tunnel_up, v4tunnel_down, },
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000384#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000385 { "static", static_up6, static_down6, },
386 { "loopback", loopback_up6, loopback_down6, },
387};
388
Denis Vlasenko05341252006-09-26 20:35:30 +0000389static const struct address_family_t addr_inet6 = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000390 "inet6",
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000391 ARRAY_SIZE(methods6),
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000392 methods6
393};
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000394#endif /* FEATURE_IFUPDOWN_IPV6 */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000395
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000396#if ENABLE_FEATURE_IFUPDOWN_IPV4
Eric Andersen8320b422003-04-02 10:13:26 +0000397static int loopback_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000398{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000399#if ENABLE_FEATURE_IFUPDOWN_IP
Eric Andersen8320b422003-04-02 10:13:26 +0000400 int result;
Eric Andersenfdd2a0f2003-08-06 09:23:44 +0000401 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
Eric Andersen8a931792003-07-03 10:20:29 +0000402 result += execute("ip link set %iface% up", ifd, exec);
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000403 return ((result == 2) ? 2 : 0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000404#else
Denis Vlasenko05341252006-09-26 20:35:30 +0000405 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000406#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000407}
408
Eric Andersen8320b422003-04-02 10:13:26 +0000409static int loopback_down(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000410{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000411#if ENABLE_FEATURE_IFUPDOWN_IP
Eric Andersen8320b422003-04-02 10:13:26 +0000412 int result;
413 result = execute("ip addr flush dev %iface%", ifd, exec);
414 result += execute("ip link set %iface% down", ifd, exec);
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000415 return ((result == 2) ? 2 : 0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000416#else
Denis Vlasenko05341252006-09-26 20:35:30 +0000417 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000418#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000419}
420
Eric Andersen8320b422003-04-02 10:13:26 +0000421static int static_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000422{
Eric Andersen8320b422003-04-02 10:13:26 +0000423 int result;
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000424#if ENABLE_FEATURE_IFUPDOWN_IP
425 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
426 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
427 result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
428 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000429 return ((result == 3) ? 3 : 0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000430#else
Denis Vlasenkoa741b772006-11-23 15:08:37 +0000431 /* ifconfig said to set iface up before it processes hw %hwaddress%,
432 * which then of course fails. Thus we run two separate ifconfig */
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000433 result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
Denis Vlasenkoa741b772006-11-23 15:08:37 +0000434 ifd, exec);
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000435 result += execute("ifconfig %iface% %address% netmask %netmask%"
436 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
Denis Vlasenkoa741b772006-11-23 15:08:37 +0000437 ifd, exec);
Denis Vlasenko8e858e22007-03-07 09:35:43 +0000438 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
Denis Vlasenkoa741b772006-11-23 15:08:37 +0000439 return ((result == 3) ? 3 : 0);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000440#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000441}
442
Eric Andersen8320b422003-04-02 10:13:26 +0000443static int static_down(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000444{
Eric Andersen8320b422003-04-02 10:13:26 +0000445 int result;
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000446#if ENABLE_FEATURE_IFUPDOWN_IP
Eric Andersen8320b422003-04-02 10:13:26 +0000447 result = execute("ip addr flush dev %iface%", ifd, exec);
448 result += execute("ip link set %iface% down", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000449#else
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000450 result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec);
Eric Andersen8320b422003-04-02 10:13:26 +0000451 result += execute("ifconfig %iface% down", ifd, exec);
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000452#endif
Glenn L McGrath0177ce12004-07-21 23:56:31 +0000453 return ((result == 2) ? 2 : 0);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000454}
455
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000456#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000457struct dhcp_client_t
458{
459 const char *name;
460 const char *startcmd;
461 const char *stopcmd;
462};
463
464static const struct dhcp_client_t ext_dhcp_clients[] = {
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000465 { "dhcpcd",
466 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",
467 "dhcpcd -k %iface%",
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000468 },
469 { "dhclient",
470 "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
471 "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
472 },
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000473 { "pump",
474 "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
475 "pump -i %iface% -k",
476 },
477 { "udhcpc",
478 "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000479 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000480 },
481};
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000482#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000483
Eric Andersen8320b422003-04-02 10:13:26 +0000484static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000485{
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000486#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
Denis Vlasenko856be772007-08-17 08:29:48 +0000487 int i;
Denis Vlasenko6cd84da2007-07-21 14:57:54 +0000488#if ENABLE_FEATURE_IFUPDOWN_IP
489 /* ip doesn't up iface when it configures it (unlike ifconfig) */
490 if (!execute("ip link set %iface% up", ifd, exec))
491 return 0;
492#endif
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000493 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000494 if (exists_execable(ext_dhcp_clients[i].name))
495 return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
496 }
497 bb_error_msg("no dhcp clients found");
Denis Vlasenko2f4399c2006-09-27 14:14:51 +0000498 return 0;
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000499#elif ENABLE_APP_UDHCPC
Denis Vlasenko6cd84da2007-07-21 14:57:54 +0000500#if ENABLE_FEATURE_IFUPDOWN_IP
501 /* ip doesn't up iface when it configures it (unlike ifconfig) */
502 if (!execute("ip link set %iface% up", ifd, exec))
503 return 0;
504#endif
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000505 return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid "
506 "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
507 ifd, exec);
508#else
509 return 0; /* no dhcp support */
Denis Vlasenko4b924f32007-05-30 00:29:55 +0000510#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000511}
512
Eric Andersen8320b422003-04-02 10:13:26 +0000513static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000514{
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000515#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
Denis Vlasenko6cd84da2007-07-21 14:57:54 +0000516 int i;
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000517 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000518 if (exists_execable(ext_dhcp_clients[i].name))
519 return execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
520 }
521 bb_error_msg("no dhcp clients found, using static interface shutdown");
Denis Vlasenko2f4399c2006-09-27 14:14:51 +0000522 return static_down(ifd, exec);
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000523#elif ENABLE_APP_UDHCPC
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000524 return execute("kill "
Denis Vlasenkoeda43d72007-05-02 22:04:38 +0000525 "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
526#else
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000527 return 0; /* no dhcp support */
Denis Vlasenkof6f43df2006-10-11 22:16:56 +0000528#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000529}
530
Denis Vlasenko1c3577f2006-10-02 20:57:10 +0000531static int manual_up_down(struct interface_defn_t *ifd, execfn *exec)
532{
533 return 1;
534}
535
Eric Andersen8320b422003-04-02 10:13:26 +0000536static int bootp_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000537{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000538 return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
Denis Vlasenko1caca342007-08-02 10:14:29 +0000539 "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
540 " --returniffail --serverbcast", ifd, exec);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000541}
542
Eric Andersen8320b422003-04-02 10:13:26 +0000543static int ppp_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000544{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000545 return execute("pon[[ %provider%]]", ifd, exec);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000546}
547
Eric Andersen8320b422003-04-02 10:13:26 +0000548static int ppp_down(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000549{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000550 return execute("poff[[ %provider%]]", ifd, exec);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000551}
552
Eric Andersen8320b422003-04-02 10:13:26 +0000553static int wvdial_up(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000554{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000555 return execute("start-stop-daemon --start -x wvdial "
556 "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd, exec);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000557}
558
Eric Andersen8320b422003-04-02 10:13:26 +0000559static int wvdial_down(struct interface_defn_t *ifd, execfn *exec)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000560{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000561 return execute("start-stop-daemon --stop -x wvdial "
Denis Vlasenko05341252006-09-26 20:35:30 +0000562 "-p /var/run/wvdial.%iface% -s 2", ifd, exec);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000563}
564
Denis Vlasenko05341252006-09-26 20:35:30 +0000565static const struct method_t methods[] = {
Denis Vlasenko1c3577f2006-10-02 20:57:10 +0000566 { "manual", manual_up_down, manual_up_down, },
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000567 { "wvdial", wvdial_up, wvdial_down, },
568 { "ppp", ppp_up, ppp_down, },
569 { "static", static_up, static_down, },
Eric Andersen373bc1e2004-07-30 14:31:01 +0000570 { "bootp", bootp_up, static_down, },
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000571 { "dhcp", dhcp_up, dhcp_down, },
572 { "loopback", loopback_up, loopback_down, },
573};
574
Denis Vlasenko05341252006-09-26 20:35:30 +0000575static const struct address_family_t addr_inet = {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000576 "inet",
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000577 ARRAY_SIZE(methods),
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000578 methods
579};
580
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000581#endif /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000582
Glenn L McGrath85737042003-01-14 23:26:57 +0000583static char *next_word(char **buf)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000584{
Glenn L McGrath85737042003-01-14 23:26:57 +0000585 unsigned short length;
586 char *word;
587
Denis Vlasenko93ad1c22006-11-23 15:07:38 +0000588 if (!buf || !*buf || !**buf) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000589 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000590 }
591
Glenn L McGrath85737042003-01-14 23:26:57 +0000592 /* Skip over leading whitespace */
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000593 word = skip_whitespace(*buf);
Eric Andersen3c8bca32003-06-20 10:02:29 +0000594
595 /* Skip over comments */
596 if (*word == '#') {
Denis Vlasenko05341252006-09-26 20:35:30 +0000597 return NULL;
Eric Andersen3c8bca32003-06-20 10:02:29 +0000598 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000599
Glenn L McGrath85737042003-01-14 23:26:57 +0000600 /* Find the length of this word */
601 length = strcspn(word, " \t\n");
602 if (length == 0) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000603 return NULL;
Glenn L McGrath85737042003-01-14 23:26:57 +0000604 }
605 *buf = word + length;
Eric Andersen28942662003-04-19 23:15:06 +0000606 /*DBU:[dave@cray.com] if we are already at EOL dont't increment beyond it */
607 if (**buf) {
608 **buf = '\0';
609 (*buf)++;
610 }
Glenn L McGrath85737042003-01-14 23:26:57 +0000611
612 return word;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000613}
614
Denis Vlasenko05341252006-09-26 20:35:30 +0000615static const struct address_family_t *get_address_family(const struct address_family_t *const af[], char *name)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000616{
617 int i;
618
Denis Vlasenko736230e2006-11-20 19:40:36 +0000619 if (!name)
620 return NULL;
621
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000622 for (i = 0; af[i]; i++) {
623 if (strcmp(af[i]->name, name) == 0) {
624 return af[i];
625 }
626 }
627 return NULL;
628}
629
Denis Vlasenko05341252006-09-26 20:35:30 +0000630static const struct method_t *get_method(const struct address_family_t *af, char *name)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000631{
632 int i;
633
Denis Vlasenko736230e2006-11-20 19:40:36 +0000634 if (!name)
635 return NULL;
Bernhard Reutner-Fischere747f622007-10-06 20:47:53 +0000636 /* TODO: use index_in_str_array() */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000637 for (i = 0; i < af->n_methods; i++) {
638 if (strcmp(af->method[i].name, name) == 0) {
639 return &af->method[i];
640 }
641 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000642 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000643}
644
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000645static const llist_t *find_list_string(const llist_t *list, const char *string)
646{
Denis Vlasenko736230e2006-11-20 19:40:36 +0000647 if (string == NULL)
648 return NULL;
649
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000650 while (list) {
651 if (strcmp(list->data, string) == 0) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000652 return list;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000653 }
654 list = list->link;
655 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000656 return NULL;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000657}
658
Glenn L McGrathd4004ee2004-09-14 17:24:59 +0000659static struct interfaces_file_t *read_interfaces(const char *filename)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000660{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000661#if ENABLE_FEATURE_IFUPDOWN_MAPPING
Eric Andersen8320b422003-04-02 10:13:26 +0000662 struct mapping_defn_t *currmap = NULL;
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000663#endif
Eric Andersen8320b422003-04-02 10:13:26 +0000664 struct interface_defn_t *currif = NULL;
665 struct interfaces_file_t *defn;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000666 FILE *f;
Glenn L McGrath85737042003-01-14 23:26:57 +0000667 char *firstword;
668 char *buf;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000669
670 enum { NONE, IFACE, MAPPING } currently_processing = NONE;
671
Rob Landleya6e131d2006-05-29 06:43:55 +0000672 defn = xzalloc(sizeof(struct interfaces_file_t));
Glenn L McGrath85737042003-01-14 23:26:57 +0000673
Rob Landleyd921b2e2006-08-03 15:41:12 +0000674 f = xfopen(filename, "r");
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000675
Denis Vlasenko2d5ca602006-10-12 22:43:20 +0000676 while ((buf = xmalloc_getline(f)) != NULL) {
Glenn L McGrath85737042003-01-14 23:26:57 +0000677 char *buf_ptr = buf;
Glenn L McGrath398ff9d2002-12-06 11:51:46 +0000678
Glenn L McGrath85737042003-01-14 23:26:57 +0000679 firstword = next_word(&buf_ptr);
680 if (firstword == NULL) {
Eric Andersen3c8bca32003-06-20 10:02:29 +0000681 free(buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000682 continue; /* blank line */
683 }
684
685 if (strcmp(firstword, "mapping") == 0) {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000686#if ENABLE_FEATURE_IFUPDOWN_MAPPING
Rob Landleya6e131d2006-05-29 06:43:55 +0000687 currmap = xzalloc(sizeof(struct mapping_defn_t));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000688
Glenn L McGrath85737042003-01-14 23:26:57 +0000689 while ((firstword = next_word(&buf_ptr)) != NULL) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000690 if (currmap->max_matches == currmap->n_matches) {
691 currmap->max_matches = currmap->max_matches * 2 + 1;
692 currmap->match = xrealloc(currmap->match, sizeof(currmap->match) * currmap->max_matches);
693 }
694
Rob Landleyd921b2e2006-08-03 15:41:12 +0000695 currmap->match[currmap->n_matches++] = xstrdup(firstword);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000696 }
697 currmap->max_mappings = 0;
698 currmap->n_mappings = 0;
699 currmap->mapping = NULL;
700 currmap->script = NULL;
701 {
Eric Andersen8320b422003-04-02 10:13:26 +0000702 struct mapping_defn_t **where = &defn->mappings;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000703 while (*where != NULL) {
704 where = &(*where)->next;
705 }
706 *where = currmap;
707 currmap->next = NULL;
708 }
Eric Andersen8320b422003-04-02 10:13:26 +0000709 debug_noise("Added mapping\n");
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +0000710#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000711 currently_processing = MAPPING;
712 } else if (strcmp(firstword, "iface") == 0) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000713 static const struct address_family_t *const addr_fams[] = {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000714#if ENABLE_FEATURE_IFUPDOWN_IPV4
Denis Vlasenko05341252006-09-26 20:35:30 +0000715 &addr_inet,
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000716#endif
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000717#if ENABLE_FEATURE_IFUPDOWN_IPV6
Denis Vlasenko05341252006-09-26 20:35:30 +0000718 &addr_inet6,
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000719#endif
Denis Vlasenko05341252006-09-26 20:35:30 +0000720 NULL
721 };
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000722
Denis Vlasenko05341252006-09-26 20:35:30 +0000723 char *iface_name;
724 char *address_family_name;
725 char *method_name;
726 llist_t *iface_list;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000727
Denis Vlasenko05341252006-09-26 20:35:30 +0000728 currif = xzalloc(sizeof(struct interface_defn_t));
729 iface_name = next_word(&buf_ptr);
730 address_family_name = next_word(&buf_ptr);
731 method_name = next_word(&buf_ptr);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000732
Denis Vlasenko05341252006-09-26 20:35:30 +0000733 if (buf_ptr == NULL) {
734 bb_error_msg("too few parameters for line \"%s\"", buf);
735 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000736 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000737
738 /* ship any trailing whitespace */
Denis Vlasenkod18a3a22006-10-25 12:46:03 +0000739 buf_ptr = skip_whitespace(buf_ptr);
Denis Vlasenko05341252006-09-26 20:35:30 +0000740
741 if (buf_ptr[0] != '\0') {
742 bb_error_msg("too many parameters \"%s\"", buf);
743 return NULL;
744 }
745
746 currif->iface = xstrdup(iface_name);
747
748 currif->address_family = get_address_family(addr_fams, address_family_name);
749 if (!currif->address_family) {
750 bb_error_msg("unknown address type \"%s\"", address_family_name);
751 return NULL;
752 }
753
754 currif->method = get_method(currif->address_family, method_name);
755 if (!currif->method) {
756 bb_error_msg("unknown method \"%s\"", method_name);
757 return NULL;
758 }
759
760 for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
761 struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
762 if ((strcmp(tmp->iface, currif->iface) == 0) &&
763 (tmp->address_family == currif->address_family)) {
764 bb_error_msg("duplicate interface \"%s\"", tmp->iface);
765 return NULL;
766 }
767 }
768 llist_add_to_end(&(defn->ifaces), (char*)currif);
769
770 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000771 currently_processing = IFACE;
772 } else if (strcmp(firstword, "auto") == 0) {
Glenn L McGrath85737042003-01-14 23:26:57 +0000773 while ((firstword = next_word(&buf_ptr)) != NULL) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000774
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000775 /* Check the interface isnt already listed */
776 if (find_list_string(defn->autointerfaces, firstword)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000777 bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000778 }
779
Glenn L McGrath8e49caa2002-12-08 01:23:39 +0000780 /* Add the interface to the list */
Rob Landleyd921b2e2006-08-03 15:41:12 +0000781 llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword));
Eric Andersen8320b422003-04-02 10:13:26 +0000782 debug_noise("\nauto %s\n", firstword);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000783 }
784 currently_processing = NONE;
785 } else {
786 switch (currently_processing) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000787 case IFACE:
788 {
789 int i;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000790
Denis Vlasenko05341252006-09-26 20:35:30 +0000791 if (strlen(buf_ptr) == 0) {
792 bb_error_msg("option with empty value \"%s\"", buf);
793 return NULL;
794 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000795
Denis Vlasenko05341252006-09-26 20:35:30 +0000796 if (strcmp(firstword, "up") != 0
797 && strcmp(firstword, "down") != 0
798 && strcmp(firstword, "pre-up") != 0
799 && strcmp(firstword, "post-down") != 0) {
800 for (i = 0; i < currif->n_options; i++) {
801 if (strcmp(currif->option[i].name, firstword) == 0) {
802 bb_error_msg("duplicate option \"%s\"", buf);
803 return NULL;
Eric Andersen8320b422003-04-02 10:13:26 +0000804 }
805 }
806 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000807 }
808 if (currif->n_options >= currif->max_options) {
809 struct variable_t *opt;
Eric Andersen8320b422003-04-02 10:13:26 +0000810
Denis Vlasenko05341252006-09-26 20:35:30 +0000811 currif->max_options = currif->max_options + 10;
812 opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
813 currif->option = opt;
814 }
815 currif->option[currif->n_options].name = xstrdup(firstword);
816 currif->option[currif->n_options].value = xstrdup(buf_ptr);
817 if (!currif->option[currif->n_options].name) {
818 perror(filename);
819 return NULL;
820 }
821 if (!currif->option[currif->n_options].value) {
822 perror(filename);
823 return NULL;
824 }
825 debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,
826 currif->option[currif->n_options].value);
827 currif->n_options++;
828 break;
829 case MAPPING:
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000830#if ENABLE_FEATURE_IFUPDOWN_MAPPING
Denis Vlasenko05341252006-09-26 20:35:30 +0000831 if (strcmp(firstword, "script") == 0) {
832 if (currmap->script != NULL) {
833 bb_error_msg("duplicate script in mapping \"%s\"", buf);
Eric Andersen8320b422003-04-02 10:13:26 +0000834 return NULL;
Denis Vlasenko05341252006-09-26 20:35:30 +0000835 } else {
836 currmap->script = xstrdup(next_word(&buf_ptr));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000837 }
Denis Vlasenko05341252006-09-26 20:35:30 +0000838 } else if (strcmp(firstword, "map") == 0) {
839 if (currmap->max_mappings == currmap->n_mappings) {
840 currmap->max_mappings = currmap->max_mappings * 2 + 1;
841 currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
842 }
843 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));
844 currmap->n_mappings++;
845 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000846 bb_error_msg("misplaced option \"%s\"", buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000847 return NULL;
Denis Vlasenko05341252006-09-26 20:35:30 +0000848 }
849#endif
850 break;
851 case NONE:
852 default:
853 bb_error_msg("misplaced option \"%s\"", buf);
854 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000855 }
856 }
Glenn L McGrath85737042003-01-14 23:26:57 +0000857 free(buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000858 }
859 if (ferror(f) != 0) {
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000860 /* ferror does NOT set errno! */
861 bb_error_msg_and_die("%s: I/O error", filename);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000862 }
863 fclose(f);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000864
865 return defn;
866}
867
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000868static char *setlocalenv(const char *format, const char *name, const char *value)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000869{
870 char *result;
871 char *here;
872 char *there;
873
Rob Landleyd921b2e2006-08-03 15:41:12 +0000874 result = xasprintf(format, name, value);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000875
876 for (here = there = result; *there != '=' && *there; there++) {
877 if (*there == '-')
878 *there = '_';
879 if (isalpha(*there))
880 *there = toupper(*there);
881
882 if (isalnum(*there) || *there == '_') {
883 *here = *there;
884 here++;
885 }
886 }
Rob Landleya3896512006-05-07 20:20:34 +0000887 memmove(here, there, strlen(there) + 1);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000888
889 return result;
890}
891
Rob Landleye813ddb2006-02-28 03:53:14 +0000892static void set_environ(struct interface_defn_t *iface, const char *mode)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000893{
894 char **environend;
895 int i;
896 const int n_env_entries = iface->n_options + 5;
897 char **ppch;
898
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000899 if (my_environ != NULL) {
900 for (ppch = my_environ; *ppch; ppch++) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000901 free(*ppch);
902 *ppch = NULL;
903 }
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000904 free(my_environ);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000905 }
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000906 my_environ = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
907 environend = my_environ;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000908
909 for (i = 0; i < iface->n_options; i++) {
910 if (strcmp(iface->option[i].name, "up") == 0
Denis Vlasenkoa4836912007-07-03 08:26:24 +0000911 || strcmp(iface->option[i].name, "down") == 0
912 || strcmp(iface->option[i].name, "pre-up") == 0
913 || strcmp(iface->option[i].name, "post-down") == 0
914 ) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000915 continue;
916 }
917 *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000918 }
919
920 *(environend++) = setlocalenv("%s=%s", "IFACE", iface->iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000921 *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000922 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000923 *(environend++) = setlocalenv("%s=%s", "MODE", mode);
Denis Vlasenko2f4399c2006-09-27 14:14:51 +0000924 *(environend++) = setlocalenv("%s=%s", "PATH", startup_PATH);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000925}
926
927static int doit(char *str)
928{
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000929 if (option_mask32 & (OPT_no_act|OPT_verbose)) {
Denis Vlasenko05341252006-09-26 20:35:30 +0000930 puts(str);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000931 }
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000932 if (!(option_mask32 & OPT_no_act)) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000933 pid_t child;
934 int status;
935
936 fflush(NULL);
Denis Vlasenko2375d752006-12-19 23:15:46 +0000937 child = fork();
938 switch (child) {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000939 case -1: /* failure */
Denis Vlasenko05341252006-09-26 20:35:30 +0000940 return 0;
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000941 case 0: /* child */
Denis Vlasenko8cd1a282006-12-19 23:01:33 +0000942 execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);
Denis Vlasenko05341252006-09-26 20:35:30 +0000943 exit(127);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000944 }
945 waitpid(child, &status, 0);
946 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
947 return 0;
948 }
949 }
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +0000950 return 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000951}
952
Rob Landleye813ddb2006-02-28 03:53:14 +0000953static int execute_all(struct interface_defn_t *ifd, const char *opt)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000954{
955 int i;
Eric Anderseneb213bd2003-09-12 08:39:05 +0000956 char *buf;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000957 for (i = 0; i < ifd->n_options; i++) {
958 if (strcmp(ifd->option[i].name, opt) == 0) {
Rob Landleye813ddb2006-02-28 03:53:14 +0000959 if (!doit(ifd->option[i].value)) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000960 return 0;
961 }
962 }
963 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000964
Rob Landleyd921b2e2006-08-03 15:41:12 +0000965 buf = xasprintf("run-parts /etc/network/if-%s.d", opt);
Denis Vlasenko2375d752006-12-19 23:15:46 +0000966 /* heh, we don't bother free'ing it */
967 return doit(buf);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000968}
969
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000970static int check(char *str)
971{
Eric Andersen8320b422003-04-02 10:13:26 +0000972 return str != NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000973}
974
Eric Andersen8320b422003-04-02 10:13:26 +0000975static int iface_up(struct interface_defn_t *iface)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000976{
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000977 if (!iface->method->up(iface, check)) return -1;
Eric Andersen8320b422003-04-02 10:13:26 +0000978 set_environ(iface, "start");
Rob Landleye813ddb2006-02-28 03:53:14 +0000979 if (!execute_all(iface, "pre-up")) return 0;
Eric Andersen658f8b12003-12-19 10:46:00 +0000980 if (!iface->method->up(iface, doit)) return 0;
Rob Landleye813ddb2006-02-28 03:53:14 +0000981 if (!execute_all(iface, "up")) return 0;
Eric Andersen658f8b12003-12-19 10:46:00 +0000982 return 1;
Eric Andersen8320b422003-04-02 10:13:26 +0000983}
984
985static int iface_down(struct interface_defn_t *iface)
986{
Eric Andersen8320b422003-04-02 10:13:26 +0000987 if (!iface->method->down(iface,check)) return -1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000988 set_environ(iface, "stop");
Rob Landleye813ddb2006-02-28 03:53:14 +0000989 if (!execute_all(iface, "down")) return 0;
Eric Andersen658f8b12003-12-19 10:46:00 +0000990 if (!iface->method->down(iface, doit)) return 0;
Rob Landleye813ddb2006-02-28 03:53:14 +0000991 if (!execute_all(iface, "post-down")) return 0;
Eric Andersen658f8b12003-12-19 10:46:00 +0000992 return 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000993}
994
Denis Vlasenkofcfe8342006-12-18 21:02:00 +0000995#if ENABLE_FEATURE_IFUPDOWN_MAPPING
Glenn L McGrath021fa7d2002-11-09 09:34:15 +0000996static int popen2(FILE **in, FILE **out, char *command, ...)
997{
998 va_list ap;
999 char *argv[11] = { command };
1000 int argc;
1001 int infd[2], outfd[2];
1002 pid_t pid;
1003
1004 argc = 1;
1005 va_start(ap, command);
1006 while ((argc < 10) && (argv[argc] = va_arg(ap, char *))) {
1007 argc++;
1008 }
1009 argv[argc] = NULL; /* make sure */
1010 va_end(ap);
1011
1012 if (pipe(infd) != 0) {
1013 return 0;
1014 }
1015
1016 if (pipe(outfd) != 0) {
1017 close(infd[0]);
1018 close(infd[1]);
1019 return 0;
1020 }
1021
1022 fflush(NULL);
1023 switch (pid = fork()) {
Denis Vlasenko05341252006-09-26 20:35:30 +00001024 case -1: /* failure */
1025 close(infd[0]);
1026 close(infd[1]);
1027 close(outfd[0]);
1028 close(outfd[1]);
1029 return 0;
1030 case 0: /* child */
1031 dup2(infd[0], 0);
1032 dup2(outfd[1], 1);
1033 close(infd[0]);
1034 close(infd[1]);
1035 close(outfd[0]);
1036 close(outfd[1]);
Denis Vlasenko1d76f432007-02-06 01:20:12 +00001037 BB_EXECVP(command, argv);
Denis Vlasenko05341252006-09-26 20:35:30 +00001038 exit(127);
1039 default: /* parent */
1040 *in = fdopen(infd[1], "w");
1041 *out = fdopen(outfd[0], "r");
1042 close(infd[0]);
1043 close(outfd[1]);
1044 return pid;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001045 }
1046 /* unreached */
1047}
1048
Glenn L McGrath0177ce12004-07-21 23:56:31 +00001049static char *run_mapping(char *physical, struct mapping_defn_t * map)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001050{
1051 FILE *in, *out;
1052 int i, status;
1053 pid_t pid;
1054
Rob Landleyd921b2e2006-08-03 15:41:12 +00001055 char *logical = xstrdup(physical);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001056
Eric Andersen8a931792003-07-03 10:20:29 +00001057 /* Run the mapping script. */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001058 pid = popen2(&in, &out, map->script, physical, NULL);
Eric Andersen8a931792003-07-03 10:20:29 +00001059
1060 /* popen2() returns 0 on failure. */
1061 if (pid == 0)
1062 return logical;
1063
1064 /* Write mappings to stdin of mapping script. */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001065 for (i = 0; i < map->n_mappings; i++) {
1066 fprintf(in, "%s\n", map->mapping[i]);
1067 }
1068 fclose(in);
1069 waitpid(pid, &status, 0);
Eric Andersen8a931792003-07-03 10:20:29 +00001070
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001071 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Eric Andersen8a931792003-07-03 10:20:29 +00001072 /* If the mapping script exited successfully, try to
1073 * grab a line of output and use that as the name of the
1074 * logical interface. */
Denis Vlasenkob95636c2006-12-19 23:36:04 +00001075 char *new_logical = xmalloc(MAX_INTERFACE_LENGTH);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001076
Eric Andersen233b1702003-06-05 19:37:01 +00001077 if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) {
Eric Andersen8a931792003-07-03 10:20:29 +00001078 /* If we are able to read a line of output from the script,
1079 * remove any trailing whitespace and use this value
1080 * as the name of the logical interface. */
Rob Landleya3896512006-05-07 20:20:34 +00001081 char *pch = new_logical + strlen(new_logical) - 1;
Eric Andersen233b1702003-06-05 19:37:01 +00001082
1083 while (pch >= new_logical && isspace(*pch))
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001084 *(pch--) = '\0';
Eric Andersen8a931792003-07-03 10:20:29 +00001085
1086 free(logical);
1087 logical = new_logical;
1088 } else {
Rob Landleya6e131d2006-05-29 06:43:55 +00001089 /* If we are UNABLE to read a line of output, discard our
Eric Andersen8a931792003-07-03 10:20:29 +00001090 * freshly allocated memory. */
1091 free(new_logical);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001092 }
1093 }
Eric Andersen8a931792003-07-03 10:20:29 +00001094
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001095 fclose(out);
1096
Eric Andersen8a931792003-07-03 10:20:29 +00001097 return logical;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001098}
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001099#endif /* FEATURE_IFUPDOWN_MAPPING */
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001100
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001101static llist_t *find_iface_state(llist_t *state_list, const char *iface)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001102{
Rob Landleya3896512006-05-07 20:20:34 +00001103 unsigned short iface_len = strlen(iface);
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001104 llist_t *search = state_list;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001105
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001106 while (search) {
Denis Vlasenkoeda43d72007-05-02 22:04:38 +00001107 if ((strncmp(search->data, iface, iface_len) == 0)
1108 && (search->data[iface_len] == '=')) {
Denis Vlasenko05341252006-09-26 20:35:30 +00001109 return search;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001110 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001111 search = search->link;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001112 }
Denis Vlasenko05341252006-09-26 20:35:30 +00001113 return NULL;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001114}
1115
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001116/* read the previous state from the state file */
1117static llist_t *read_iface_state(void)
1118{
1119 llist_t *state_list = NULL;
Denis Vlasenko2a86a612007-07-19 21:49:30 +00001120 FILE *state_fp = fopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "r");
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001121
1122 if (state_fp) {
1123 char *start, *end_ptr;
1124 while ((start = xmalloc_fgets(state_fp)) != NULL) {
1125 /* We should only need to check for a single character */
1126 end_ptr = start + strcspn(start, " \t\n");
1127 *end_ptr = '\0';
1128 llist_add_to(&state_list, start);
1129 }
1130 fclose(state_fp);
1131 }
1132 return state_list;
1133}
1134
1135
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001136int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleydfba7412006-03-06 20:47:33 +00001137int ifupdown_main(int argc, char **argv)
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001138{
Denis Vlasenko05341252006-09-26 20:35:30 +00001139 int (*cmds)(struct interface_defn_t *) = NULL;
Eric Andersen8320b422003-04-02 10:13:26 +00001140 struct interfaces_file_t *defn;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001141 llist_t *target_list = NULL;
Glenn L McGrathd4004ee2004-09-14 17:24:59 +00001142 const char *interfaces = "/etc/network/interfaces";
Bernhard Reutner-Fischer16deb862007-03-19 19:54:56 +00001143 bool any_failures = 0;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001144
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001145 cmds = iface_down;
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00001146 if (applet_name[2] == 'u') {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001147 /* ifup command */
1148 cmds = iface_up;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001149 }
1150
Denis Vlasenkofe7cd642007-08-18 15:32:12 +00001151 getopt32(argv, OPTION_STR, &interfaces);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001152 if (argc - optind > 0) {
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001153 if (DO_ALL) bb_show_usage();
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001154 } else {
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001155 if (!DO_ALL) bb_show_usage();
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001156 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001157
Eric Andersen8320b422003-04-02 10:13:26 +00001158 debug_noise("reading %s file:\n", interfaces);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001159 defn = read_interfaces(interfaces);
Eric Andersen8320b422003-04-02 10:13:26 +00001160 debug_noise("\ndone reading %s\n\n", interfaces);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001161
Eric Andersen3c8bca32003-06-20 10:02:29 +00001162 if (!defn) {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001163 return EXIT_FAILURE;
Eric Andersen3c8bca32003-06-20 10:02:29 +00001164 }
1165
Denis Vlasenko2f4399c2006-09-27 14:14:51 +00001166 startup_PATH = getenv("PATH");
1167 if (!startup_PATH) startup_PATH = "";
1168
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001169 /* Create a list of interfaces to work on */
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001170 if (DO_ALL) {
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001171 target_list = defn->autointerfaces;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001172 } else {
Rob Landley8bb50782006-05-26 23:44:51 +00001173 llist_add_to_end(&target_list, argv[optind]);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001174 }
1175
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001176 /* Update the interfaces */
1177 while (target_list) {
Eric Andersen8320b422003-04-02 10:13:26 +00001178 llist_t *iface_list;
1179 struct interface_defn_t *currif;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001180 char *iface;
1181 char *liface;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001182 char *pch;
Bernhard Reutner-Fischer16deb862007-03-19 19:54:56 +00001183 bool okay = 0;
1184 unsigned cmds_ret;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001185
Rob Landleyd921b2e2006-08-03 15:41:12 +00001186 iface = xstrdup(target_list->data);
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001187 target_list = target_list->link;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001188
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001189 pch = strchr(iface, '=');
1190 if (pch) {
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001191 *pch = '\0';
Rob Landleyd921b2e2006-08-03 15:41:12 +00001192 liface = xstrdup(pch + 1);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001193 } else {
Rob Landleyd921b2e2006-08-03 15:41:12 +00001194 liface = xstrdup(iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001195 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001196
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001197 if (!FORCE) {
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001198 llist_t *state_list = read_iface_state();
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001199 const llist_t *iface_state = find_iface_state(state_list, iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001200
1201 if (cmds == iface_up) {
1202 /* ifup */
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001203 if (iface_state) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001204 bb_error_msg("interface %s already configured", iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001205 continue;
1206 }
1207 } else {
1208 /* ifdown */
Denis Vlasenkoc115fdb2007-03-06 22:53:10 +00001209 if (!iface_state) {
Manuel Novoa III cad53642003-03-19 09:13:01 +00001210 bb_error_msg("interface %s not configured", iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001211 continue;
1212 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001213 }
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001214 llist_free(state_list, free);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001215 }
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001216
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001217#if ENABLE_FEATURE_IFUPDOWN_MAPPING
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001218 if ((cmds == iface_up) && !NO_MAPPINGS) {
Eric Andersen8320b422003-04-02 10:13:26 +00001219 struct mapping_defn_t *currmap;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001220
1221 for (currmap = defn->mappings; currmap; currmap = currmap->next) {
Denis Vlasenko4e33e072006-10-16 18:24:57 +00001222 int i;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001223 for (i = 0; i < currmap->n_matches; i++) {
1224 if (fnmatch(currmap->match[i], liface, 0) != 0)
1225 continue;
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001226 if (VERBOSE) {
Eric Andersen8320b422003-04-02 10:13:26 +00001227 printf("Running mapping script %s on %s\n", currmap->script, liface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001228 }
Eric Andersen8a931792003-07-03 10:20:29 +00001229 liface = run_mapping(iface, currmap);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001230 break;
1231 }
1232 }
1233 }
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001234#endif
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001235
Eric Andersen8320b422003-04-02 10:13:26 +00001236 iface_list = defn->ifaces;
1237 while (iface_list) {
1238 currif = (struct interface_defn_t *) iface_list->data;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001239 if (strcmp(liface, currif->iface) == 0) {
1240 char *oldiface = currif->iface;
1241
1242 okay = 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001243 currif->iface = iface;
1244
Denis Vlasenko8cd1a282006-12-19 23:01:33 +00001245 debug_noise("\nConfiguring interface %s (%s)\n", liface, currif->address_family->name);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001246
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001247 /* Call the cmds function pointer, does either iface_up() or iface_down() */
Glenn L McGrath0177ce12004-07-21 23:56:31 +00001248 cmds_ret = cmds(currif);
1249 if (cmds_ret == -1) {
Denis Vlasenko05341252006-09-26 20:35:30 +00001250 bb_error_msg("don't seem to have all the variables for %s/%s",
Eric Andersen8320b422003-04-02 10:13:26 +00001251 liface, currif->address_family->name);
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001252 any_failures = 1;
Glenn L McGrath0177ce12004-07-21 23:56:31 +00001253 } else if (cmds_ret == 0) {
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001254 any_failures = 1;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001255 }
Glenn L McGrathcdbe5e52002-12-06 08:35:55 +00001256
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001257 currif->iface = oldiface;
1258 }
Eric Andersen8320b422003-04-02 10:13:26 +00001259 iface_list = iface_list->link;
1260 }
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001261 if (VERBOSE) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00001262 bb_putchar('\n');
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001263 }
1264
Denis Vlasenko7f1f5b02006-09-23 12:49:01 +00001265 if (!okay && !FORCE) {
Denis Vlasenko05341252006-09-26 20:35:30 +00001266 bb_error_msg("ignoring unknown interface %s", liface);
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001267 any_failures = 1;
Denis Vlasenkof92df582007-05-02 22:22:23 +00001268 } else if (!NO_ACT) {
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001269 /* update the state file */
Denis Vlasenkof92df582007-05-02 22:22:23 +00001270 FILE *state_fp;
1271 llist_t *state;
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001272 llist_t *state_list = read_iface_state();
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001273 llist_t *iface_state = find_iface_state(state_list, iface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001274
1275 if (cmds == iface_up) {
Bernhard Reutner-Fischer16deb862007-03-19 19:54:56 +00001276 char * const newiface = xasprintf("%s=%s", iface, liface);
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001277 if (iface_state == NULL) {
Rob Landley8bb50782006-05-26 23:44:51 +00001278 llist_add_to_end(&state_list, newiface);
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001279 } else {
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001280 free(iface_state->data);
1281 iface_state->data = newiface;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001282 }
Rob Landleye813ddb2006-02-28 03:53:14 +00001283 } else {
Denis Vlasenkoc115fdb2007-03-06 22:53:10 +00001284 /* Remove an interface from state_list */
1285 llist_unlink(&state_list, iface_state);
Rob Landleya6e131d2006-05-29 06:43:55 +00001286 free(llist_pop(&iface_state));
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001287 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001288
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001289 /* Actually write the new state */
Denis Vlasenko2a86a612007-07-19 21:49:30 +00001290 state_fp = xfopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "w");
Denis Vlasenkof92df582007-05-02 22:22:23 +00001291 state = state_list;
1292 while (state) {
1293 if (state->data) {
1294 fprintf(state_fp, "%s\n", state->data);
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001295 }
Denis Vlasenkof92df582007-05-02 22:22:23 +00001296 state = state->link;
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001297 }
Denis Vlasenkof92df582007-05-02 22:22:23 +00001298 fclose(state_fp);
Denis Vlasenkobd100b72007-05-02 21:38:44 +00001299 llist_free(state_list, free);
Glenn L McGrath8e49caa2002-12-08 01:23:39 +00001300 }
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001301 }
1302
Denis Vlasenkofcfe8342006-12-18 21:02:00 +00001303 return any_failures;
Glenn L McGrath021fa7d2002-11-09 09:34:15 +00001304}