Magellan Linux

Diff of /tags/mkinitrd-6_1_11/busybox/networking/ifupdown.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 1  Line 1 
1  /* vi: set sw=4 ts=4: */  /* vi: set sw=4 ts=4: */
2  /*  /*
3   *  ifupdown for busybox   *  ifupdown for busybox
4   *  Copyright (c) 2002 Glenn McGrath <bug1@iinet.net.au>   *  Copyright (c) 2002 Glenn McGrath
5   *  Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>   *  Copyright (c) 2003-2004 Erik Andersen <andersen@codepoet.org>
6   *   *
7   *  Based on ifupdown v 0.6.4 by Anthony Towns   *  Based on ifupdown v 0.6.4 by Anthony Towns
# Line 10  Line 10 
10   *  Changes to upstream version   *  Changes to upstream version
11   *  Remove checks for kernel version, assume kernel version 2.2.0 or better.   *  Remove checks for kernel version, assume kernel version 2.2.0 or better.
12   *  Lines in the interfaces file cannot wrap.   *  Lines in the interfaces file cannot wrap.
13   *  To adhere to the FHS, the default state file is /var/run/ifstate.   *  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.
16   *   *
17   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
18   */   */
19    
 #include "busybox.h"  
20  #include <sys/utsname.h>  #include <sys/utsname.h>
21  #include <fnmatch.h>  #include <fnmatch.h>
22  #include <getopt.h>  
23    #include "libbb.h"
24    
25  #define MAX_OPT_DEPTH 10  #define MAX_OPT_DEPTH 10
26  #define EUNBALBRACK 10001  #define EUNBALBRACK 10001
# Line 36  struct interface_defn_t; Line 38  struct interface_defn_t;
38    
39  typedef int execfn(char *command);  typedef int execfn(char *command);
40    
41  struct method_t  struct method_t {
42  {   const char *name;
  char *name;  
43   int (*up)(struct interface_defn_t *ifd, execfn *e);   int (*up)(struct interface_defn_t *ifd, execfn *e);
44   int (*down)(struct interface_defn_t *ifd, execfn *e);   int (*down)(struct interface_defn_t *ifd, execfn *e);
45  };  };
46    
47  struct address_family_t  struct address_family_t {
48  {   const char *name;
  char *name;  
49   int n_methods;   int n_methods;
50   const struct method_t *method;   const struct method_t *method;
51  };  };
52    
53  struct mapping_defn_t  struct mapping_defn_t {
 {  
54   struct mapping_defn_t *next;   struct mapping_defn_t *next;
55    
56   int max_matches;   int max_matches;
# Line 65  struct mapping_defn_t Line 64  struct mapping_defn_t
64   char **mapping;   char **mapping;
65  };  };
66    
67  struct variable_t  struct variable_t {
 {  
68   char *name;   char *name;
69   char *value;   char *value;
70  };  };
71    
72  struct interface_defn_t  struct interface_defn_t {
 {  
73   const struct address_family_t *address_family;   const struct address_family_t *address_family;
74   const struct method_t *method;   const struct method_t *method;
75    
# Line 82  struct interface_defn_t Line 79  struct interface_defn_t
79   struct variable_t *option;   struct variable_t *option;
80  };  };
81    
82  struct interfaces_file_t  struct interfaces_file_t {
 {  
83   llist_t *autointerfaces;   llist_t *autointerfaces;
84   llist_t *ifaces;   llist_t *ifaces;
85   struct mapping_defn_t *mappings;   struct mapping_defn_t *mappings;
# Line 105  enum { Line 101  enum {
101    
102  static char **my_environ;  static char **my_environ;
103    
104  static char *startup_PATH;  static const char *startup_PATH;
105    
106  #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6  #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
107    
 #if ENABLE_FEATURE_IFUPDOWN_IP  
   
 static unsigned count_bits(unsigned a)  
 {  
  unsigned result;  
  result = (a & 0x55) + ((a >> 1) & 0x55);  
  result = (result & 0x33) + ((result >> 2) & 0x33);  
  return (result & 0x0F) + ((result >> 4) & 0x0F);  
 }  
   
 static int count_netmask_bits(char *dotted_quad)  
 {  
  unsigned result, a, b, c, d;  
  /* Found a netmask...  Check if it is dotted quad */  
  if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)  
  return -1;  
  // FIXME: will be confused by e.g. 255.0.255.0  
  result = count_bits(a);  
  result += count_bits(b);  
  result += count_bits(c);  
  result += count_bits(d);  
  return (int)result;  
 }  
 #endif  
   
108  static void addstr(char **bufp, const char *str, size_t str_length)  static void addstr(char **bufp, const char *str, size_t str_length)
109  {  {
110   /* xasprintf trick will be smaller, but we are often   /* xasprintf trick will be smaller, but we are often
# Line 162  static char *get_var(const char *id, siz Line 133  static char *get_var(const char *id, siz
133   int i;   int i;
134    
135   if (strncmpz(id, "iface", idlen) == 0) {   if (strncmpz(id, "iface", idlen) == 0) {
136   char *result;   static char *label_buf;
137   static char label_buf[20];   //char *result;
138   safe_strncpy(label_buf, ifd->iface, sizeof(label_buf));  
139   result = strchr(label_buf, ':');   free(label_buf);
140   if (result) {   label_buf = xstrdup(ifd->iface);
141   *result = '\0';   // Remove virtual iface suffix - why?
142   }   // ubuntu's ifup doesn't do this
143     //result = strchrnul(label_buf, ':');
144     //*result = '\0';
145   return label_buf;   return label_buf;
146   }   }
147   if (strncmpz(id, "label", idlen) == 0) {   if (strncmpz(id, "label", idlen) == 0) {
# Line 182  static char *get_var(const char *id, siz Line 155  static char *get_var(const char *id, siz
155   return NULL;   return NULL;
156  }  }
157    
158    #if ENABLE_FEATURE_IFUPDOWN_IP
159    static int count_netmask_bits(const char *dotted_quad)
160    {
161    // int result;
162    // unsigned a, b, c, d;
163    // /* Found a netmask...  Check if it is dotted quad */
164    // if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
165    // return -1;
166    // if ((a|b|c|d) >> 8)
167    // return -1; /* one of numbers is >= 256 */
168    // d |= (a << 24) | (b << 16) | (c << 8); /* IP */
169    // d = ~d; /* 11110000 -> 00001111 */
170    
171     /* Shorter version */
172     int result;
173     struct in_addr ip;
174     unsigned d;
175    
176     if (inet_aton(dotted_quad, &ip) == 0)
177     return -1; /* malformed dotted IP */
178     d = ntohl(ip.s_addr); /* IP in host order */
179     d = ~d; /* 11110000 -> 00001111 */
180     if (d & (d+1)) /* check that it is in 00001111 form */
181     return -1; /* no it is not */
182     result = 32;
183     while (d) {
184     d >>= 1;
185     result--;
186     }
187     return result;
188    }
189    #endif
190    
191  static char *parse(const char *command, struct interface_defn_t *ifd)  static char *parse(const char *command, struct interface_defn_t *ifd)
192  {  {
193   size_t old_pos[MAX_OPT_DEPTH] = { 0 };   size_t old_pos[MAX_OPT_DEPTH] = { 0 };
# Line 243  static char *parse(const char *command, Line 249  static char *parse(const char *command,
249   varvalue = get_var(command, nextpercent - command, ifd);   varvalue = get_var(command, nextpercent - command, ifd);
250    
251   if (varvalue) {   if (varvalue) {
252    #if ENABLE_FEATURE_IFUPDOWN_IP
253     /* "hwaddress <class> <address>":
254     * unlike ifconfig, ip doesnt want <class>
255     * (usually "ether" keyword). Skip it. */
256     if (strncmp(command, "hwaddress", 9) == 0) {
257     varvalue = skip_whitespace(skip_non_whitespace(varvalue));
258     }
259    #endif
260   addstr(&result, varvalue, strlen(varvalue));   addstr(&result, varvalue, strlen(varvalue));
261   } else {   } else {
262  #if ENABLE_FEATURE_IFUPDOWN_IP  #if ENABLE_FEATURE_IFUPDOWN_IP
# Line 251  static char *parse(const char *command, Line 265  static char *parse(const char *command,
265   if (strncmp(command, "bnmask", 6) == 0) {   if (strncmp(command, "bnmask", 6) == 0) {
266   unsigned res;   unsigned res;
267   varvalue = get_var("netmask", 7, ifd);   varvalue = get_var("netmask", 7, ifd);
268   if (varvalue && (res = count_netmask_bits(varvalue)) > 0) {   if (varvalue) {
269   const char *argument = utoa(res);   res = count_netmask_bits(varvalue);
270   addstr(&result, argument, strlen(argument));   if (res > 0) {
271   command = nextpercent + 1;   const char *argument = utoa(res);
272   break;   addstr(&result, argument, strlen(argument));
273     command = nextpercent + 1;
274     break;
275     }
276   }   }
277   }   }
278  #endif  #endif
# Line 332  static int static_up6(struct interface_d Line 349  static int static_up6(struct interface_d
349   int result;   int result;
350  #if ENABLE_FEATURE_IFUPDOWN_IP  #if ENABLE_FEATURE_IFUPDOWN_IP
351   result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);   result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
352   result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);   result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
353   /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */   /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
354   result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);   result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
355  #else  #else
# Line 380  static const struct method_t methods6[] Line 397  static const struct method_t methods6[]
397    
398  static const struct address_family_t addr_inet6 = {  static const struct address_family_t addr_inet6 = {
399   "inet6",   "inet6",
400   sizeof(methods6) / sizeof(struct method_t),   ARRAY_SIZE(methods6),
401   methods6   methods6
402  };  };
403  #endif /* FEATURE_IFUPDOWN_IPV6 */  #endif /* FEATURE_IFUPDOWN_IPV6 */
# Line 416  static int static_up(struct interface_de Line 433  static int static_up(struct interface_de
433  #if ENABLE_FEATURE_IFUPDOWN_IP  #if ENABLE_FEATURE_IFUPDOWN_IP
434   result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "   result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
435   "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);   "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
436   result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);   result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
437   result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);   result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
438   return ((result == 3) ? 3 : 0);   return ((result == 3) ? 3 : 0);
439  #else  #else
# Line 427  static int static_up(struct interface_de Line 444  static int static_up(struct interface_de
444   result += execute("ifconfig %iface% %address% netmask %netmask%"   result += execute("ifconfig %iface% %address% netmask %netmask%"
445   "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",   "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
446   ifd, exec);   ifd, exec);
447   result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);   result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
448   return ((result == 3) ? 3 : 0);   return ((result == 3) ? 3 : 0);
449  #endif  #endif
450  }  }
# Line 439  static int static_down(struct interface_ Line 456  static int static_down(struct interface_
456   result = execute("ip addr flush dev %iface%", ifd, exec);   result = execute("ip addr flush dev %iface%", ifd, exec);
457   result += execute("ip link set %iface% down", ifd, exec);   result += execute("ip link set %iface% down", ifd, exec);
458  #else  #else
459   result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec);   /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */
460     /* Bringing the interface down deletes the routes in itself.
461       Otherwise this fails if we reference 'gateway' when using this from dhcp_down */
462     result = 1;
463   result += execute("ifconfig %iface% down", ifd, exec);   result += execute("ifconfig %iface% down", ifd, exec);
464  #endif  #endif
465   return ((result == 2) ? 2 : 0);   return ((result == 2) ? 2 : 0);
466  }  }
467    
468  #if !ENABLE_APP_UDHCPC  #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
469  struct dhcp_client_t  struct dhcp_client_t
470  {  {
471   const char *name;   const char *name;
# Line 454  struct dhcp_client_t Line 474  struct dhcp_client_t
474  };  };
475    
476  static const struct dhcp_client_t ext_dhcp_clients[] = {  static const struct dhcp_client_t ext_dhcp_clients[] = {
477   { "udhcpc",   { "dhcpcd",
478   "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",   "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",
479   "kill -TERM `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",   "dhcpcd -k %iface%",
  },  
  { "pump",  
  "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",  
  "pump -i %iface% -k",  
480   },   },
481   { "dhclient",   { "dhclient",
482   "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",   "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
483   "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",   "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
484   },   },
485   { "dhcpcd",   { "pump",
486   "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",   "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
487   "dhcpcd -k %iface%",   "pump -i %iface% -k",
488     },
489     { "udhcpc",
490     "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]]"
491     "[[ -s %script%]][[ %udhcpc_opts%]]",
492     "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
493   },   },
494  };  };
495  #endif  #endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
496    
497    #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
498  static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)  static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
499  {  {
500  #if ENABLE_APP_UDHCPC   unsigned i;
501   return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid "  #if ENABLE_FEATURE_IFUPDOWN_IP
502   "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",   /* ip doesn't up iface when it configures it (unlike ifconfig) */
503   ifd, exec);   if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
504     return 0;
505  #else  #else
506   int i, nclients = sizeof(ext_dhcp_clients) / sizeof(ext_dhcp_clients[0]);   /* needed if we have hwaddress on dhcp iface */
507   for (i = 0; i < nclients; i++) {   if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
508     return 0;
509    #endif
510     for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
511   if (exists_execable(ext_dhcp_clients[i].name))   if (exists_execable(ext_dhcp_clients[i].name))
512   return execute(ext_dhcp_clients[i].startcmd, ifd, exec);   return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
513   }   }
514   bb_error_msg("no dhcp clients found");   bb_error_msg("no dhcp clients found");
515   return 0;   return 0;
516    }
517    #elif ENABLE_APP_UDHCPC
518    static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
519    {
520    #if ENABLE_FEATURE_IFUPDOWN_IP
521     /* ip doesn't up iface when it configures it (unlike ifconfig) */
522     if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
523     return 0;
524    #else
525     /* needed if we have hwaddress on dhcp iface */
526     if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
527     return 0;
528  #endif  #endif
529     return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid "
530     "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]][[ %udhcpc_opts%]]",
531     ifd, exec);
532    }
533    #else
534    static int dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM,
535     execfn *exec UNUSED_PARAM)
536    {
537     return 0; /* no dhcp support */
538  }  }
539    #endif
540    
541    #if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
542    static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
543    {
544     int result = 0;
545     unsigned i;
546    
547     for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
548     if (exists_execable(ext_dhcp_clients[i].name)) {
549     result += execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
550     if (result)
551     break;
552     }
553     }
554    
555     if (!result)
556     bb_error_msg("warning: no dhcp clients found and stopped");
557    
558     /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
559       and it may come back up because udhcpc is still shutting down */
560     usleep(100000);
561     result += static_down(ifd, exec);
562     return ((result == 3) ? 3 : 0);
563    }
564    #elif ENABLE_APP_UDHCPC
565  static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)  static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
566  {  {
567  #if ENABLE_APP_UDHCPC   int result;
568   return execute("kill -TERM "   result = execute("kill "
569                 "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);                 "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
570     /* Also bring the hardware interface down since
571       killing the dhcp client alone doesn't do it.
572       This enables consecutive ifup->ifdown->ifup */
573     /* Sleep a bit, otherwise static_down tries to bring down interface too soon,
574       and it may come back up because udhcpc is still shutting down */
575     usleep(100000);
576     result += static_down(ifd, exec);
577     return ((result == 3) ? 3 : 0);
578    }
579  #else  #else
580   int i, nclients = sizeof(ext_dhcp_clients) / sizeof(ext_dhcp_clients[0]);  static int dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM,
581   for (i = 0; i < nclients; i++) {   execfn *exec UNUSED_PARAM)
582   if (exists_execable(ext_dhcp_clients[i].name))  {
583   return execute(ext_dhcp_clients[i].stopcmd, ifd, exec);   return 0; /* no dhcp support */
  }  
  bb_error_msg("no dhcp clients found, using static interface shutdown");  
  return static_down(ifd, exec);  
 #endif  
584  }  }
585    #endif
586    
587  static int manual_up_down(struct interface_defn_t *ifd, execfn *exec)  static int manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
588  {  {
589   return 1;   return 1;
590  }  }
# Line 514  static int manual_up_down(struct interfa Line 592  static int manual_up_down(struct interfa
592  static int bootp_up(struct interface_defn_t *ifd, execfn *exec)  static int bootp_up(struct interface_defn_t *ifd, execfn *exec)
593  {  {
594   return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"   return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
595   "[[ --server %server%]][[ --hwaddr %hwaddr%]] "   "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
596   "--returniffail --serverbcast", ifd, exec);   " --returniffail --serverbcast", ifd, exec);
597  }  }
598    
599  static int ppp_up(struct interface_defn_t *ifd, execfn *exec)  static int ppp_up(struct interface_defn_t *ifd, execfn *exec)
# Line 552  static const struct method_t methods[] = Line 630  static const struct method_t methods[] =
630    
631  static const struct address_family_t addr_inet = {  static const struct address_family_t addr_inet = {
632   "inet",   "inet",
633   sizeof(methods) / sizeof(struct method_t),   ARRAY_SIZE(methods),
634   methods   methods
635  };  };
636    
# Line 560  static const struct address_family_t add Line 638  static const struct address_family_t add
638    
639  static char *next_word(char **buf)  static char *next_word(char **buf)
640  {  {
641   unsigned short length;   unsigned length;
642   char *word;   char *word;
643    
  if (!buf || !*buf || !**buf) {  
  return NULL;  
  }  
   
644   /* Skip over leading whitespace */   /* Skip over leading whitespace */
645   word = skip_whitespace(*buf);   word = skip_whitespace(*buf);
646    
647   /* Skip over comments */   /* Stop on EOL */
648   if (*word == '#') {   if (*word == '\0')
649   return NULL;   return NULL;
  }  
650    
651   /* Find the length of this word */   /* Find the length of this word (can't be 0) */
652   length = strcspn(word, " \t\n");   length = strcspn(word, " \t\n");
653   if (length == 0) {  
654   return NULL;   /* Unless we are already at NUL, store NUL and advance */
655   }   if (word[length] != '\0')
656     word[length++] = '\0';
657    
658   *buf = word + length;   *buf = word + length;
  /*DBU:[dave@cray.com] if we are already at EOL dont't increment beyond it */  
  if (**buf) {  
  **buf = '\0';  
  (*buf)++;  
  }  
659    
660   return word;   return word;
661  }  }
# Line 611  static const struct method_t *get_method Line 681  static const struct method_t *get_method
681    
682   if (!name)   if (!name)
683   return NULL;   return NULL;
684     /* TODO: use index_in_str_array() */
685   for (i = 0; i < af->n_methods; i++) {   for (i = 0; i < af->n_methods; i++) {
686   if (strcmp(af->method[i].name, name) == 0) {   if (strcmp(af->method[i].name, name) == 0) {
687   return &af->method[i];   return &af->method[i];
# Line 636  static const llist_t *find_list_string(c Line 706  static const llist_t *find_list_string(c
706    
707  static struct interfaces_file_t *read_interfaces(const char *filename)  static struct interfaces_file_t *read_interfaces(const char *filename)
708  {  {
709     /* Let's try to be compatible.
710     *
711     * "man 5 interfaces" says:
712     * Lines starting with "#" are ignored. Note that end-of-line
713     * comments are NOT supported, comments must be on a line of their own.
714     * A line may be extended across multiple lines by making
715     * the last character a backslash.
716     *
717     * Seen elsewhere in example config file:
718     * A first non-blank "#" character makes the rest of the line
719     * be ignored. Blank lines are ignored. Lines may be indented freely.
720     * A "\" character at the very end of the line indicates the next line
721     * should be treated as a continuation of the current one.
722     */
723  #if ENABLE_FEATURE_IFUPDOWN_MAPPING  #if ENABLE_FEATURE_IFUPDOWN_MAPPING
724   struct mapping_defn_t *currmap = NULL;   struct mapping_defn_t *currmap = NULL;
725  #endif  #endif
726   struct interface_defn_t *currif = NULL;   struct interface_defn_t *currif = NULL;
727   struct interfaces_file_t *defn;   struct interfaces_file_t *defn;
728   FILE *f;   FILE *f;
  char *firstword;  
729   char *buf;   char *buf;
730     char *first_word;
731     char *rest_of_line;
732   enum { NONE, IFACE, MAPPING } currently_processing = NONE;   enum { NONE, IFACE, MAPPING } currently_processing = NONE;
733    
734   defn = xzalloc(sizeof(struct interfaces_file_t));   defn = xzalloc(sizeof(*defn));
735     f = xfopen_for_read(filename);
  f = xfopen(filename, "r");  
736    
737   while ((buf = xmalloc_getline(f)) != NULL) {   while ((buf = xmalloc_fgetline(f)) != NULL) {
738   char *buf_ptr = buf;  #if ENABLE_DESKTOP
739     /* Trailing "\" concatenates lines */
740   firstword = next_word(&buf_ptr);   char *p;
741   if (firstword == NULL) {   while ((p = last_char_is(buf, '\\')) != NULL) {
742     *p = '\0';
743     rest_of_line = xmalloc_fgetline(f);
744     if (!rest_of_line)
745     break;
746     p = xasprintf("%s%s", buf, rest_of_line);
747   free(buf);   free(buf);
748   continue; /* blank line */   free(rest_of_line);
749     buf = p;
750     }
751    #endif
752     rest_of_line = buf;
753     first_word = next_word(&rest_of_line);
754     if (!first_word || *first_word == '#') {
755     free(buf);
756     continue; /* blank/comment line */
757   }   }
758    
759   if (strcmp(firstword, "mapping") == 0) {   if (strcmp(first_word, "mapping") == 0) {
760  #if ENABLE_FEATURE_IFUPDOWN_MAPPING  #if ENABLE_FEATURE_IFUPDOWN_MAPPING
761   currmap = xzalloc(sizeof(struct mapping_defn_t));   currmap = xzalloc(sizeof(*currmap));
   
  while ((firstword = next_word(&buf_ptr)) != NULL) {  
  if (currmap->max_matches == currmap->n_matches) {  
  currmap->max_matches = currmap->max_matches * 2 + 1;  
  currmap->match = xrealloc(currmap->match, sizeof(currmap->match) * currmap->max_matches);  
  }  
762    
763   currmap->match[currmap->n_matches++] = xstrdup(firstword);   while ((first_word = next_word(&rest_of_line)) != NULL) {
764     currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches);
765     currmap->match[currmap->n_matches++] = xstrdup(first_word);
766   }   }
767   currmap->max_mappings = 0;   /*currmap->max_mappings = 0; - done by xzalloc */
768   currmap->n_mappings = 0;   /*currmap->n_mappings = 0;*/
769   currmap->mapping = NULL;   /*currmap->mapping = NULL;*/
770   currmap->script = NULL;   /*currmap->script = NULL;*/
771   {   {
772   struct mapping_defn_t **where = &defn->mappings;   struct mapping_defn_t **where = &defn->mappings;
773   while (*where != NULL) {   while (*where != NULL) {
774   where = &(*where)->next;   where = &(*where)->next;
775   }   }
776   *where = currmap;   *where = currmap;
777   currmap->next = NULL;   /*currmap->next = NULL;*/
778   }   }
779   debug_noise("Added mapping\n");   debug_noise("Added mapping\n");
780  #endif  #endif
781   currently_processing = MAPPING;   currently_processing = MAPPING;
782   } else if (strcmp(firstword, "iface") == 0) {   } else if (strcmp(first_word, "iface") == 0) {
783   static const struct address_family_t *const addr_fams[] = {   static const struct address_family_t *const addr_fams[] = {
784  #if ENABLE_FEATURE_IFUPDOWN_IPV4  #if ENABLE_FEATURE_IFUPDOWN_IPV4
785   &addr_inet,   &addr_inet,
# Line 697  static struct interfaces_file_t *read_in Line 789  static struct interfaces_file_t *read_in
789  #endif  #endif
790   NULL   NULL
791   };   };
   
792   char *iface_name;   char *iface_name;
793   char *address_family_name;   char *address_family_name;
794   char *method_name;   char *method_name;
795   llist_t *iface_list;   llist_t *iface_list;
796    
797   currif = xzalloc(sizeof(struct interface_defn_t));   currif = xzalloc(sizeof(*currif));
798   iface_name = next_word(&buf_ptr);   iface_name = next_word(&rest_of_line);
799   address_family_name = next_word(&buf_ptr);   address_family_name = next_word(&rest_of_line);
800   method_name = next_word(&buf_ptr);   method_name = next_word(&rest_of_line);
801    
802   if (buf_ptr == NULL) {   if (method_name == NULL)
803   bb_error_msg("too few parameters for line \"%s\"", buf);   bb_error_msg_and_die("too few parameters for line \"%s\"", buf);
  return NULL;  
  }  
804    
805   /* ship any trailing whitespace */   /* ship any trailing whitespace */
806   buf_ptr = skip_whitespace(buf_ptr);   rest_of_line = skip_whitespace(rest_of_line);
807    
808   if (buf_ptr[0] != '\0') {   if (rest_of_line[0] != '\0' /* && rest_of_line[0] != '#' */)
809   bb_error_msg("too many parameters \"%s\"", buf);   bb_error_msg_and_die("too many parameters \"%s\"", buf);
  return NULL;  
  }  
810    
811   currif->iface = xstrdup(iface_name);   currif->iface = xstrdup(iface_name);
812    
813   currif->address_family = get_address_family(addr_fams, address_family_name);   currif->address_family = get_address_family(addr_fams, address_family_name);
814   if (!currif->address_family) {   if (!currif->address_family)
815   bb_error_msg("unknown address type \"%s\"", address_family_name);   bb_error_msg_and_die("unknown address type \"%s\"", address_family_name);
  return NULL;  
  }  
816    
817   currif->method = get_method(currif->address_family, method_name);   currif->method = get_method(currif->address_family, method_name);
818   if (!currif->method) {   if (!currif->method)
819   bb_error_msg("unknown method \"%s\"", method_name);   bb_error_msg_and_die("unknown method \"%s\"", method_name);
  return NULL;  
  }  
820    
821   for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {   for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
822   struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;   struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
823   if ((strcmp(tmp->iface, currif->iface) == 0) &&   if ((strcmp(tmp->iface, currif->iface) == 0)
824   (tmp->address_family == currif->address_family)) {   && (tmp->address_family == currif->address_family)
825   bb_error_msg("duplicate interface \"%s\"", tmp->iface);   ) {
826   return NULL;   bb_error_msg_and_die("duplicate interface \"%s\"", tmp->iface);
827   }   }
828   }   }
829   llist_add_to_end(&(defn->ifaces), (char*)currif);   llist_add_to_end(&(defn->ifaces), (char*)currif);
830    
831   debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);   debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
832   currently_processing = IFACE;   currently_processing = IFACE;
833   } else if (strcmp(firstword, "auto") == 0) {   } else if (strcmp(first_word, "auto") == 0) {
834   while ((firstword = next_word(&buf_ptr)) != NULL) {   while ((first_word = next_word(&rest_of_line)) != NULL) {
835    
836   /* Check the interface isnt already listed */   /* Check the interface isnt already listed */
837   if (find_list_string(defn->autointerfaces, firstword)) {   if (find_list_string(defn->autointerfaces, first_word)) {
838   bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf);   bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf);
839   }   }
840    
841   /* Add the interface to the list */   /* Add the interface to the list */
842   llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword));   llist_add_to_end(&(defn->autointerfaces), xstrdup(first_word));
843   debug_noise("\nauto %s\n", firstword);   debug_noise("\nauto %s\n", first_word);
844   }   }
845   currently_processing = NONE;   currently_processing = NONE;
846   } else {   } else {
847   switch (currently_processing) {   switch (currently_processing) {
848   case IFACE:   case IFACE:
849   {   if (rest_of_line[0] == '\0')
850   int i;   bb_error_msg_and_die("option with empty value \"%s\"", buf);
   
  if (strlen(buf_ptr) == 0) {  
  bb_error_msg("option with empty value \"%s\"", buf);  
  return NULL;  
  }  
851    
852   if (strcmp(firstword, "up") != 0   if (strcmp(first_word, "up") != 0
853   && strcmp(firstword, "down") != 0   && strcmp(first_word, "down") != 0
854   && strcmp(firstword, "pre-up") != 0   && strcmp(first_word, "pre-up") != 0
855   && strcmp(firstword, "post-down") != 0) {   && strcmp(first_word, "post-down") != 0
856   for (i = 0; i < currif->n_options; i++) {   ) {
857   if (strcmp(currif->option[i].name, firstword) == 0) {   int i;
858   bb_error_msg("duplicate option \"%s\"", buf);   for (i = 0; i < currif->n_options; i++) {
859   return NULL;   if (strcmp(currif->option[i].name, first_word) == 0)
860   }   bb_error_msg_and_die("duplicate option \"%s\"", buf);
  }  
861   }   }
862   }   }
863   if (currif->n_options >= currif->max_options) {   if (currif->n_options >= currif->max_options) {
864   struct variable_t *opt;   currif->max_options += 10;
865     currif->option = xrealloc(currif->option,
866   currif->max_options = currif->max_options + 10;   sizeof(*currif->option) * currif->max_options);
  opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);  
  currif->option = opt;  
  }  
  currif->option[currif->n_options].name = xstrdup(firstword);  
  currif->option[currif->n_options].value = xstrdup(buf_ptr);  
  if (!currif->option[currif->n_options].name) {  
  perror(filename);  
  return NULL;  
  }  
  if (!currif->option[currif->n_options].value) {  
  perror(filename);  
  return NULL;  
867   }   }
868   debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,   debug_noise("\t%s=%s\n", first_word, rest_of_line);
869   currif->option[currif->n_options].value);   currif->option[currif->n_options].name = xstrdup(first_word);
870     currif->option[currif->n_options].value = xstrdup(rest_of_line);
871   currif->n_options++;   currif->n_options++;
872   break;   break;
873   case MAPPING:   case MAPPING:
874  #if ENABLE_FEATURE_IFUPDOWN_MAPPING  #if ENABLE_FEATURE_IFUPDOWN_MAPPING
875   if (strcmp(firstword, "script") == 0) {   if (strcmp(first_word, "script") == 0) {
876   if (currmap->script != NULL) {   if (currmap->script != NULL)
877   bb_error_msg("duplicate script in mapping \"%s\"", buf);   bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf);
878   return NULL;   currmap->script = xstrdup(next_word(&rest_of_line));
879   } else {   } else if (strcmp(first_word, "map") == 0) {
880   currmap->script = xstrdup(next_word(&buf_ptr));   if (currmap->n_mappings >= currmap->max_mappings) {
  }  
  } else if (strcmp(firstword, "map") == 0) {  
  if (currmap->max_mappings == currmap->n_mappings) {  
881   currmap->max_mappings = currmap->max_mappings * 2 + 1;   currmap->max_mappings = currmap->max_mappings * 2 + 1;
882   currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);   currmap->mapping = xrealloc(currmap->mapping,
883     sizeof(char *) * currmap->max_mappings);
884   }   }
885   currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));   currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line));
886   currmap->n_mappings++;   currmap->n_mappings++;
887   } else {   } else {
888   bb_error_msg("misplaced option \"%s\"", buf);   bb_error_msg_and_die("misplaced option \"%s\"", buf);
  return NULL;  
889   }   }
890  #endif  #endif
891   break;   break;
892   case NONE:   case NONE:
893   default:   default:
894   bb_error_msg("misplaced option \"%s\"", buf);   bb_error_msg_and_die("misplaced option \"%s\"", buf);
  return NULL;  
