source: MondoRescue/branches/3.3/mindi-busybox/networking/ifupdown.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 36.5 KB
RevLine 
[821]1/* vi: set sw=4 ts=4: */
2/*
3 * ifupdown for busybox
[2725]4 * Copyright (c) 2002 Glenn McGrath
[821]5 * Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>
6 *
7 * Based on ifupdown v 0.6.4 by Anthony Towns
8 * Copyright (c) 1999 Anthony Towns <aj@azure.humbug.org.au>
9 *
10 * Changes to upstream version
11 * Remove checks for kernel version, assume kernel version 2.2.0 or better.
12 * Lines in the interfaces file cannot wrap.
[1765]13 * 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.
[821]16 *
[2725]17 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
[821]18 */
19
[3232]20//usage:#define ifup_trivial_usage
21//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..."
22//usage:#define ifup_full_usage "\n\n"
23//usage: " -a De/configure all interfaces automatically"
24//usage: "\n -i FILE Use FILE for interface definitions"
25//usage: "\n -n Print out what would happen, but don't do it"
26//usage: IF_FEATURE_IFUPDOWN_MAPPING(
27//usage: "\n (note: doesn't disable mappings)"
28//usage: "\n -m Don't run any mappings"
29//usage: )
30//usage: "\n -v Print out what would happen before doing it"
31//usage: "\n -f Force de/configuration"
32//usage:
33//usage:#define ifdown_trivial_usage
34//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..."
35//usage:#define ifdown_full_usage "\n\n"
36//usage: " -a De/configure all interfaces automatically"
37//usage: "\n -i FILE Use FILE for interface definitions"
38//usage: "\n -n Print out what would happen, but don't do it"
39//usage: IF_FEATURE_IFUPDOWN_MAPPING(
40//usage: "\n (note: doesn't disable mappings)"
41//usage: "\n -m Don't run any mappings"
42//usage: )
43//usage: "\n -v Print out what would happen before doing it"
44//usage: "\n -f Force de/configuration"
45
[2725]46#include "libbb.h"
[3621]47#include "common_bufsiz.h"
[2725]48/* After libbb.h, since it needs sys/types.h on some systems */
[821]49#include <sys/utsname.h>
50#include <fnmatch.h>
51
52#define MAX_OPT_DEPTH 10
53
[1765]54#if ENABLE_FEATURE_IFUPDOWN_MAPPING
[821]55#define MAX_INTERFACE_LENGTH 10
56#endif
57
[2725]58#define UDHCPC_CMD_OPTIONS CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS
59
[1765]60#define debug_noise(args...) /*fprintf(stderr, args)*/
[821]61
62/* Forward declaration */
63struct interface_defn_t;
64
[1765]65typedef int execfn(char *command);
[821]66
[1765]67struct method_t {
68 const char *name;
[2725]69 int (*up)(struct interface_defn_t *ifd, execfn *e) FAST_FUNC;
70 int (*down)(struct interface_defn_t *ifd, execfn *e) FAST_FUNC;
[821]71};
72
[1765]73struct address_family_t {
74 const char *name;
[821]75 int n_methods;
[1765]76 const struct method_t *method;
[821]77};
78
[1765]79struct mapping_defn_t {
[821]80 struct mapping_defn_t *next;
81
82 int max_matches;
83 int n_matches;
84 char **match;
85
86 char *script;
87
88 int n_mappings;
89 char **mapping;
90};
91
[1765]92struct variable_t {
[821]93 char *name;
94 char *value;
95};
96
[1765]97struct interface_defn_t {
98 const struct address_family_t *address_family;
99 const struct method_t *method;
[821]100
101 char *iface;
102 int n_options;
103 struct variable_t *option;
104};
105
[1765]106struct interfaces_file_t {
[821]107 llist_t *autointerfaces;
108 llist_t *ifaces;
109 struct mapping_defn_t *mappings;
110};
111
[2725]112
113#define OPTION_STR "anvf" IF_FEATURE_IFUPDOWN_MAPPING("m") "i:"
[1765]114enum {
[2725]115 OPT_do_all = 0x1,
116 OPT_no_act = 0x2,
117 OPT_verbose = 0x4,
118 OPT_force = 0x8,
[1765]119 OPT_no_mappings = 0x10,
120};
[2725]121#define DO_ALL (option_mask32 & OPT_do_all)
122#define NO_ACT (option_mask32 & OPT_no_act)
123#define VERBOSE (option_mask32 & OPT_verbose)
124#define FORCE (option_mask32 & OPT_force)
[1765]125#define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
[821]126
127
[2725]128struct globals {
129 char **my_environ;
130 const char *startup_PATH;
[3232]131 char *shell;
[2725]132} FIX_ALIASING;
[3621]133#define G (*(struct globals*)bb_common_bufsiz1)
134#define INIT_G() do { setup_common_bufsiz(); } while (0)
[821]135
[2725]136
[3232]137static const char keywords_up_down[] ALIGN1 =
138 "up\0"
139 "down\0"
140 "pre-up\0"
141 "post-down\0"
142;
143
144
[1765]145#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
[821]146
[1765]147static void addstr(char **bufp, const char *str, size_t str_length)
[821]148{
[1765]149 /* xasprintf trick will be smaller, but we are often
150 * called with str_length == 1 - don't want to have
151 * THAT much of malloc/freeing! */
152 char *buf = *bufp;
153 int len = (buf ? strlen(buf) : 0);
154 str_length++;
155 buf = xrealloc(buf, len + str_length);
156 /* copies at most str_length-1 chars! */
157 safe_strncpy(buf + len, str, str_length);
158 *bufp = buf;
[821]159}
160
[1765]161static int strncmpz(const char *l, const char *r, size_t llen)
[821]162{
163 int i = strncmp(l, r, llen);
164
[1765]165 if (i == 0)
[2725]166 return - (unsigned char)r[llen];
[1765]167 return i;
[821]168}
169
[1765]170static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd)
[821]171{
172 int i;
173
174 if (strncmpz(id, "iface", idlen) == 0) {
[2725]175 // ubuntu's ifup doesn't do this:
176 //static char *label_buf;
177 //char *result;
178 //free(label_buf);
179 //label_buf = xstrdup(ifd->iface);
180 // Remove virtual iface suffix
181 //result = strchrnul(label_buf, ':');
182 //*result = '\0';
183 //return label_buf;
184
185 return ifd->iface;
[1765]186 }
187 if (strncmpz(id, "label", idlen) == 0) {
188 return ifd->iface;
189 }
190 for (i = 0; i < ifd->n_options; i++) {
191 if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
192 return ifd->option[i].value;
[821]193 }
194 }
[1765]195 return NULL;
196}
[821]197
[2725]198# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]199static int count_netmask_bits(const char *dotted_quad)
200{
201// int result;
202// unsigned a, b, c, d;
203// /* Found a netmask... Check if it is dotted quad */
204// if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
205// return -1;
206// if ((a|b|c|d) >> 8)
207// return -1; /* one of numbers is >= 256 */
208// d |= (a << 24) | (b << 16) | (c << 8); /* IP */
209// d = ~d; /* 11110000 -> 00001111 */
210
211 /* Shorter version */
212 int result;
213 struct in_addr ip;
214 unsigned d;
215
216 if (inet_aton(dotted_quad, &ip) == 0)
217 return -1; /* malformed dotted IP */
218 d = ntohl(ip.s_addr); /* IP in host order */
219 d = ~d; /* 11110000 -> 00001111 */
220 if (d & (d+1)) /* check that it is in 00001111 form */
221 return -1; /* no it is not */
222 result = 32;
223 while (d) {
224 d >>= 1;
225 result--;
226 }
227 return result;
[821]228}
[2725]229# endif
[821]230
[1765]231static char *parse(const char *command, struct interface_defn_t *ifd)
[821]232{
233 size_t old_pos[MAX_OPT_DEPTH] = { 0 };
[3232]234 smallint okay[MAX_OPT_DEPTH] = { 1 };
[821]235 int opt_depth = 1;
[1765]236 char *result = NULL;
[821]237
238 while (*command) {
239 switch (*command) {
[1765]240 default:
241 addstr(&result, command, 1);
242 command++;
243 break;
244 case '\\':
[3232]245 if (command[1])
[1765]246 command++;
[3232]247 addstr(&result, command, 1);
248 command++;
[1765]249 break;
250 case '[':
251 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
252 old_pos[opt_depth] = result ? strlen(result) : 0;
253 okay[opt_depth] = 1;
254 opt_depth++;
255 command += 2;
256 } else {
[3232]257 addstr(&result, command, 1);
[1765]258 command++;
259 }
260 break;
261 case ']':
262 if (command[1] == ']' && opt_depth > 1) {
263 opt_depth--;
264 if (!okay[opt_depth]) {
265 result[old_pos[opt_depth]] = '\0';
266 }
267 command += 2;
268 } else {
[3232]269 addstr(&result, command, 1);
[1765]270 command++;
271 }
272 break;
273 case '%':
274 {
275 char *nextpercent;
276 char *varvalue;
[821]277
278 command++;
[1765]279 nextpercent = strchr(command, '%');
280 if (!nextpercent) {
[3232]281 /* Unterminated %var% */
[1765]282 free(result);
283 return NULL;
[821]284 }
285
[1765]286 varvalue = get_var(command, nextpercent - command, ifd);
[821]287
[1765]288 if (varvalue) {
[2725]289# if ENABLE_FEATURE_IFUPDOWN_IP
290 /* "hwaddress <class> <address>":
291 * unlike ifconfig, ip doesnt want <class>
292 * (usually "ether" keyword). Skip it. */
[3621]293 if (is_prefixed_with(command, "hwaddress")) {
[2725]294 varvalue = skip_whitespace(skip_non_whitespace(varvalue));
295 }
296# endif
[1765]297 addstr(&result, varvalue, strlen(varvalue));
298 } else {
[2725]299# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]300 /* Sigh... Add a special case for 'ip' to convert from
301 * dotted quad to bit count style netmasks. */
[3621]302 if (is_prefixed_with(command, "bnmask")) {
[1765]303 unsigned res;
304 varvalue = get_var("netmask", 7, ifd);
305 if (varvalue) {
306 res = count_netmask_bits(varvalue);
307 if (res > 0) {
308 const char *argument = utoa(res);
309 addstr(&result, argument, strlen(argument));
[821]310 command = nextpercent + 1;
311 break;
312 }
313 }
[1765]314 }
[2725]315# endif
[1765]316 okay[opt_depth - 1] = 0;
317 }
[821]318
[1765]319 command = nextpercent + 1;
320 }
321 break;
[821]322 }
323 }
324
325 if (opt_depth > 1) {
[3232]326 /* Unbalanced bracket */
[821]327 free(result);
[1765]328 return NULL;
[821]329 }
330
331 if (!okay[0]) {
[3232]332 /* Undefined variable and we aren't in a bracket */
[821]333 free(result);
[1765]334 return NULL;
[821]335 }
336
[1765]337 return result;
[821]338}
339
[1765]340/* execute() returns 1 for success and 0 for failure */
341static int execute(const char *command, struct interface_defn_t *ifd, execfn *exec)
[821]342{
343 char *out;
344 int ret;
345
346 out = parse(command, ifd);
347 if (!out) {
[1765]348 /* parse error? */
349 return 0;
[821]350 }
[1765]351 /* out == "": parsed ok but not all needed variables known, skip */
352 ret = out[0] ? (*exec)(out) : 1;
[821]353
354 free(out);
355 if (ret != 1) {
[1765]356 return 0;
[821]357 }
[1765]358 return 1;
[821]359}
360
[2725]361#endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */
362
363
[1765]364#if ENABLE_FEATURE_IFUPDOWN_IPV6
[2725]365
366static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec)
[821]367{
[2725]368# if ENABLE_FEATURE_IFUPDOWN_IP
[821]369 int result;
[1765]370 result = execute("ip addr add ::1 dev %iface%", ifd, exec);
[821]371 result += execute("ip link set %iface% up", ifd, exec);
372 return ((result == 2) ? 2 : 0);
[2725]373# else
[1765]374 return execute("ifconfig %iface% add ::1", ifd, exec);
[2725]375# endif
[821]376}
377
[2725]378static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec)
[821]379{
[2725]380# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]381 return execute("ip link set %iface% down", ifd, exec);
[2725]382# else
[1765]383 return execute("ifconfig %iface% del ::1", ifd, exec);
[2725]384# endif
[821]385}
386
[2725]387static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
[821]388{
[2725]389 return 1;
390}
391
392static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
393{
[821]394 int result;
[2725]395# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]396 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
[2725]397 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
[3621]398 /* Reportedly, IPv6 needs "dev %iface%", but IPv4 does not: */
399 result += execute("[[ip route add ::/0 via %gateway% dev %iface%]][[ metric %metric%]]", ifd, exec);
[2725]400# else
[1765]401 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
[821]402 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
[3232]403 result += execute("[[route -A inet6 add ::/0 gw %gateway%[[ metric %metric%]]]]", ifd, exec);
[2725]404# endif
[821]405 return ((result == 3) ? 3 : 0);
406}
407
[2725]408static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec)
[821]409{
[2725]410# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]411 return execute("ip link set %iface% down", ifd, exec);
[2725]412# else
[1765]413 return execute("ifconfig %iface% down", ifd, exec);
[2725]414# endif
[821]415}
416
[2725]417# if ENABLE_FEATURE_IFUPDOWN_IP
418static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
[821]419{
420 int result;
421 result = execute("ip tunnel add %iface% mode sit remote "
[1765]422 "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd, exec);
[821]423 result += execute("ip link set %iface% up", ifd, exec);
424 result += execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec);
[3621]425 /* Reportedly, IPv6 needs "dev %iface%", but IPv4 does not: */
426 result += execute("[[ip route add ::/0 via %gateway% dev %iface%]]", ifd, exec);
[821]427 return ((result == 4) ? 4 : 0);
428}
429
[2725]430static int FAST_FUNC v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
[821]431{
[1765]432 return execute("ip tunnel del %iface%", ifd, exec);
[821]433}
[2725]434# endif
[821]435
[1765]436static const struct method_t methods6[] = {
[2725]437# if ENABLE_FEATURE_IFUPDOWN_IP
438 { "v4tunnel" , v4tunnel_up , v4tunnel_down , },
439# endif
440 { "static" , static_up6 , static_down6 , },
441 { "manual" , manual_up_down6 , manual_up_down6 , },
442 { "loopback" , loopback_up6 , loopback_down6 , },
[821]443};
444
[1765]445static const struct address_family_t addr_inet6 = {
[821]446 "inet6",
[1765]447 ARRAY_SIZE(methods6),
[821]448 methods6
449};
[2725]450
[1765]451#endif /* FEATURE_IFUPDOWN_IPV6 */
[821]452
[2725]453
[1765]454#if ENABLE_FEATURE_IFUPDOWN_IPV4
[2725]455
456static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec)
[821]457{
[2725]458# if ENABLE_FEATURE_IFUPDOWN_IP
[821]459 int result;
460 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
461 result += execute("ip link set %iface% up", ifd, exec);
462 return ((result == 2) ? 2 : 0);
[2725]463# else
[1765]464 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
[2725]465# endif
[821]466}
467
[2725]468static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec)
[821]469{
[2725]470# if ENABLE_FEATURE_IFUPDOWN_IP
[821]471 int result;
472 result = execute("ip addr flush dev %iface%", ifd, exec);
473 result += execute("ip link set %iface% down", ifd, exec);
474 return ((result == 2) ? 2 : 0);
[2725]475# else
[1765]476 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
[2725]477# endif
[821]478}
479
[2725]480static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
[821]481{
482 int result;
[2725]483# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]484 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
485 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
[2725]486 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
[3621]487 result += execute("[[ip route add default via %gateway% dev %iface%[[ metric %metric%]]]]", ifd, exec);
[821]488 return ((result == 3) ? 3 : 0);
[2725]489# else
[1765]490 /* ifconfig said to set iface up before it processes hw %hwaddress%,
491 * which then of course fails. Thus we run two separate ifconfig */
492 result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
[821]493 ifd, exec);
[1765]494 result += execute("ifconfig %iface% %address% netmask %netmask%"
495 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
496 ifd, exec);
[3232]497 result += execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd, exec);
[1765]498 return ((result == 3) ? 3 : 0);
[2725]499# endif
[821]500}
501
[2725]502static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec)
[821]503{
504 int result;
[2725]505# if ENABLE_FEATURE_IFUPDOWN_IP
[821]506 result = execute("ip addr flush dev %iface%", ifd, exec);
507 result += execute("ip link set %iface% down", ifd, exec);
[2725]508# else
509 /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */
510 /* Bringing the interface down deletes the routes in itself.
511 Otherwise this fails if we reference 'gateway' when using this from dhcp_down */
512 result = 1;
[821]513 result += execute("ifconfig %iface% down", ifd, exec);
[2725]514# endif
[821]515 return ((result == 2) ? 2 : 0);
516}
517
[2725]518# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
519struct dhcp_client_t {
[1765]520 const char *name;
521 const char *startcmd;
522 const char *stopcmd;
523};
[821]524
[1765]525static const struct dhcp_client_t ext_dhcp_clients[] = {
526 { "dhcpcd",
[2725]527 "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %client%]][[ -l %leasetime%]] %iface%",
[1765]528 "dhcpcd -k %iface%",
529 },
530 { "dhclient",
531 "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
532 "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
533 },
534 { "pump",
535 "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
536 "pump -i %iface% -k",
537 },
538 { "udhcpc",
[3621]539 "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -x hostname:%hostname%]][[ -c %client%]]"
[2725]540 "[[ -s %script%]][[ %udhcpc_opts%]]",
[1765]541 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
542 },
543};
[2725]544# endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
[1765]545
[2725]546# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
547static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
[821]548{
[2725]549 unsigned i;
550# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]551 /* ip doesn't up iface when it configures it (unlike ifconfig) */
[2725]552 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
[1765]553 return 0;
[2725]554# else
555 /* needed if we have hwaddress on dhcp iface */
556 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
557 return 0;
558# endif
[1765]559 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
[3621]560 if (executable_exists(ext_dhcp_clients[i].name))
[1765]561 return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
[821]562 }
[1765]563 bb_error_msg("no dhcp clients found");
564 return 0;
[2725]565}
566# elif ENABLE_UDHCPC
567static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
568{
569# if ENABLE_FEATURE_IFUPDOWN_IP
[1765]570 /* ip doesn't up iface when it configures it (unlike ifconfig) */
[2725]571 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
[1765]572 return 0;
[2725]573# else
574 /* needed if we have hwaddress on dhcp iface */
575 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
576 return 0;
577# endif
578 return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid "
[3621]579 "-i %iface%[[ -x hostname:%hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]",
[1765]580 ifd, exec);
[2725]581}
582# else
583static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM,
584 execfn *exec UNUSED_PARAM)
585{
[1765]586 return 0; /* no dhcp support */
[821]587}
[2725]588# endif
[821]589
[2725]590# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
591static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
[821]592{
[2725]593 int result = 0;
594 unsigned i;
595
[1765]596 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
[3621]597 if (executable_exists(ext_dhcp_clients[i].name)) {
[2725]598 result = execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
599 if (result)
600 break;
601 }
[821]602 }
[2725]603
604 if (!result)
605 bb_error_msg("warning: no dhcp clients found and stopped");
606
607 /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
608 and it may come back up because udhcpc is still shutting down */
609 usleep(100000);
610 result += static_down(ifd, exec);
611 return ((result == 3) ? 3 : 0);
612}
613# elif ENABLE_UDHCPC
614static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
615{
616 int result;
617 result = execute(
618 "test -f /var/run/udhcpc.%iface%.pid && "
619 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
620 ifd, exec);
621 /* Also bring the hardware interface down since
622 killing the dhcp client alone doesn't do it.
623 This enables consecutive ifup->ifdown->ifup */
624 /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
625 and it may come back up because udhcpc is still shutting down */
626 usleep(100000);
627 result += static_down(ifd, exec);
628 return ((result == 3) ? 3 : 0);
629}
630# else
631static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM,
632 execfn *exec UNUSED_PARAM)
633{
[1765]634 return 0; /* no dhcp support */
[821]635}
[2725]636# endif
[821]637
[2725]638static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
[1765]639{
640 return 1;
641}
642
[2725]643static int FAST_FUNC bootp_up(struct interface_defn_t *ifd, execfn *exec)
[821]644{
[1765]645 return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
646 "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
647 " --returniffail --serverbcast", ifd, exec);
[821]648}
649
[2725]650static int FAST_FUNC ppp_up(struct interface_defn_t *ifd, execfn *exec)
[821]651{
[1765]652 return execute("pon[[ %provider%]]", ifd, exec);
[821]653}
654
[2725]655static int FAST_FUNC ppp_down(struct interface_defn_t *ifd, execfn *exec)
[821]656{
[1765]657 return execute("poff[[ %provider%]]", ifd, exec);
[821]658}
659
[2725]660static int FAST_FUNC wvdial_up(struct interface_defn_t *ifd, execfn *exec)
[821]661{
[1765]662 return execute("start-stop-daemon --start -x wvdial "
663 "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd, exec);
[821]664}
665
[2725]666static int FAST_FUNC wvdial_down(struct interface_defn_t *ifd, execfn *exec)
[821]667{
[1765]668 return execute("start-stop-daemon --stop -x wvdial "
669 "-p /var/run/wvdial.%iface% -s 2", ifd, exec);
[821]670}
671
[1765]672static const struct method_t methods[] = {
[2725]673 { "manual" , manual_up_down, manual_up_down, },
674 { "wvdial" , wvdial_up , wvdial_down , },
675 { "ppp" , ppp_up , ppp_down , },
676 { "static" , static_up , static_down , },
677 { "bootp" , bootp_up , static_down , },
678 { "dhcp" , dhcp_up , dhcp_down , },
679 { "loopback", loopback_up , loopback_down , },
[821]680};
681
[1765]682static const struct address_family_t addr_inet = {
[821]683 "inet",
[1765]684 ARRAY_SIZE(methods),
[821]685 methods
686};
687
[2725]688#endif /* FEATURE_IFUPDOWN_IPV4 */
[821]689
[3621]690static int FAST_FUNC link_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
691{
692 return 1;
693}
[2725]694
[3621]695static const struct method_t link_methods[] = {
696 { "none", link_up_down, link_up_down }
697};
698
699static const struct address_family_t addr_link = {
700 "link", ARRAY_SIZE(link_methods), link_methods
701};
702
[2725]703/* Returns pointer to the next word, or NULL.
704 * In 1st case, advances *buf to the word after this one.
705 */
[821]706static char *next_word(char **buf)
707{
[2725]708 unsigned length;
[821]709 char *word;
710
711 /* Skip over leading whitespace */
[1765]712 word = skip_whitespace(*buf);
[821]713
[2725]714 /* Stop on EOL */
715 if (*word == '\0')
[1765]716 return NULL;
[821]717
[2725]718 /* Find the length of this word (can't be 0) */
[821]719 length = strcspn(word, " \t\n");
720
[2725]721 /* Unless we are already at NUL, store NUL and advance */
722 if (word[length] != '\0')
723 word[length++] = '\0';
724
725 *buf = skip_whitespace(word + length);
726
[821]727 return word;
728}
729
[1765]730static const struct address_family_t *get_address_family(const struct address_family_t *const af[], char *name)
[821]731{
732 int i;
733
[1765]734 if (!name)
735 return NULL;
736
[821]737 for (i = 0; af[i]; i++) {
738 if (strcmp(af[i]->name, name) == 0) {
739 return af[i];
740 }
741 }
742 return NULL;
743}
744
[1765]745static const struct method_t *get_method(const struct address_family_t *af, char *name)
[821]746{
747 int i;
748
[1765]749 if (!name)
750 return NULL;
[2725]751 /* TODO: use index_in_str_array() */
[821]752 for (i = 0; i < af->n_methods; i++) {
753 if (strcmp(af->method[i].name, name) == 0) {
754 return &af->method[i];
755 }
756 }
[1765]757 return NULL;
[821]758}
759
[3621]760static struct interfaces_file_t *read_interfaces(const char *filename, struct interfaces_file_t *defn)
[821]761{
[2725]762 /* Let's try to be compatible.
763 *
764 * "man 5 interfaces" says:
765 * Lines starting with "#" are ignored. Note that end-of-line
766 * comments are NOT supported, comments must be on a line of their own.
767 * A line may be extended across multiple lines by making
768 * the last character a backslash.
769 *
770 * Seen elsewhere in example config file:
771 * A first non-blank "#" character makes the rest of the line
772 * be ignored. Blank lines are ignored. Lines may be indented freely.
773 * A "\" character at the very end of the line indicates the next line
774 * should be treated as a continuation of the current one.
[3621]775 *
776 * Lines beginning with "source" are used to include stanzas from
777 * other files, so configuration can be split into many files.
778 * The word "source" is followed by the path of file to be sourced.
[2725]779 */
[1765]780#if ENABLE_FEATURE_IFUPDOWN_MAPPING
[821]781 struct mapping_defn_t *currmap = NULL;
782#endif
783 struct interface_defn_t *currif = NULL;
784 FILE *f;
785 char *buf;
[2725]786 char *first_word;
787 char *rest_of_line;
[821]788 enum { NONE, IFACE, MAPPING } currently_processing = NONE;
789
[3621]790 if (!defn)
791 defn = xzalloc(sizeof(*defn));
792
793 debug_noise("reading %s file:\n", filename);
[2725]794 f = xfopen_for_read(filename);
[821]795
[2725]796 while ((buf = xmalloc_fgetline(f)) != NULL) {
797#if ENABLE_DESKTOP
798 /* Trailing "\" concatenates lines */
799 char *p;
800 while ((p = last_char_is(buf, '\\')) != NULL) {
801 *p = '\0';
802 rest_of_line = xmalloc_fgetline(f);
803 if (!rest_of_line)
804 break;
805 p = xasprintf("%s%s", buf, rest_of_line);
[821]806 free(buf);
[2725]807 free(rest_of_line);
808 buf = p;
[821]809 }
[2725]810#endif
811 rest_of_line = buf;
812 first_word = next_word(&rest_of_line);
813 if (!first_word || *first_word == '#') {
814 free(buf);
815 continue; /* blank/comment line */
816 }
[821]817
[2725]818 if (strcmp(first_word, "mapping") == 0) {
[1765]819#if ENABLE_FEATURE_IFUPDOWN_MAPPING
[2725]820 currmap = xzalloc(sizeof(*currmap));
[821]821
[2725]822 while ((first_word = next_word(&rest_of_line)) != NULL) {
823 currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches);
824 currmap->match[currmap->n_matches++] = xstrdup(first_word);
[821]825 }
[2725]826 /*currmap->n_mappings = 0;*/
827 /*currmap->mapping = NULL;*/
828 /*currmap->script = NULL;*/
[821]829 {
830 struct mapping_defn_t **where = &defn->mappings;
831 while (*where != NULL) {
832 where = &(*where)->next;
833 }
834 *where = currmap;
[2725]835 /*currmap->next = NULL;*/
[821]836 }
837 debug_noise("Added mapping\n");
838#endif
839 currently_processing = MAPPING;
[2725]840 } else if (strcmp(first_word, "iface") == 0) {
[1765]841 static const struct address_family_t *const addr_fams[] = {
842#if ENABLE_FEATURE_IFUPDOWN_IPV4
843 &addr_inet,
[821]844#endif
[1765]845#if ENABLE_FEATURE_IFUPDOWN_IPV6
846 &addr_inet6,
[821]847#endif
[3621]848 &addr_link,
[1765]849 NULL
850 };
851 char *iface_name;
852 char *address_family_name;
853 char *method_name;
[821]854
[2725]855 currif = xzalloc(sizeof(*currif));
856 iface_name = next_word(&rest_of_line);
857 address_family_name = next_word(&rest_of_line);
858 method_name = next_word(&rest_of_line);
[821]859
[2725]860 if (method_name == NULL)
861 bb_error_msg_and_die("too few parameters for line \"%s\"", buf);
[821]862
[1765]863 /* ship any trailing whitespace */
[2725]864 rest_of_line = skip_whitespace(rest_of_line);
[821]865
[2725]866 if (rest_of_line[0] != '\0' /* && rest_of_line[0] != '#' */)
867 bb_error_msg_and_die("too many parameters \"%s\"", buf);
[821]868
[1765]869 currif->iface = xstrdup(iface_name);
[821]870
[1765]871 currif->address_family = get_address_family(addr_fams, address_family_name);
[2725]872 if (!currif->address_family)
873 bb_error_msg_and_die("unknown address type \"%s\"", address_family_name);
[821]874
[1765]875 currif->method = get_method(currif->address_family, method_name);
[2725]876 if (!currif->method)
877 bb_error_msg_and_die("unknown method \"%s\"", method_name);
[3621]878#if 0
879// Allegedly, Debian allows a duplicate definition:
880// iface eth0 inet static
881// address 192.168.0.15
882// netmask 255.255.0.0
883// gateway 192.168.0.1
884//
885// iface eth0 inet static
886// address 10.0.0.1
887// netmask 255.255.255.0
888//
889// This adds *two* addresses to eth0 (probably requires use of "ip", not "ifconfig"
890//
891 llist_t *iface_list;
[1765]892 for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
893 struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
[2725]894 if ((strcmp(tmp->iface, currif->iface) == 0)
895 && (tmp->address_family == currif->address_family)
896 ) {
897 bb_error_msg_and_die("duplicate interface \"%s\"", tmp->iface);
[821]898 }
899 }
[3621]900#endif
[1765]901 llist_add_to_end(&(defn->ifaces), (char*)currif);
902
903 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
[821]904 currently_processing = IFACE;
[2725]905 } else if (strcmp(first_word, "auto") == 0) {
906 while ((first_word = next_word(&rest_of_line)) != NULL) {
[821]907
908 /* Check the interface isnt already listed */
[2725]909 if (llist_find_str(defn->autointerfaces, first_word)) {
[821]910 bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf);
911 }
912
913 /* Add the interface to the list */
[2725]914 llist_add_to_end(&(defn->autointerfaces), xstrdup(first_word));
915 debug_noise("\nauto %s\n", first_word);
[821]916 }
917 currently_processing = NONE;
[3621]918 } else if (strcmp(first_word, "source") == 0) {
919 read_interfaces(next_word(&rest_of_line), defn);
[821]920 } else {
921 switch (currently_processing) {
[1765]922 case IFACE:
[2725]923 if (rest_of_line[0] == '\0')
924 bb_error_msg_and_die("option with empty value \"%s\"", buf);
925
[3232]926 if (strcmp(first_word, "post-up") == 0)
927 first_word += 5; /* "up" */
928 else if (strcmp(first_word, "pre-down") == 0)
929 first_word += 4; /* "down" */
930
931 /* If not one of "up", "down",... words... */
932 if (index_in_strings(keywords_up_down, first_word) < 0) {
[1765]933 int i;
[2725]934 for (i = 0; i < currif->n_options; i++) {
935 if (strcmp(currif->option[i].name, first_word) == 0)
936 bb_error_msg_and_die("duplicate option \"%s\"", buf);
[1765]937 }
938 }
[2725]939 debug_noise("\t%s=%s\n", first_word, rest_of_line);
[3232]940 currif->option = xrealloc_vector(currif->option, 4, currif->n_options);
[2725]941 currif->option[currif->n_options].name = xstrdup(first_word);
942 currif->option[currif->n_options].value = xstrdup(rest_of_line);
[1765]943 currif->n_options++;
944 break;
945 case MAPPING:
946#if ENABLE_FEATURE_IFUPDOWN_MAPPING
[2725]947 if (strcmp(first_word, "script") == 0) {
948 if (currmap->script != NULL)
949 bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf);
950 currmap->script = xstrdup(next_word(&rest_of_line));
951 } else if (strcmp(first_word, "map") == 0) {
[3232]952 currmap->mapping = xrealloc_vector(currmap->mapping, 2, currmap->n_mappings);
[2725]953 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line));
[1765]954 currmap->n_mappings++;
955 } else {
[2725]956 bb_error_msg_and_die("misplaced option \"%s\"", buf);
[1765]957 }
958#endif
959 break;
960 case NONE:
961 default:
[2725]962 bb_error_msg_and_die("misplaced option \"%s\"", buf);
[821]963 }
964 }
965 free(buf);
[2725]966 } /* while (fgets) */
967
[821]968 if (ferror(f) != 0) {
[1765]969 /* ferror does NOT set errno! */
970 bb_error_msg_and_die("%s: I/O error", filename);
[821]971 }
972 fclose(f);
[3621]973 debug_noise("\ndone reading %s\n\n", filename);
[821]974
975 return defn;
976}
977
[1765]978static char *setlocalenv(const char *format, const char *name, const char *value)
[821]979{
980 char *result;
[2725]981 char *dst;
982 char *src;
983 char c;
[821]984
[1765]985 result = xasprintf(format, name, value);
[821]986
[2725]987 for (dst = src = result; (c = *src) != '=' && c; src++) {
988 if (c == '-')
989 c = '_';
990 if (c >= 'a' && c <= 'z')
991 c -= ('a' - 'A');
992 if (isalnum(c) || c == '_')
993 *dst++ = c;
[821]994 }
[2725]995 overlapping_strcpy(dst, src);
[821]996
997 return result;
998}
999
[3232]1000static void set_environ(struct interface_defn_t *iface, const char *mode, const char *opt)
[821]1001{
1002 int i;
[2725]1003 char **pp;
[821]1004
[2725]1005 if (G.my_environ != NULL) {
1006 for (pp = G.my_environ; *pp; pp++) {
1007 free(*pp);
[821]1008 }
[2725]1009 free(G.my_environ);
[821]1010 }
1011
[2725]1012 /* note: last element will stay NULL: */
[3232]1013 G.my_environ = xzalloc(sizeof(char *) * (iface->n_options + 7));
[2725]1014 pp = G.my_environ;
1015
[821]1016 for (i = 0; i < iface->n_options; i++) {
[3232]1017 if (index_in_strings(keywords_up_down, iface->option[i].name) >= 0) {
[821]1018 continue;
1019 }
[2725]1020 *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
[821]1021 }
1022
[2725]1023 *pp++ = setlocalenv("%s=%s", "IFACE", iface->iface);
1024 *pp++ = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
1025 *pp++ = setlocalenv("%s=%s", "METHOD", iface->method->name);
1026 *pp++ = setlocalenv("%s=%s", "MODE", mode);
[3232]1027 *pp++ = setlocalenv("%s=%s", "PHASE", opt);
[2725]1028 if (G.startup_PATH)
1029 *pp++ = setlocalenv("%s=%s", "PATH", G.startup_PATH);
[821]1030}
1031
1032static int doit(char *str)
1033{
[1765]1034 if (option_mask32 & (OPT_no_act|OPT_verbose)) {
1035 puts(str);
[821]1036 }
[1765]1037 if (!(option_mask32 & OPT_no_act)) {
[821]1038 pid_t child;
1039 int status;
1040
[2725]1041 fflush_all();
1042 child = vfork();
[3232]1043 if (child < 0) /* failure */
[1765]1044 return 0;
[3232]1045 if (child == 0) { /* child */
1046 execle(G.shell, G.shell, "-c", str, (char *) NULL, G.my_environ);
[2725]1047 _exit(127);
[821]1048 }
[2725]1049 safe_waitpid(child, &status, 0);
[821]1050 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1051 return 0;
1052 }
1053 }
[1765]1054 return 1;
[821]1055}
1056
1057static int execute_all(struct interface_defn_t *ifd, const char *opt)
1058{
1059 int i;
1060 char *buf;
1061 for (i = 0; i < ifd->n_options; i++) {
1062 if (strcmp(ifd->option[i].name, opt) == 0) {
1063 if (!doit(ifd->option[i].value)) {
1064 return 0;
1065 }
1066 }
1067 }
1068
[1765]1069 buf = xasprintf("run-parts /etc/network/if-%s.d", opt);
1070 /* heh, we don't bother free'ing it */
1071 return doit(buf);
[821]1072}
1073
[1765]1074static int check(char *str)
1075{
[821]1076 return str != NULL;
1077}
1078
1079static int iface_up(struct interface_defn_t *iface)
1080{
[1765]1081 if (!iface->method->up(iface, check)) return -1;
[3232]1082 set_environ(iface, "start", "pre-up");
[821]1083 if (!execute_all(iface, "pre-up")) return 0;
1084 if (!iface->method->up(iface, doit)) return 0;
[3232]1085 set_environ(iface, "start", "post-up");
[821]1086 if (!execute_all(iface, "up")) return 0;
1087 return 1;
1088}
1089
1090static int iface_down(struct interface_defn_t *iface)
1091{
[3232]1092 if (!iface->method->down(iface, check)) return -1;
1093 set_environ(iface, "stop", "pre-down");
[821]1094 if (!execute_all(iface, "down")) return 0;
1095 if (!iface->method->down(iface, doit)) return 0;
[3232]1096 set_environ(iface, "stop", "post-down");
[821]1097 if (!execute_all(iface, "post-down")) return 0;
1098 return 1;
1099}
1100
[1765]1101#if ENABLE_FEATURE_IFUPDOWN_MAPPING
[2725]1102static int popen2(FILE **in, FILE **out, char *command, char *param)
[821]1103{
[2725]1104 char *argv[3] = { command, param, NULL };
1105 struct fd_pair infd, outfd;
[821]1106 pid_t pid;
1107
[2725]1108 xpiped_pair(infd);
1109 xpiped_pair(outfd);
[821]1110
[2725]1111 fflush_all();
1112 pid = xvfork();
[821]1113
[2725]1114 if (pid == 0) {
1115 /* Child */
1116 /* NB: close _first_, then move fds! */
1117 close(infd.wr);
1118 close(outfd.rd);
1119 xmove_fd(infd.rd, 0);
1120 xmove_fd(outfd.wr, 1);
1121 BB_EXECVP_or_die(argv);
[821]1122 }
[2725]1123 /* parent */
1124 close(infd.rd);
1125 close(outfd.wr);
1126 *in = xfdopen_for_write(infd.wr);
1127 *out = xfdopen_for_read(outfd.rd);
1128 return pid;
[821]1129}
1130
[2725]1131static char *run_mapping(char *physical, struct mapping_defn_t *map)
[821]1132{
1133 FILE *in, *out;
1134 int i, status;
1135 pid_t pid;
1136
[1765]1137 char *logical = xstrdup(physical);
[821]1138
[2725]1139 /* Run the mapping script. Never fails. */
1140 pid = popen2(&in, &out, map->script, physical);
[821]1141
1142 /* Write mappings to stdin of mapping script. */
1143 for (i = 0; i < map->n_mappings; i++) {
1144 fprintf(in, "%s\n", map->mapping[i]);
1145 }
1146 fclose(in);
[2725]1147 safe_waitpid(pid, &status, 0);
[821]1148
1149 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1150 /* If the mapping script exited successfully, try to
1151 * grab a line of output and use that as the name of the
1152 * logical interface. */
[2725]1153 char *new_logical = xmalloc_fgetline(out);
[821]1154
[2725]1155 if (new_logical) {
[821]1156 /* If we are able to read a line of output from the script,
1157 * remove any trailing whitespace and use this value
1158 * as the name of the logical interface. */
1159 char *pch = new_logical + strlen(new_logical) - 1;
1160
1161 while (pch >= new_logical && isspace(*pch))
1162 *(pch--) = '\0';
1163
1164 free(logical);
1165 logical = new_logical;
1166 }
1167 }
1168
1169 fclose(out);
1170
1171 return logical;
1172}
[1765]1173#endif /* FEATURE_IFUPDOWN_MAPPING */
[821]1174
1175static llist_t *find_iface_state(llist_t *state_list, const char *iface)
1176{
1177 llist_t *search = state_list;
1178
1179 while (search) {
[3621]1180 char *after_iface = is_prefixed_with(search->data, iface);
1181 if (after_iface
1182 && *after_iface == '='
[2725]1183 ) {
[1765]1184 return search;
[821]1185 }
1186 search = search->link;
1187 }
[1765]1188 return NULL;
[821]1189}
1190
[1765]1191/* read the previous state from the state file */
1192static llist_t *read_iface_state(void)
1193{
1194 llist_t *state_list = NULL;
[2725]1195 FILE *state_fp = fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH);
[1765]1196
1197 if (state_fp) {
1198 char *start, *end_ptr;
1199 while ((start = xmalloc_fgets(state_fp)) != NULL) {
1200 /* We should only need to check for a single character */
1201 end_ptr = start + strcspn(start, " \t\n");
1202 *end_ptr = '\0';
1203 llist_add_to(&state_list, start);
1204 }
1205 fclose(state_fp);
1206 }
1207 return state_list;
1208}
1209
1210
[2725]1211int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1212int ifupdown_main(int argc UNUSED_PARAM, char **argv)
[821]1213{
[2725]1214 int (*cmds)(struct interface_defn_t *);
[821]1215 struct interfaces_file_t *defn;
1216 llist_t *target_list = NULL;
1217 const char *interfaces = "/etc/network/interfaces";
[1765]1218 bool any_failures = 0;
[821]1219
[2725]1220 INIT_G();
1221
1222 G.startup_PATH = getenv("PATH");
[3232]1223 G.shell = xstrdup(get_shell_name());
[2725]1224
[1765]1225 cmds = iface_down;
1226 if (applet_name[2] == 'u') {
[821]1227 /* ifup command */
1228 cmds = iface_up;
1229 }
1230
[1765]1231 getopt32(argv, OPTION_STR, &interfaces);
[2725]1232 argv += optind;
1233 if (argv[0]) {
[1765]1234 if (DO_ALL) bb_show_usage();
[821]1235 } else {
[1765]1236 if (!DO_ALL) bb_show_usage();
[821]1237 }
1238
[3621]1239 defn = read_interfaces(interfaces, NULL);
[821]1240
1241 /* Create a list of interfaces to work on */
[1765]1242 if (DO_ALL) {
1243 target_list = defn->autointerfaces;
[821]1244 } else {
[2725]1245 llist_add_to_end(&target_list, argv[0]);
[821]1246 }
1247
1248 /* Update the interfaces */
1249 while (target_list) {
1250 llist_t *iface_list;
1251 struct interface_defn_t *currif;
1252 char *iface;
1253 char *liface;
1254 char *pch;
[1765]1255 bool okay = 0;
[2725]1256 int cmds_ret;
[3621]1257 bool curr_failure = 0;
[821]1258
[1765]1259 iface = xstrdup(target_list->data);
[821]1260 target_list = target_list->link;
1261
1262 pch = strchr(iface, '=');
1263 if (pch) {
1264 *pch = '\0';
[1765]1265 liface = xstrdup(pch + 1);
[821]1266 } else {
[1765]1267 liface = xstrdup(iface);
[821]1268 }
1269
[1765]1270 if (!FORCE) {
1271 llist_t *state_list = read_iface_state();
[821]1272 const llist_t *iface_state = find_iface_state(state_list, iface);
1273
1274 if (cmds == iface_up) {
1275 /* ifup */
1276 if (iface_state) {
1277 bb_error_msg("interface %s already configured", iface);
[3232]1278 goto next;
[821]1279 }
1280 } else {
1281 /* ifdown */
[1765]1282 if (!iface_state) {
[821]1283 bb_error_msg("interface %s not configured", iface);
[3232]1284 goto next;
[821]1285 }
1286 }
[1765]1287 llist_free(state_list, free);
[821]1288 }
1289
[1765]1290#if ENABLE_FEATURE_IFUPDOWN_MAPPING
1291 if ((cmds == iface_up) && !NO_MAPPINGS) {
[821]1292 struct mapping_defn_t *currmap;
1293
1294 for (currmap = defn->mappings; currmap; currmap = currmap->next) {
[1765]1295 int i;
[821]1296 for (i = 0; i < currmap->n_matches; i++) {
1297 if (fnmatch(currmap->match[i], liface, 0) != 0)
1298 continue;
[1765]1299 if (VERBOSE) {
[821]1300 printf("Running mapping script %s on %s\n", currmap->script, liface);
1301 }
1302 liface = run_mapping(iface, currmap);
1303 break;
1304 }
1305 }
1306 }
1307#endif
1308
1309 iface_list = defn->ifaces;
1310 while (iface_list) {
1311 currif = (struct interface_defn_t *) iface_list->data;
1312 if (strcmp(liface, currif->iface) == 0) {
1313 char *oldiface = currif->iface;
1314
1315 okay = 1;
1316 currif->iface = iface;
1317
1318 debug_noise("\nConfiguring interface %s (%s)\n", liface, currif->address_family->name);
1319
1320 /* Call the cmds function pointer, does either iface_up() or iface_down() */
1321 cmds_ret = cmds(currif);
1322 if (cmds_ret == -1) {
[3621]1323 bb_error_msg("don't have all variables for %s/%s",
[821]1324 liface, currif->address_family->name);
[3621]1325 any_failures = curr_failure = 1;
[821]1326 } else if (cmds_ret == 0) {
[3621]1327 any_failures = curr_failure = 1;
[821]1328 }
1329
1330 currif->iface = oldiface;
1331 }
1332 iface_list = iface_list->link;
1333 }
[1765]1334 if (VERBOSE) {
[2725]1335 bb_putchar('\n');
[821]1336 }
1337
[1765]1338 if (!okay && !FORCE) {
1339 bb_error_msg("ignoring unknown interface %s", liface);
1340 any_failures = 1;
1341 } else if (!NO_ACT) {
1342 /* update the state file */
1343 FILE *state_fp;
1344 llist_t *state;
1345 llist_t *state_list = read_iface_state();
[821]1346 llist_t *iface_state = find_iface_state(state_list, iface);
1347
[3621]1348 if (cmds == iface_up && !curr_failure) {
[3232]1349 char *newiface = xasprintf("%s=%s", iface, liface);
1350 if (!iface_state) {
[821]1351 llist_add_to_end(&state_list, newiface);
1352 } else {
1353 free(iface_state->data);
1354 iface_state->data = newiface;
1355 }
1356 } else {
[1765]1357 /* Remove an interface from state_list */
1358 llist_unlink(&state_list, iface_state);
[821]1359 free(llist_pop(&iface_state));
1360 }
1361
[1765]1362 /* Actually write the new state */
[2725]1363 state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH);
[1765]1364 state = state_list;
1365 while (state) {
1366 if (state->data) {
1367 fprintf(state_fp, "%s\n", state->data);
1368 }
1369 state = state->link;
[821]1370 }
[1765]1371 fclose(state_fp);
1372 llist_free(state_list, free);
[821]1373 }
[3232]1374 next:
1375 free(iface);
1376 free(liface);
[821]1377 }
1378
[1765]1379 return any_failures;
[821]1380}
Note: See TracBrowser for help on using the repository browser.