895   }   }
896   }   }
897   free(buf);   free(buf);
898   }   } /* while (fgets) */
899    
900   if (ferror(f) != 0) {   if (ferror(f) != 0) {
901   bb_perror_msg_and_die("%s", filename);   /* ferror does NOT set errno! */
902     bb_error_msg_and_die("%s: I/O error", filename);
903   }   }
904   fclose(f);   fclose(f);
905    
906   return defn;   return defn;
907  }  }
908    
909  static char *setlocalenv(char *format, const char *name, const char *value)  static char *setlocalenv(const char *format, const char *name, const char *value)
910  {  {
911   char *result;   char *result;
912   char *here;   char *here;
# Line 885  static void set_environ(struct interface Line 949  static void set_environ(struct interface
949    
950   for (i = 0; i < iface->n_options; i++) {   for (i = 0; i < iface->n_options; i++) {
951   if (strcmp(iface->option[i].name, "up") == 0   if (strcmp(iface->option[i].name, "up") == 0
952   || strcmp(iface->option[i].name, "down") == 0   || strcmp(iface->option[i].name, "down") == 0
953   || strcmp(iface->option[i].name, "pre-up") == 0   || strcmp(iface->option[i].name, "pre-up") == 0
954   || strcmp(iface->option[i].name, "post-down") == 0) {   || strcmp(iface->option[i].name, "post-down") == 0
955     ) {
956   continue;   continue;
957   }   }
958   *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);   *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
# Line 910  static int doit(char *str) Line 975  static int doit(char *str)
975   int status;   int status;
976    
977   fflush(NULL);   fflush(NULL);
978   child = fork();   child = vfork();
979   switch (child) {   switch (child) {
980   case -1: /* failure */   case -1: /* failure */
981   return 0;   return 0;
982   case 0: /* child */   case 0: /* child */
983   execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);   execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);
984   exit(127);   _exit(127);
985   }   }
986   waitpid(child, &status, 0);   safe_waitpid(child, &status, 0);
987   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
988   return 0;   return 0;
989   }   }
# Line 969  static int iface_down(struct interface_d Line 1034  static int iface_down(struct interface_d
1034  }  }
1035    
1036  #if ENABLE_FEATURE_IFUPDOWN_MAPPING  #if ENABLE_FEATURE_IFUPDOWN_MAPPING
1037  static int popen2(FILE **in, FILE **out, char *command, ...)  static int popen2(FILE **in, FILE **out, char *command, char *param)
1038  {  {
1039   va_list ap;   char *argv[3] = { command, param, NULL };
1040   char *argv[11] = { command };   struct fd_pair infd, outfd;
  int argc;  
  int infd[2], outfd[2];  
1041   pid_t pid;   pid_t pid;
1042    
1043   argc = 1;   xpiped_pair(infd);
1044   va_start(ap, command);   xpiped_pair(outfd);
  while ((argc < 10) && (argv[argc] = va_arg(ap, char *))) {  
  argc++;  
  }  
  argv[argc] = NULL; /* make sure */  
  va_end(ap);  
   
  if (pipe(infd) != 0) {  
  return 0;  
  }  
   
  if (pipe(outfd) != 0) {  
  close(infd[0]);  
  close(infd[1]);  
  return 0;  
  }  
1045    
1046   fflush(NULL);   fflush(NULL);
1047   switch (pid = fork()) {   pid = vfork();
1048   case -1: /* failure */  
1049   close(infd[0]);   switch (pid) {
1050   close(infd[1]);   case -1:  /* failure */
1051   close(outfd[0]);   bb_perror_msg_and_die("vfork");
1052   close(outfd[1]);   case 0:  /* child */
1053   return 0;   /* NB: close _first_, then move fds! */
1054   case 0: /* child */   close(infd.wr);
1055   dup2(infd[0], 0);   close(outfd.rd);
1056   dup2(outfd[1], 1);   xmove_fd(infd.rd, 0);
1057   close(infd[0]);   xmove_fd(outfd.wr, 1);
1058   close(infd[1]);   BB_EXECVP(command, argv);
1059   close(outfd[0]);   _exit(127);
1060   close(outfd[1]);   }
1061   execvp(command, argv);   /* parent */
1062   exit(127);   close(infd.rd);
1063   default: /* parent */   close(outfd.wr);
1064   *in = fdopen(infd[1], "w");   *in = fdopen(infd.wr, "w");
1065   *out = fdopen(outfd[0], "r");   *out = fdopen(outfd.rd, "r");
1066   close(infd[0]);   return pid;
  close(outfd[1]);  
  return pid;  
  }  
  /* unreached */  
1067  }  }
1068    
1069  static char *run_mapping(char *physical, struct mapping_defn_t * map)  static char *run_mapping(char *physical, struct mapping_defn_t *map)
1070  {  {
1071   FILE *in, *out;   FILE *in, *out;
1072   int i, status;   int i, status;
# Line 1030  static char *run_mapping(char *physical, Line 1074  static char *run_mapping(char *physical,
1074    
1075   char *logical = xstrdup(physical);   char *logical = xstrdup(physical);
1076    
1077   /* Run the mapping script. */   /* Run the mapping script. Never fails. */
1078   pid = popen2(&in, &out, map->script, physical, NULL);   pid = popen2(&in, &out, map->script, physical);
   
  /* popen2() returns 0 on failure. */  
  if (pid == 0)  
  return logical;  
1079    
1080   /* Write mappings to stdin of mapping script. */   /* Write mappings to stdin of mapping script. */
1081   for (i = 0; i < map->n_mappings; i++) {   for (i = 0; i < map->n_mappings; i++) {
1082   fprintf(in, "%s\n", map->mapping[i]);   fprintf(in, "%s\n", map->mapping[i]);
1083   }   }
1084   fclose(in);   fclose(in);
1085   waitpid(pid, &status, 0);   safe_waitpid(pid, &status, 0);
1086    
1087   if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {   if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1088   /* If the mapping script exited successfully, try to   /* If the mapping script exited successfully, try to
1089   * grab a line of output and use that as the name of the   * grab a line of output and use that as the name of the
1090   * logical interface. */   * logical interface. */
1091   char *new_logical = xmalloc(MAX_INTERFACE_LENGTH);   char *new_logical = xmalloc_fgetline(out);
1092    
1093   if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) {   if (new_logical) {
1094   /* If we are able to read a line of output from the script,   /* If we are able to read a line of output from the script,
1095   * remove any trailing whitespace and use this value   * remove any trailing whitespace and use this value
1096   * as the name of the logical interface. */   * as the name of the logical interface. */
# Line 1061  static char *run_mapping(char *physical, Line 1101  static char *run_mapping(char *physical,
1101    
1102   free(logical);   free(logical);
1103   logical = new_logical;   logical = new_logical;
  } else {  
  /* If we are UNABLE to read a line of output, discard our  
  * freshly allocated memory. */  
  free(new_logical);  
1104   }   }
1105   }   }
1106    
# Line 1076  static char *run_mapping(char *physical, Line 1112  static char *run_mapping(char *physical,
1112    
1113  static llist_t *find_iface_state(llist_t *state_list, const char *iface)  static llist_t *find_iface_state(llist_t *state_list, const char *iface)
1114  {  {
1115   unsigned short iface_len = strlen(iface);   unsigned iface_len = strlen(iface);
1116   llist_t *search = state_list;   llist_t *search = state_list;
1117    
1118   while (search) {   while (search) {
1119   if ((strncmp(search->data, iface, iface_len) == 0) &&   if ((strncmp(search->data, iface, iface_len) == 0)
1120   (search->data[iface_len] == '=')) {   && (search->data[iface_len] == '=')
1121     ) {
1122   return search;   return search;
1123   }   }
1124   search = search->link;   search = search->link;
# Line 1089  static llist_t *find_iface_state(llist_t Line 1126  static llist_t *find_iface_state(llist_t
1126   return NULL;   return NULL;
1127  }  }
1128    
1129    /* read the previous state from the state file */
1130    static llist_t *read_iface_state(void)
1131    {
1132     llist_t *state_list = NULL;
1133     FILE *state_fp = fopen_for_read(CONFIG_IFUPDOWN_IFSTATE_PATH);
1134    
1135     if (state_fp) {
1136     char *start, *end_ptr;
1137     while ((start = xmalloc_fgets(state_fp)) != NULL) {
1138     /* We should only need to check for a single character */
1139     end_ptr = start + strcspn(start, " \t\n");
1140     *end_ptr = '\0';
1141     llist_add_to(&state_list, start);
1142     }
1143     fclose(state_fp);
1144     }
1145     return state_list;
1146    }
1147    
1148    
1149    int ifupdown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1150  int ifupdown_main(int argc, char **argv)  int ifupdown_main(int argc, char **argv)
1151  {  {
1152   int (*cmds)(struct interface_defn_t *) = NULL;   int (*cmds)(struct interface_defn_t *);
1153   struct interfaces_file_t *defn;   struct interfaces_file_t *defn;
  llist_t *state_list = NULL;  
1154   llist_t *target_list = NULL;   llist_t *target_list = NULL;
1155   const char *interfaces = "/etc/network/interfaces";   const char *interfaces = "/etc/network/interfaces";
1156   int any_failures = 0;   bool any_failures = 0;
1157    
1158   cmds = iface_down;   cmds = iface_down;
1159   if (applet_name[2] == 'u') {   if (applet_name[2] == 'u') {
# Line 1104  int ifupdown_main(int argc, char **argv) Line 1161  int ifupdown_main(int argc, char **argv)
1161   cmds = iface_up;   cmds = iface_up;
1162   }   }
1163    
1164   getopt32(argc, argv, OPTION_STR, &interfaces);   getopt32(argv, OPTION_STR, &interfaces);
1165   if (argc - optind > 0) {   if (argc - optind > 0) {
1166   if (DO_ALL) bb_show_usage();   if (DO_ALL) bb_show_usage();
1167   } else {   } else {
# Line 1115  int ifupdown_main(int argc, char **argv) Line 1172  int ifupdown_main(int argc, char **argv)
1172   defn = read_interfaces(interfaces);   defn = read_interfaces(interfaces);
1173   debug_noise("\ndone reading %s\n\n", interfaces);   debug_noise("\ndone reading %s\n\n", interfaces);
1174    
  if (!defn) {  
  return EXIT_FAILURE;  
  }  
   
1175   startup_PATH = getenv("PATH");   startup_PATH = getenv("PATH");
1176   if (!startup_PATH) startup_PATH = "";   if (!startup_PATH) startup_PATH = "";
1177    
1178   /* Create a list of interfaces to work on */   /* Create a list of interfaces to work on */
1179   if (DO_ALL) {   if (DO_ALL) {
1180   if (cmds == iface_up) {   target_list = defn->autointerfaces;
  target_list = defn->autointerfaces;  
  } else {  
  /* iface_down */  
  const llist_t *list = state_list;  
  while (list) {  
  llist_add_to_end(&target_list, xstrdup(list->data));  
  list = list->link;  
  }  
  target_list = defn->autointerfaces;  
  }  
1181   } else {   } else {
1182   llist_add_to_end(&target_list, argv[optind]);   llist_add_to_end(&target_list, argv[optind]);
1183   }   }
# Line 1146  int ifupdown_main(int argc, char **argv) Line 1189  int ifupdown_main(int argc, char **argv)
1189   char *iface;   char *iface;
1190   char *liface;   char *liface;
1191   char *pch;   char *pch;
1192   int okay = 0;   bool okay = 0;
1193   int cmds_ret;   int cmds_ret;
1194    
1195   iface = xstrdup(target_list->data);   iface = xstrdup(target_list->data);
# Line 1161  int ifupdown_main(int argc, char **argv) Line 1204  int ifupdown_main(int argc, char **argv)
1204   }   }
1205    
1206   if (!FORCE) {   if (!FORCE) {
1207     llist_t *state_list = read_iface_state();
1208   const llist_t *iface_state = find_iface_state(state_list, iface);   const llist_t *iface_state = find_iface_state(state_list, iface);
1209    
1210   if (cmds == iface_up) {   if (cmds == iface_up) {
# Line 1171  int ifupdown_main(int argc, char **argv) Line 1215  int ifupdown_main(int argc, char **argv)
1215   }   }
1216   } else {   } else {
1217   /* ifdown */   /* ifdown */
1218   if (iface_state) {   if (!iface_state) {
1219   bb_error_msg("interface %s not configured", iface);   bb_error_msg("interface %s not configured", iface);
1220   continue;   continue;
1221   }   }
1222   }   }
1223     llist_free(state_list, free);
1224   }   }
1225    
1226  #if ENABLE_FEATURE_IFUPDOWN_MAPPING  #if ENABLE_FEATURE_IFUPDOWN_MAPPING
# Line 1223  int ifupdown_main(int argc, char **argv) Line 1268  int ifupdown_main(int argc, char **argv)
1268   iface_list = iface_list->link;   iface_list = iface_list->link;
1269   }   }
1270   if (VERBOSE) {   if (VERBOSE) {
1271   puts("");   bb_putchar('\n');
1272   }   }
1273    
1274   if (!okay && !FORCE) {   if (!okay && !FORCE) {
1275   bb_error_msg("ignoring unknown interface %s", liface);   bb_error_msg("ignoring unknown interface %s", liface);
1276   any_failures = 1;   any_failures = 1;
1277   } else {   } else if (!NO_ACT) {
1278     /* update the state file */
1279     FILE *state_fp;
1280     llist_t *state;
1281     llist_t *state_list = read_iface_state();
1282   llist_t *iface_state = find_iface_state(state_list, iface);   llist_t *iface_state = find_iface_state(state_list, iface);
1283    
1284   if (cmds == iface_up) {   if (cmds == iface_up) {
1285   char *newiface = xasprintf("%s=%s", iface, liface);   char * const newiface = xasprintf("%s=%s", iface, liface);
1286   if (iface_state == NULL) {   if (iface_state == NULL) {
1287   llist_add_to_end(&state_list, newiface);   llist_add_to_end(&state_list, newiface);
1288   } else {   } else {
# Line 1241  int ifupdown_main(int argc, char **argv) Line 1290  int ifupdown_main(int argc, char **argv)
1290   iface_state->data = newiface;   iface_state->data = newiface;
1291   }   }
1292   } else {   } else {
1293   /* Remove an interface from the linked list */   /* Remove an interface from state_list */
1294     llist_unlink(&state_list, iface_state);
1295   free(llist_pop(&iface_state));   free(llist_pop(&iface_state));
1296   }   }
  }  
  }  
1297    
1298   /* Actually write the new state */   /* Actually write the new state */
1299   if (!NO_ACT) {   state_fp = xfopen_for_write(CONFIG_IFUPDOWN_IFSTATE_PATH);
1300   FILE *state_fp;   state = state_list;
1301     while (state) {
1302   state_fp = xfopen("/var/run/ifstate", "w");   if (state->data) {
1303   while (state_list) {   fprintf(state_fp, "%s\n", state->data);
1304   if (state_list->data) {   }
1305   fprintf(state_fp, "%s\n", state_list->data);   state = state->link;
1306   }   }
1307   state_list = state_list->link;   fclose(state_fp);
1308     llist_free(state_list, free);
1309   }   }
  fclose(state_fp);  
1310   }   }
1311    
1312   return any_failures;   return any_failures;

Legend:
Removed from v.532  
changed lines
  Added in v.816