Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (17 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/networking/ifupdown.c

    r821 r1765  
    1111 *  Remove checks for kernel version, assume kernel version 2.2.0 or better.
    1212 *  Lines in the interfaces file cannot wrap.
    13  *  To adhere to the FHS, the default state file is /var/run/ifstate.
     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.
    1416 *
    1517 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    1618 */
    1719
    18 /* TODO: standardise execute() return codes to return 0 for success and 1 for failure */
    19 
    20 #include <sys/stat.h>
    2120#include <sys/utsname.h>
    22 #include <sys/wait.h>
    23 
    24 #include <ctype.h>
    25 #include <errno.h>
    26 #include <fcntl.h>
    2721#include <fnmatch.h>
    2822#include <getopt.h>
    29 #include <stdarg.h>
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 #include <unistd.h>
    34 
    35 #include "busybox.h"
     23
     24#include "libbb.h"
    3625
    3726#define MAX_OPT_DEPTH 10
     
    4029#define EUNBALPER   10000
    4130
    42 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     31#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    4332#define MAX_INTERFACE_LENGTH 10
    4433#endif
    4534
    46 #if 0
    47 #define debug_noise(fmt, args...) printf(fmt, ## args)
    48 #else
    49 #define debug_noise(fmt, args...)
    50 #endif
     35#define debug_noise(args...) /*fprintf(stderr, args)*/
    5136
    5237/* Forward declaration */
    5338struct interface_defn_t;
    5439
    55 typedef int (execfn)(char *command);
    56 
    57 struct method_t
    58 {
    59     char *name;
     40typedef int execfn(char *command);
     41
     42struct method_t {
     43    const char *name;
    6044    int (*up)(struct interface_defn_t *ifd, execfn *e);
    6145    int (*down)(struct interface_defn_t *ifd, execfn *e);
    6246};
    6347
    64 struct address_family_t
    65 {
    66     char *name;
     48struct address_family_t {
     49    const char *name;
    6750    int n_methods;
    68     struct method_t *method;
     51    const struct method_t *method;
    6952};
    7053
    71 struct mapping_defn_t
    72 {
     54struct mapping_defn_t {
    7355    struct mapping_defn_t *next;
    7456
     
    8466};
    8567
    86 struct variable_t
    87 {
     68struct variable_t {
    8869    char *name;
    8970    char *value;
    9071};
    9172
    92 struct interface_defn_t
    93 {
    94     struct address_family_t *address_family;
    95     struct method_t *method;
     73struct interface_defn_t {
     74    const struct address_family_t *address_family;
     75    const struct method_t *method;
    9676
    9777    char *iface;
     
    10181};
    10282
    103 struct interfaces_file_t
    104 {
     83struct interfaces_file_t {
    10584    llist_t *autointerfaces;
    10685    llist_t *ifaces;
     
    10887};
    10988
    110 static char no_act = 0;
    111 static char verbose = 0;
    112 static char **__myenviron = NULL;
     89#define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:"
     90enum {
     91    OPT_do_all = 0x1,
     92    OPT_no_act = 0x2,
     93    OPT_verbose = 0x4,
     94    OPT_force = 0x8,
     95    OPT_no_mappings = 0x10,
     96};
     97#define DO_ALL (option_mask32 & OPT_do_all)
     98#define NO_ACT (option_mask32 & OPT_no_act)
     99#define VERBOSE (option_mask32 & OPT_verbose)
     100#define FORCE (option_mask32 & OPT_force)
     101#define NO_MAPPINGS (option_mask32 & OPT_no_mappings)
     102
     103static char **my_environ;
     104
     105static const char *startup_PATH;
    113106
    114107#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
    115108
    116 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    117 
    118 static unsigned int count_bits(unsigned int a)
    119 {
    120     unsigned int result;
    121     result = (a & 0x55) + ((a >> 1) & 0x55);
    122     result = (result & 0x33) + ((result >> 2) & 0x33);
    123     return((result & 0x0F) + ((result >> 4) & 0x0F));
    124 }
    125 
    126 static int count_netmask_bits(char *dotted_quad)
    127 {
    128     unsigned int result, a, b, c, d;
    129     /* Found a netmask...  Check if it is dotted quad */
    130     if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
    131         return -1;
    132     result = count_bits(a);
    133     result += count_bits(b);
    134     result += count_bits(c);
    135     result += count_bits(d);
    136     return ((int)result);
    137 }
    138 #endif
    139 
    140 static void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t str_length)
    141 {
    142     if (*pos + str_length >= *len) {
    143         char *newbuf;
    144 
    145         newbuf = xrealloc(*buf, *len * 2 + str_length + 1);
    146         *buf = newbuf;
    147         *len = *len * 2 + str_length + 1;
    148     }
    149 
    150     while (str_length-- >= 1) {
    151         (*buf)[(*pos)++] = *str;
    152         str++;
    153     }
    154     (*buf)[*pos] = '\0';
    155 }
    156 
    157 static int strncmpz(char *l, char *r, size_t llen)
     109static void addstr(char **bufp, const char *str, size_t str_length)
     110{
     111    /* xasprintf trick will be smaller, but we are often
     112     * called with str_length == 1 - don't want to have
     113     * THAT much of malloc/freeing! */
     114    char *buf = *bufp;
     115    int len = (buf ? strlen(buf) : 0);
     116    str_length++;
     117    buf = xrealloc(buf, len + str_length);
     118    /* copies at most str_length-1 chars! */
     119    safe_strncpy(buf + len, str, str_length);
     120    *bufp = buf;
     121}
     122
     123static int strncmpz(const char *l, const char *r, size_t llen)
    158124{
    159125    int i = strncmp(l, r, llen);
    160126
    161     if (i == 0) {
    162         return(-r[llen]);
    163     } else {
    164         return(i);
    165     }
    166 }
    167 
    168 static char *get_var(char *id, size_t idlen, struct interface_defn_t *ifd)
     127    if (i == 0)
     128        return -r[llen];
     129    return i;
     130}
     131
     132static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd)
    169133{
    170134    int i;
     
    173137        char *result;
    174138        static char label_buf[20];
    175         strncpy(label_buf, ifd->iface, 19);
    176         label_buf[19]=0;
     139        safe_strncpy(label_buf, ifd->iface, sizeof(label_buf));
    177140        result = strchr(label_buf, ':');
    178141        if (result) {
    179             *result=0;
    180         }
    181         return( label_buf);
    182     } else if (strncmpz(id, "label", idlen) == 0) {
    183         return (ifd->iface);
    184     } else {
    185         for (i = 0; i < ifd->n_options; i++) {
    186             if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
    187                 return (ifd->option[i].value);
    188             }
    189         }
    190     }
    191 
    192     return(NULL);
    193 }
    194 
    195 static char *parse(char *command, struct interface_defn_t *ifd)
    196 {
    197 
    198     char *result = NULL;
    199     size_t pos = 0, len = 0;
     142            *result = '\0';
     143        }
     144        return label_buf;
     145    }
     146    if (strncmpz(id, "label", idlen) == 0) {
     147        return ifd->iface;
     148    }
     149    for (i = 0; i < ifd->n_options; i++) {
     150        if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
     151            return ifd->option[i].value;
     152        }
     153    }
     154    return NULL;
     155}
     156
     157#if ENABLE_FEATURE_IFUPDOWN_IP
     158static int count_netmask_bits(const char *dotted_quad)
     159{
     160//  int result;
     161//  unsigned a, b, c, d;
     162//  /* Found a netmask...  Check if it is dotted quad */
     163//  if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
     164//      return -1;
     165//  if ((a|b|c|d) >> 8)
     166//      return -1; /* one of numbers is >= 256 */
     167//  d |= (a << 24) | (b << 16) | (c << 8); /* IP */
     168//  d = ~d; /* 11110000 -> 00001111 */
     169
     170    /* Shorter version */
     171    int result;
     172    struct in_addr ip;
     173    unsigned d;
     174
     175    if (inet_aton(dotted_quad, &ip) == 0)
     176        return -1; /* malformed dotted IP */
     177    d = ntohl(ip.s_addr); /* IP in host order */
     178    d = ~d; /* 11110000 -> 00001111 */
     179    if (d & (d+1)) /* check that it is in 00001111 form */
     180        return -1; /* no it is not */
     181    result = 32;
     182    while (d) {
     183        d >>= 1;
     184        result--;
     185    }
     186    return result;
     187}
     188#endif
     189
     190static char *parse(const char *command, struct interface_defn_t *ifd)
     191{
    200192    size_t old_pos[MAX_OPT_DEPTH] = { 0 };
    201193    int okay[MAX_OPT_DEPTH] = { 1 };
    202194    int opt_depth = 1;
     195    char *result = NULL;
    203196
    204197    while (*command) {
    205198        switch (*command) {
    206 
    207             default:
    208                 addstr(&result, &len, &pos, command, 1);
     199        default:
     200            addstr(&result, command, 1);
     201            command++;
     202            break;
     203        case '\\':
     204            if (command[1]) {
     205                addstr(&result, command + 1, 1);
     206                command += 2;
     207            } else {
     208                addstr(&result, command, 1);
    209209                command++;
    210                 break;
    211             case '\\':
    212                 if (command[1]) {
    213                     addstr(&result, &len, &pos, command + 1, 1);
    214                     command += 2;
     210            }
     211            break;
     212        case '[':
     213            if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
     214                old_pos[opt_depth] = result ? strlen(result) : 0;
     215                okay[opt_depth] = 1;
     216                opt_depth++;
     217                command += 2;
     218            } else {
     219                addstr(&result, "[", 1);
     220                command++;
     221            }
     222            break;
     223        case ']':
     224            if (command[1] == ']' && opt_depth > 1) {
     225                opt_depth--;
     226                if (!okay[opt_depth]) {
     227                    result[old_pos[opt_depth]] = '\0';
     228                }
     229                command += 2;
     230            } else {
     231                addstr(&result, "]", 1);
     232                command++;
     233            }
     234            break;
     235        case '%':
     236            {
     237                char *nextpercent;
     238                char *varvalue;
     239
     240                command++;
     241                nextpercent = strchr(command, '%');
     242                if (!nextpercent) {
     243                    errno = EUNBALPER;
     244                    free(result);
     245                    return NULL;
     246                }
     247
     248                varvalue = get_var(command, nextpercent - command, ifd);
     249
     250                if (varvalue) {
     251                    addstr(&result, varvalue, strlen(varvalue));
    215252                } else {
    216                     addstr(&result, &len, &pos, command, 1);
    217                     command++;
    218                 }
    219                 break;
    220             case '[':
    221                 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
    222                     old_pos[opt_depth] = pos;
    223                     okay[opt_depth] = 1;
    224                     opt_depth++;
    225                     command += 2;
    226                 } else {
    227                     addstr(&result, &len, &pos, "[", 1);
    228                     command++;
    229                 }
    230                 break;
    231             case ']':
    232                 if (command[1] == ']' && opt_depth > 1) {
    233                     opt_depth--;
    234                     if (!okay[opt_depth]) {
    235                         pos = old_pos[opt_depth];
    236                         result[pos] = '\0';
    237                     }
    238                     command += 2;
    239                 } else {
    240                     addstr(&result, &len, &pos, "]", 1);
    241                     command++;
    242                 }
    243                 break;
    244             case '%':
    245                 {
    246                     char *nextpercent;
    247                     char *varvalue;
    248 
    249                     command++;
    250                     nextpercent = strchr(command, '%');
    251                     if (!nextpercent) {
    252                         errno = EUNBALPER;
    253                         free(result);
    254                         return (NULL);
    255                     }
    256 
    257                     varvalue = get_var(command, nextpercent - command, ifd);
    258 
    259                     if (varvalue) {
    260                         addstr(&result, &len, &pos, varvalue, strlen(varvalue));
    261                     } else {
    262 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    263                         /* Sigh...  Add a special case for 'ip' to convert from
    264                          * dotted quad to bit count style netmasks.  */
    265                         if (strncmp(command, "bnmask", 6)==0) {
    266                             int res;
    267                             varvalue = get_var("netmask", 7, ifd);
    268                             if (varvalue && (res=count_netmask_bits(varvalue)) > 0) {
    269                                 char argument[255];
    270                                 sprintf(argument, "%d", res);
    271                                 addstr(&result, &len, &pos, argument, strlen(argument));
     253#if ENABLE_FEATURE_IFUPDOWN_IP
     254                    /* Sigh...  Add a special case for 'ip' to convert from
     255                     * dotted quad to bit count style netmasks.  */
     256                    if (strncmp(command, "bnmask", 6) == 0) {
     257                        unsigned res;
     258                        varvalue = get_var("netmask", 7, ifd);
     259                        if (varvalue) {
     260                            res = count_netmask_bits(varvalue);
     261                            if (res > 0) {
     262                                const char *argument = utoa(res);
     263                                addstr(&result, argument, strlen(argument));
    272264                                command = nextpercent + 1;
    273265                                break;
    274266                            }
    275267                        }
    276 #endif
    277                         okay[opt_depth - 1] = 0;
    278268                    }
    279 
    280                     command = nextpercent + 1;
    281                 }
    282                 break;
     269#endif
     270                    okay[opt_depth - 1] = 0;
     271                }
     272
     273                command = nextpercent + 1;
     274            }
     275            break;
    283276        }
    284277    }
     
    287280        errno = EUNBALBRACK;
    288281        free(result);
    289         return(NULL);
     282        return NULL;
    290283    }
    291284
     
    293286        errno = EUNDEFVAR;
    294287        free(result);
    295         return(NULL);
    296     }
    297 
    298     return(result);
    299 }
    300 
    301 static int execute(char *command, struct interface_defn_t *ifd, execfn *exec)
     288        return NULL;
     289    }
     290
     291    return result;
     292}
     293
     294/* execute() returns 1 for success and 0 for failure */
     295static int execute(const char *command, struct interface_defn_t *ifd, execfn *exec)
    302296{
    303297    char *out;
     
    306300    out = parse(command, ifd);
    307301    if (!out) {
    308         return(0);
    309     }
    310     ret = (*exec) (out);
     302        /* parse error? */
     303        return 0;
     304    }
     305    /* out == "": parsed ok but not all needed variables known, skip */
     306    ret = out[0] ? (*exec)(out) : 1;
    311307
    312308    free(out);
    313309    if (ret != 1) {
    314         return(0);
    315     }
    316     return(1);
    317 }
    318 #endif
    319 
    320 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
     310        return 0;
     311    }
     312    return 1;
     313}
     314#endif
     315
     316#if ENABLE_FEATURE_IFUPDOWN_IPV6
    321317static int loopback_up6(struct interface_defn_t *ifd, execfn *exec)
    322318{
    323 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     319#if ENABLE_FEATURE_IFUPDOWN_IP
    324320    int result;
    325     result =execute("ip addr add ::1 dev %iface%", ifd, exec);
     321    result = execute("ip addr add ::1 dev %iface%", ifd, exec);
    326322    result += execute("ip link set %iface% up", ifd, exec);
    327323    return ((result == 2) ? 2 : 0);
    328324#else
    329     return( execute("ifconfig %iface% add ::1", ifd, exec));
     325    return execute("ifconfig %iface% add ::1", ifd, exec);
    330326#endif
    331327}
     
    333329static int loopback_down6(struct interface_defn_t *ifd, execfn *exec)
    334330{
    335 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    336     return(execute("ip link set %iface% down", ifd, exec));
     331#if ENABLE_FEATURE_IFUPDOWN_IP
     332    return execute("ip link set %iface% down", ifd, exec);
    337333#else
    338     return(execute("ifconfig %iface% del ::1", ifd, exec));
     334    return execute("ifconfig %iface% del ::1", ifd, exec);
    339335#endif
    340336}
     
    343339{
    344340    int result;
    345 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    346     result = execute("ip addr add %address%/%netmask% dev %iface% [[label %label%]]", ifd, exec);
    347     result += execute("ip link set [[mtu %mtu%]] [[address %hwaddress%]] %iface% up", ifd, exec);
    348     result += execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec);
     341#if ENABLE_FEATURE_IFUPDOWN_IP
     342    result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
     343    result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
     344    /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
     345    result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
    349346#else
    350     result = execute("ifconfig %iface% [[media %media%]] [[hw %hwaddress%]] [[mtu %mtu%]] up", ifd, exec);
     347    result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
    351348    result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
    352     result += execute("[[ route -A inet6 add ::/0 gw %gateway% ]]", ifd, exec);
     349    result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);
    353350#endif
    354351    return ((result == 3) ? 3 : 0);
     
    357354static int static_down6(struct interface_defn_t *ifd, execfn *exec)
    358355{
    359 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    360     return(execute("ip link set %iface% down", ifd, exec));
     356#if ENABLE_FEATURE_IFUPDOWN_IP
     357    return execute("ip link set %iface% down", ifd, exec);
    361358#else
    362     return(execute("ifconfig %iface% down", ifd, exec));
    363 #endif
    364 }
    365 
    366 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     359    return execute("ifconfig %iface% down", ifd, exec);
     360#endif
     361}
     362
     363#if ENABLE_FEATURE_IFUPDOWN_IP
    367364static int v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
    368365{
    369366    int result;
    370367    result = execute("ip tunnel add %iface% mode sit remote "
    371                 "%endpoint% [[local %local%]] [[ttl %ttl%]]", ifd, exec);
     368            "%endpoint%[[ local %local%]][[ ttl %ttl%]]", ifd, exec);
    372369    result += execute("ip link set %iface% up", ifd, exec);
    373370    result += execute("ip addr add %address%/%netmask% dev %iface%", ifd, exec);
    374     result += execute("[[ ip route add ::/0 via %gateway% ]]", ifd, exec);
     371    result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
    375372    return ((result == 4) ? 4 : 0);
    376373}
     
    378375static int v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
    379376{
    380     return( execute("ip tunnel del %iface%", ifd, exec));
    381 }
    382 #endif
    383 
    384 static struct method_t methods6[] = {
    385 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     377    return execute("ip tunnel del %iface%", ifd, exec);
     378}
     379#endif
     380
     381static const struct method_t methods6[] = {
     382#if ENABLE_FEATURE_IFUPDOWN_IP
    386383    { "v4tunnel", v4tunnel_up, v4tunnel_down, },
    387384#endif
     
    390387};
    391388
    392 static struct address_family_t addr_inet6 = {
     389static const struct address_family_t addr_inet6 = {
    393390    "inet6",
    394     sizeof(methods6) / sizeof(struct method_t),
     391    ARRAY_SIZE(methods6),
    395392    methods6
    396393};
    397 #endif /* CONFIG_FEATURE_IFUPDOWN_IPV6 */
    398 
    399 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
     394#endif /* FEATURE_IFUPDOWN_IPV6 */
     395
     396#if ENABLE_FEATURE_IFUPDOWN_IPV4
    400397static int loopback_up(struct interface_defn_t *ifd, execfn *exec)
    401398{
    402 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     399#if ENABLE_FEATURE_IFUPDOWN_IP
    403400    int result;
    404401    result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
     
    406403    return ((result == 2) ? 2 : 0);
    407404#else
    408     return( execute("ifconfig %iface% 127.0.0.1 up", ifd, exec));
     405    return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
    409406#endif
    410407}
     
    412409static int loopback_down(struct interface_defn_t *ifd, execfn *exec)
    413410{
    414 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     411#if ENABLE_FEATURE_IFUPDOWN_IP
    415412    int result;
    416413    result = execute("ip addr flush dev %iface%", ifd, exec);
     
    418415    return ((result == 2) ? 2 : 0);
    419416#else
    420     return( execute("ifconfig %iface% 127.0.0.1 down", ifd, exec));
     417    return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
    421418#endif
    422419}
     
    425422{
    426423    int result;
    427 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
    428     result = execute("ip addr add %address%/%bnmask% [[broadcast %broadcast%]] "
    429             "dev %iface% [[peer %pointopoint%]] [[label %label%]]", ifd, exec);
    430     result += execute("ip link set [[mtu %mtu%]] [[address %hwaddress%]] %iface% up", ifd, exec);
    431     result += execute("[[ ip route add default via %gateway% dev %iface% ]]", ifd, exec);
     424#if ENABLE_FEATURE_IFUPDOWN_IP
     425    result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
     426            "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
     427    result += execute("ip link set[[ mtu %mtu%]][[ address %hwaddress%]] %iface% up", ifd, exec);
     428    result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
    432429    return ((result == 3) ? 3 : 0);
    433430#else
    434     result = execute("ifconfig %iface% %address% netmask %netmask% "
    435                 "[[broadcast %broadcast%]] [[pointopoint %pointopoint%]] "
    436                 "[[media %media%]] [[mtu %mtu%]] [[hw %hwaddress%]] up",
     431    /* ifconfig said to set iface up before it processes hw %hwaddress%,
     432     * which then of course fails. Thus we run two separate ifconfig */
     433    result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
    437434                ifd, exec);
    438     result += execute("[[ route add default gw %gateway% %iface% ]]", ifd, exec);
    439     return ((result == 2) ? 2 : 0);
     435    result += execute("ifconfig %iface% %address% netmask %netmask%"
     436                "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
     437                ifd, exec);
     438    result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
     439    return ((result == 3) ? 3 : 0);
    440440#endif
    441441}
     
    444444{
    445445    int result;
    446 #ifdef CONFIG_FEATURE_IFUPDOWN_IP
     446#if ENABLE_FEATURE_IFUPDOWN_IP
    447447    result = execute("ip addr flush dev %iface%", ifd, exec);
    448448    result += execute("ip link set %iface% down", ifd, exec);
    449449#else
    450     result = execute("[[ route del default gw %gateway% %iface% ]]", ifd, exec);
     450    result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec);
    451451    result += execute("ifconfig %iface% down", ifd, exec);
    452452#endif
     
    454454}
    455455
    456 static int execable(char *program)
    457 {
    458     struct stat buf;
    459     if (0 == stat(program, &buf)) {
    460         if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode)) {
    461             return(1);
    462         }
    463     }
    464     return(0);
    465 }
     456#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     457struct dhcp_client_t
     458{
     459    const char *name;
     460    const char *startcmd;
     461    const char *stopcmd;
     462};
     463
     464static const struct dhcp_client_t ext_dhcp_clients[] = {
     465    { "dhcpcd",
     466        "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%",
     467        "dhcpcd -k %iface%",
     468    },
     469    { "dhclient",
     470        "dhclient -pf /var/run/dhclient.%iface%.pid %iface%",
     471        "kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null",
     472    },
     473    { "pump",
     474        "pump -i %iface%[[ -h %hostname%]][[ -l %leasehours%]]",
     475        "pump -i %iface% -k",
     476    },
     477    { "udhcpc",
     478        "udhcpc -R -n -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
     479        "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
     480    },
     481};
     482#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
    466483
    467484static int dhcp_up(struct interface_defn_t *ifd, execfn *exec)
    468485{
    469     if (execable("/sbin/udhcpc")) {
    470         return( execute("udhcpc -n -p /var/run/udhcpc.%iface%.pid -i "
    471                     "%iface% [[-H %hostname%]] [[-c %clientid%]]", ifd, exec));
    472     } else if (execable("/sbin/pump")) {
    473         return( execute("pump -i %iface% [[-h %hostname%]] [[-l %leasehours%]]", ifd, exec));
    474     } else if (execable("/sbin/dhclient")) {
    475         return( execute("dhclient -pf /var/run/dhclient.%iface%.pid %iface%", ifd, exec));
    476     } else if (execable("/sbin/dhcpcd")) {
    477         return( execute("dhcpcd [[-h %hostname%]] [[-i %vendor%]] [[-I %clientid%]] "
    478                     "[[-l %leasetime%]] %iface%", ifd, exec));
    479     }
    480     return(0);
     486#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     487    int i;
     488#if ENABLE_FEATURE_IFUPDOWN_IP
     489    /* ip doesn't up iface when it configures it (unlike ifconfig) */
     490    if (!execute("ip link set %iface% up", ifd, exec))
     491        return 0;
     492#endif
     493    for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
     494        if (exists_execable(ext_dhcp_clients[i].name))
     495            return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
     496    }
     497    bb_error_msg("no dhcp clients found");
     498    return 0;
     499#elif ENABLE_APP_UDHCPC
     500#if ENABLE_FEATURE_IFUPDOWN_IP
     501    /* ip doesn't up iface when it configures it (unlike ifconfig) */
     502    if (!execute("ip link set %iface% up", ifd, exec))
     503        return 0;
     504#endif
     505    return execute("udhcpc -R -n -p /var/run/udhcpc.%iface%.pid "
     506            "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]]",
     507            ifd, exec);
     508#else
     509    return 0; /* no dhcp support */
     510#endif
    481511}
    482512
    483513static int dhcp_down(struct interface_defn_t *ifd, execfn *exec)
    484514{
    485     int result = 0;
    486     if (execable("/sbin/udhcpc")) {
    487         /* SIGUSR2 forces udhcpc to release the current lease and go inactive,
    488          * and SIGTERM causes udhcpc to exit.  Signals are queued and processed
    489          * sequentially so we don't need to sleep */
    490         result = execute("kill -USR2 `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
    491         result += execute("kill -TERM `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
    492     } else if (execable("/sbin/pump")) {
    493         result = execute("pump -i %iface% -k", ifd, exec);
    494     } else if (execable("/sbin/dhclient")) {
    495         result = execute("kill -9 `cat /var/run/dhclient.%iface%.pid` 2>/dev/null", ifd, exec);
    496     } else if (execable("/sbin/dhcpcd")) {
    497         result = execute("dhcpcd -k %iface%", ifd, exec);
    498     }
    499     return (result || static_down(ifd, exec));
     515#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
     516    int i;
     517    for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
     518        if (exists_execable(ext_dhcp_clients[i].name))
     519            return execute(ext_dhcp_clients[i].stopcmd, ifd, exec);
     520    }
     521    bb_error_msg("no dhcp clients found, using static interface shutdown");
     522    return static_down(ifd, exec);
     523#elif ENABLE_APP_UDHCPC
     524    return execute("kill "
     525                   "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec);
     526#else
     527    return 0; /* no dhcp support */
     528#endif
     529}
     530
     531static int manual_up_down(struct interface_defn_t *ifd, execfn *exec)
     532{
     533    return 1;
    500534}
    501535
    502536static int bootp_up(struct interface_defn_t *ifd, execfn *exec)
    503537{
    504     return( execute("bootpc [[--bootfile %bootfile%]] --dev %iface% "
    505                 "[[--server %server%]] [[--hwaddr %hwaddr%]] "
    506                 "--returniffail --serverbcast", ifd, exec));
     538    return execute("bootpc[[ --bootfile %bootfile%]] --dev %iface%"
     539            "[[ --server %server%]][[ --hwaddr %hwaddr%]]"
     540            " --returniffail --serverbcast", ifd, exec);
    507541}
    508542
    509543static int ppp_up(struct interface_defn_t *ifd, execfn *exec)
    510544{
    511     return( execute("pon [[%provider%]]", ifd, exec));
     545    return execute("pon[[ %provider%]]", ifd, exec);
    512546}
    513547
    514548static int ppp_down(struct interface_defn_t *ifd, execfn *exec)
    515549{
    516     return( execute("poff [[%provider%]]", ifd, exec));
     550    return execute("poff[[ %provider%]]", ifd, exec);
    517551}
    518552
    519553static int wvdial_up(struct interface_defn_t *ifd, execfn *exec)
    520554{
    521     return( execute("/sbin/start-stop-daemon --start -x /usr/bin/wvdial "
    522                 "-p /var/run/wvdial.%iface% -b -m -- [[ %provider% ]]", ifd, exec));
     555    return execute("start-stop-daemon --start -x wvdial "
     556        "-p /var/run/wvdial.%iface% -b -m --[[ %provider%]]", ifd, exec);
    523557}
    524558
    525559static int wvdial_down(struct interface_defn_t *ifd, execfn *exec)
    526560{
    527     return( execute("/sbin/start-stop-daemon --stop -x /usr/bin/wvdial "
    528                 "-p /var/run/wvdial.%iface% -s 2", ifd, exec));
    529 }
    530 
    531 static struct method_t methods[] =
    532 {
     561    return execute("start-stop-daemon --stop -x wvdial "
     562            "-p /var/run/wvdial.%iface% -s 2", ifd, exec);
     563}
     564
     565static const struct method_t methods[] = {
     566    { "manual", manual_up_down, manual_up_down, },
    533567    { "wvdial", wvdial_up, wvdial_down, },
    534568    { "ppp", ppp_up, ppp_down, },
     
    539573};
    540574
    541 static struct address_family_t addr_inet =
    542 {
     575static const struct address_family_t addr_inet = {
    543576    "inet",
    544     sizeof(methods) / sizeof(struct method_t),
     577    ARRAY_SIZE(methods),
    545578    methods
    546579};
    547580
    548 #endif  /* ifdef CONFIG_FEATURE_IFUPDOWN_IPV4 */
     581#endif  /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */
    549582
    550583static char *next_word(char **buf)
     
    553586    char *word;
    554587
    555     if ((buf == NULL) || (*buf == NULL) || (**buf == '\0')) {
     588    if (!buf || !*buf || !**buf) {
    556589        return NULL;
    557590    }
    558591
    559592    /* Skip over leading whitespace */
    560     word = *buf;
    561     while (isspace(*word)) {
    562         ++word;
    563     }
     593    word = skip_whitespace(*buf);
    564594
    565595    /* Skip over comments */
    566596    if (*word == '#') {
    567         return(NULL);
     597        return NULL;
    568598    }
    569599
     
    571601    length = strcspn(word, " \t\n");
    572602    if (length == 0) {
    573         return(NULL);
     603        return NULL;
    574604    }
    575605    *buf = word + length;
     
    583613}
    584614
    585 static struct address_family_t *get_address_family(struct address_family_t *af[], char *name)
     615static const struct address_family_t *get_address_family(const struct address_family_t *const af[], char *name)
    586616{
    587617    int i;
     618
     619    if (!name)
     620        return NULL;
    588621
    589622    for (i = 0; af[i]; i++) {
     
    595628}
    596629
    597 static struct method_t *get_method(struct address_family_t *af, char *name)
     630static const struct method_t *get_method(const struct address_family_t *af, char *name)
    598631{
    599632    int i;
     633
     634    if (!name)
     635        return NULL;
    600636
    601637    for (i = 0; i < af->n_methods; i++) {
     
    604640        }
    605641    }
    606     return(NULL);
     642    return NULL;
    607643}
    608644
    609645static const llist_t *find_list_string(const llist_t *list, const char *string)
    610646{
     647    if (string == NULL)
     648        return NULL;
     649
    611650    while (list) {
    612651        if (strcmp(list->data, string) == 0) {
    613             return(list);
     652            return list;
    614653        }
    615654        list = list->link;
    616655    }
    617     return(NULL);
     656    return NULL;
    618657}
    619658
    620659static struct interfaces_file_t *read_interfaces(const char *filename)
    621660{
    622 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     661#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    623662    struct mapping_defn_t *currmap = NULL;
    624663#endif
     
    633672    defn = xzalloc(sizeof(struct interfaces_file_t));
    634673
    635     f = bb_xfopen(filename, "r");
    636 
    637     while ((buf = bb_get_chomped_line_from_file(f)) != NULL) {
     674    f = xfopen(filename, "r");
     675
     676    while ((buf = xmalloc_getline(f)) != NULL) {
    638677        char *buf_ptr = buf;
    639678
     
    645684
    646685        if (strcmp(firstword, "mapping") == 0) {
    647 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     686#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    648687            currmap = xzalloc(sizeof(struct mapping_defn_t));
    649688
     
    654693                }
    655694
    656                 currmap->match[currmap->n_matches++] = bb_xstrdup(firstword);
     695                currmap->match[currmap->n_matches++] = xstrdup(firstword);
    657696            }
    658697            currmap->max_mappings = 0;
     
    672711            currently_processing = MAPPING;
    673712        } else if (strcmp(firstword, "iface") == 0) {
    674             {
    675                 char *iface_name;
    676                 char *address_family_name;
    677                 char *method_name;
    678                 struct address_family_t *addr_fams[] = {
    679 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV4
    680                     &addr_inet,
    681 #endif
    682 #ifdef CONFIG_FEATURE_IFUPDOWN_IPV6
    683                     &addr_inet6,
    684 #endif
    685                     NULL
    686                 };
    687 
    688                 currif = xzalloc(sizeof(struct interface_defn_t));
    689                 iface_name = next_word(&buf_ptr);
    690                 address_family_name = next_word(&buf_ptr);
    691                 method_name = next_word(&buf_ptr);
    692 
    693                 if (buf_ptr == NULL) {
    694                     bb_error_msg("too few parameters for line \"%s\"", buf);
     713            static const struct address_family_t *const addr_fams[] = {
     714#if ENABLE_FEATURE_IFUPDOWN_IPV4
     715                &addr_inet,
     716#endif
     717#if ENABLE_FEATURE_IFUPDOWN_IPV6
     718                &addr_inet6,
     719#endif
     720                NULL
     721            };
     722
     723            char *iface_name;
     724            char *address_family_name;
     725            char *method_name;
     726            llist_t *iface_list;
     727
     728            currif = xzalloc(sizeof(struct interface_defn_t));
     729            iface_name = next_word(&buf_ptr);
     730            address_family_name = next_word(&buf_ptr);
     731            method_name = next_word(&buf_ptr);
     732
     733            if (buf_ptr == NULL) {
     734                bb_error_msg("too few parameters for line \"%s\"", buf);
     735                return NULL;
     736            }
     737
     738            /* ship any trailing whitespace */
     739            buf_ptr = skip_whitespace(buf_ptr);
     740
     741            if (buf_ptr[0] != '\0') {
     742                bb_error_msg("too many parameters \"%s\"", buf);
     743                return NULL;
     744            }
     745
     746            currif->iface = xstrdup(iface_name);
     747
     748            currif->address_family = get_address_family(addr_fams, address_family_name);
     749            if (!currif->address_family) {
     750                bb_error_msg("unknown address type \"%s\"", address_family_name);
     751                return NULL;
     752            }
     753
     754            currif->method = get_method(currif->address_family, method_name);
     755            if (!currif->method) {
     756                bb_error_msg("unknown method \"%s\"", method_name);
     757                return NULL;
     758            }
     759
     760            for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
     761                struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
     762                if ((strcmp(tmp->iface, currif->iface) == 0) &&
     763                    (tmp->address_family == currif->address_family)) {
     764                    bb_error_msg("duplicate interface \"%s\"", tmp->iface);
    695765                    return NULL;
    696766                }
    697 
    698                 /* ship any trailing whitespace */
    699                 while (isspace(*buf_ptr)) {
    700                     ++buf_ptr;
    701                 }
    702 
    703                 if (buf_ptr[0] != '\0') {
    704                     bb_error_msg("too many parameters \"%s\"", buf);
    705                     return NULL;
    706                 }
    707 
    708                 currif->iface = bb_xstrdup(iface_name);
    709 
    710                 currif->address_family = get_address_family(addr_fams, address_family_name);
    711                 if (!currif->address_family) {
    712                     bb_error_msg("unknown address type \"%s\"", address_family_name);
    713                     return NULL;
    714                 }
    715 
    716                 currif->method = get_method(currif->address_family, method_name);
    717                 if (!currif->method) {
    718                     bb_error_msg("unknown method \"%s\"", method_name);
    719                     return NULL;
    720                 }
    721 
    722 
    723                 {
    724                     llist_t *iface_list;
    725                     for (iface_list = defn->ifaces; iface_list; iface_list = iface_list->link) {
    726                         struct interface_defn_t *tmp = (struct interface_defn_t *) iface_list->data;
    727                         if ((strcmp(tmp->iface, currif->iface) == 0) &&
    728                             (tmp->address_family == currif->address_family)) {
    729                             bb_error_msg("duplicate interface \"%s\"", tmp->iface);
    730                             return NULL;
    731                         }
    732                     }
    733 
    734                     llist_add_to_end(&(defn->ifaces), (char*)currif);
    735                 }
    736                 debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
    737             }
     767            }
     768            llist_add_to_end(&(defn->ifaces), (char*)currif);
     769
     770            debug_noise("iface %s %s %s\n", currif->iface, address_family_name, method_name);
    738771            currently_processing = IFACE;
    739772        } else if (strcmp(firstword, "auto") == 0) {
     
    746779
    747780                /* Add the interface to the list */
    748                 llist_add_to_end(&(defn->autointerfaces), bb_xstrdup(firstword));
     781                llist_add_to_end(&(defn->autointerfaces), xstrdup(firstword));
    749782                debug_noise("\nauto %s\n", firstword);
    750783            }
     
    752785        } else {
    753786            switch (currently_processing) {
    754                 case IFACE:
    755                     {
    756                         int i;
    757 
    758                         if (strlen(buf_ptr) == 0) {
    759                             bb_error_msg("option with empty value \"%s\"", buf);
    760                             return NULL;
    761                         }
    762 
    763                         if (strcmp(firstword, "up") != 0
    764                                 && strcmp(firstword, "down") != 0
    765                                 && strcmp(firstword, "pre-up") != 0
    766                                 && strcmp(firstword, "post-down") != 0) {
    767                             for (i = 0; i < currif->n_options; i++) {
    768                                 if (strcmp(currif->option[i].name, firstword) == 0) {
    769                                     bb_error_msg("duplicate option \"%s\"", buf);
    770                                     return NULL;
    771                                 }
     787            case IFACE:
     788                {
     789                    int i;
     790
     791                    if (strlen(buf_ptr) == 0) {
     792                        bb_error_msg("option with empty value \"%s\"", buf);
     793                        return NULL;
     794                    }
     795
     796                    if (strcmp(firstword, "up") != 0
     797                            && strcmp(firstword, "down") != 0
     798                            && strcmp(firstword, "pre-up") != 0
     799                            && strcmp(firstword, "post-down") != 0) {
     800                        for (i = 0; i < currif->n_options; i++) {
     801                            if (strcmp(currif->option[i].name, firstword) == 0) {
     802                                bb_error_msg("duplicate option \"%s\"", buf);
     803                                return NULL;
    772804                            }
    773805                        }
    774806                    }
    775                     if (currif->n_options >= currif->max_options) {
    776                         struct variable_t *opt;
    777 
    778                         currif->max_options = currif->max_options + 10;
    779                         opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
    780                         currif->option = opt;
     807                }
     808                if (currif->n_options >= currif->max_options) {
     809                    struct variable_t *opt;
     810
     811                    currif->max_options = currif->max_options + 10;
     812                    opt = xrealloc(currif->option, sizeof(*opt) * currif->max_options);
     813                    currif->option = opt;
     814                }
     815                currif->option[currif->n_options].name = xstrdup(firstword);
     816                currif->option[currif->n_options].value = xstrdup(buf_ptr);
     817                if (!currif->option[currif->n_options].name) {
     818                    perror(filename);
     819                    return NULL;
     820                }
     821                if (!currif->option[currif->n_options].value) {
     822                    perror(filename);
     823                    return NULL;
     824                }
     825                debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,
     826                        currif->option[currif->n_options].value);
     827                currif->n_options++;
     828                break;
     829            case MAPPING:
     830#if ENABLE_FEATURE_IFUPDOWN_MAPPING
     831                if (strcmp(firstword, "script") == 0) {
     832                    if (currmap->script != NULL) {
     833                        bb_error_msg("duplicate script in mapping \"%s\"", buf);
     834                        return NULL;
     835                    } else {
     836                        currmap->script = xstrdup(next_word(&buf_ptr));
    781837                    }
    782                     currif->option[currif->n_options].name = bb_xstrdup(firstword);
    783                     currif->option[currif->n_options].value = bb_xstrdup(buf_ptr);
    784                     if (!currif->option[currif->n_options].name) {
    785                         perror(filename);
    786                         return NULL;
     838                } else if (strcmp(firstword, "map") == 0) {
     839                    if (currmap->max_mappings == currmap->n_mappings) {
     840                        currmap->max_mappings = currmap->max_mappings * 2 + 1;
     841                        currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
    787842                    }
    788                     if (!currif->option[currif->n_options].value) {
    789                         perror(filename);
    790                         return NULL;
    791                     }
    792                     debug_noise("\t%s=%s\n", currif->option[currif->n_options].name,
    793                             currif->option[currif->n_options].value);
    794                     currif->n_options++;
    795                     break;
    796                 case MAPPING:
    797 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    798                     if (strcmp(firstword, "script") == 0) {
    799                         if (currmap->script != NULL) {
    800                             bb_error_msg("duplicate script in mapping \"%s\"", buf);
    801                             return NULL;
    802                         } else {
    803                             currmap->script = bb_xstrdup(next_word(&buf_ptr));
    804                         }
    805                     } else if (strcmp(firstword, "map") == 0) {
    806                         if (currmap->max_mappings == currmap->n_mappings) {
    807                             currmap->max_mappings = currmap->max_mappings * 2 + 1;
    808                             currmap->mapping = xrealloc(currmap->mapping, sizeof(char *) * currmap->max_mappings);
    809                         }
    810                         currmap->mapping[currmap->n_mappings] = bb_xstrdup(next_word(&buf_ptr));
    811                         currmap->n_mappings++;
    812                     } else {
    813                         bb_error_msg("misplaced option \"%s\"", buf);
    814                         return NULL;
    815                     }
    816 #endif
    817                     break;
    818                 case NONE:
    819                 default:
     843                    currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&buf_ptr));
     844                    currmap->n_mappings++;
     845                } else {
    820846                    bb_error_msg("misplaced option \"%s\"", buf);
    821847                    return NULL;
     848                }
     849#endif
     850                break;
     851            case NONE:
     852            default:
     853                bb_error_msg("misplaced option \"%s\"", buf);
     854                return NULL;
    822855            }
    823856        }
     
    825858    }
    826859    if (ferror(f) != 0) {
    827         bb_perror_msg_and_die("%s", filename);
     860        /* ferror does NOT set errno! */
     861        bb_error_msg_and_die("%s: I/O error", filename);
    828862    }
    829863    fclose(f);
     
    832866}
    833867
    834 static char *setlocalenv(char *format, const char *name, const char *value)
     868static char *setlocalenv(const char *format, const char *name, const char *value)
    835869{
    836870    char *result;
     
    838872    char *there;
    839873
    840     result = bb_xasprintf(format, name, value);
     874    result = xasprintf(format, name, value);
    841875
    842876    for (here = there = result; *there != '=' && *there; there++) {
     
    863897    char **ppch;
    864898
    865     if (__myenviron != NULL) {
    866         for (ppch = __myenviron; *ppch; ppch++) {
     899    if (my_environ != NULL) {
     900        for (ppch = my_environ; *ppch; ppch++) {
    867901            free(*ppch);
    868902            *ppch = NULL;
    869903        }
    870         free(__myenviron);
    871     }
    872     __myenviron = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
    873     environend = __myenviron;
     904        free(my_environ);
     905    }
     906    my_environ = xzalloc(sizeof(char *) * (n_env_entries + 1 /* for final NULL */ ));
     907    environend = my_environ;
    874908
    875909    for (i = 0; i < iface->n_options; i++) {
    876910        if (strcmp(iface->option[i].name, "up") == 0
    877                 || strcmp(iface->option[i].name, "down") == 0
    878                 || strcmp(iface->option[i].name, "pre-up") == 0
    879                 || strcmp(iface->option[i].name, "post-down") == 0) {
     911         || strcmp(iface->option[i].name, "down") == 0
     912         || strcmp(iface->option[i].name, "pre-up") == 0
     913         || strcmp(iface->option[i].name, "post-down") == 0
     914        ) {
    880915            continue;
    881916        }
     
    887922    *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
    888923    *(environend++) = setlocalenv("%s=%s", "MODE", mode);
    889     *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
     924    *(environend++) = setlocalenv("%s=%s", "PATH", startup_PATH);
    890925}
    891926
    892927static int doit(char *str)
    893928{
    894     if (verbose || no_act) {
    895         printf("%s\n", str);
    896     }
    897     if (!no_act) {
     929    if (option_mask32 & (OPT_no_act|OPT_verbose)) {
     930        puts(str);
     931    }
     932    if (!(option_mask32 & OPT_no_act)) {
    898933        pid_t child;
    899934        int status;
    900935
    901936        fflush(NULL);
    902         switch (child = fork()) {
    903             case -1:        /* failure */
    904                 return 0;
    905             case 0:     /* child */
    906                 execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, __myenviron);
    907                 exit(127);
     937        child = fork();
     938        switch (child) {
     939        case -1: /* failure */
     940            return 0;
     941        case 0: /* child */
     942            execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, NULL, my_environ);
     943            exit(127);
    908944        }
    909945        waitpid(child, &status, 0);
     
    912948        }
    913949    }
    914     return (1);
     950    return 1;
    915951}
    916952
     
    927963    }
    928964
    929     buf = bb_xasprintf("run-parts /etc/network/if-%s.d", opt);
    930     if (doit(buf) != 1) {
    931         return 0;
    932     }
    933     return 1;
    934 }
    935 
    936 static int check(char *str) {
     965    buf = xasprintf("run-parts /etc/network/if-%s.d", opt);
     966    /* heh, we don't bother free'ing it */
     967    return doit(buf);
     968}
     969
     970static int check(char *str)
     971{
    937972    return str != NULL;
    938973}
     
    940975static int iface_up(struct interface_defn_t *iface)
    941976{
    942     if (!iface->method->up(iface,check)) return -1;
     977    if (!iface->method->up(iface, check)) return -1;
    943978    set_environ(iface, "start");
    944979    if (!execute_all(iface, "pre-up")) return 0;
     
    958993}
    959994
    960 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
     995#if ENABLE_FEATURE_IFUPDOWN_MAPPING
    961996static int popen2(FILE **in, FILE **out, char *command, ...)
    962997{
     
    9871022    fflush(NULL);
    9881023    switch (pid = fork()) {
    989         case -1:            /* failure */
    990             close(infd[0]);
    991             close(infd[1]);
    992             close(outfd[0]);
    993             close(outfd[1]);
    994             return 0;
    995         case 0:         /* child */
    996             dup2(infd[0], 0);
    997             dup2(outfd[1], 1);
    998             close(infd[0]);
    999             close(infd[1]);
    1000             close(outfd[0]);
    1001             close(outfd[1]);
    1002             execvp(command, argv);
    1003             exit(127);
    1004         default:            /* parent */
    1005             *in = fdopen(infd[1], "w");
    1006             *out = fdopen(outfd[0], "r");
    1007             close(infd[0]);
    1008             close(outfd[1]);
    1009             return pid;
     1024    case -1:            /* failure */
     1025        close(infd[0]);
     1026        close(infd[1]);
     1027        close(outfd[0]);
     1028        close(outfd[1]);
     1029        return 0;
     1030    case 0:         /* child */
     1031        dup2(infd[0], 0);
     1032        dup2(outfd[1], 1);
     1033        close(infd[0]);
     1034        close(infd[1]);
     1035        close(outfd[0]);
     1036        close(outfd[1]);
     1037        BB_EXECVP(command, argv);
     1038        exit(127);
     1039    default:            /* parent */
     1040        *in = fdopen(infd[1], "w");
     1041        *out = fdopen(outfd[0], "r");
     1042        close(infd[0]);
     1043        close(outfd[1]);
     1044        return pid;
    10101045    }
    10111046    /* unreached */
     
    10181053    pid_t pid;
    10191054
    1020     char *logical = bb_xstrdup(physical);
     1055    char *logical = xstrdup(physical);
    10211056
    10221057    /* Run the mapping script. */
     
    10381073         * grab a line of output and use that as the name of the
    10391074         * logical interface. */
    1040         char *new_logical = (char *)xmalloc(MAX_INTERFACE_LENGTH);
     1075        char *new_logical = xmalloc(MAX_INTERFACE_LENGTH);
    10411076
    10421077        if (fgets(new_logical, MAX_INTERFACE_LENGTH, out)) {
     
    10621097    return logical;
    10631098}
    1064 #endif /* CONFIG_FEATURE_IFUPDOWN_MAPPING */
     1099#endif /* FEATURE_IFUPDOWN_MAPPING */
    10651100
    10661101static llist_t *find_iface_state(llist_t *state_list, const char *iface)
     
    10701105
    10711106    while (search) {
    1072         if ((strncmp(search->data, iface, iface_len) == 0) &&
    1073                 (search->data[iface_len] == '=')) {
    1074             return(search);
     1107        if ((strncmp(search->data, iface, iface_len) == 0)
     1108         && (search->data[iface_len] == '=')) {
     1109            return search;
    10751110        }
    10761111        search = search->link;
    10771112    }
    1078     return(NULL);
    1079 }
    1080 
     1113    return NULL;
     1114}
     1115
     1116/* read the previous state from the state file */
     1117static llist_t *read_iface_state(void)
     1118{
     1119    llist_t *state_list = NULL;
     1120    FILE *state_fp = fopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "r");
     1121
     1122    if (state_fp) {
     1123        char *start, *end_ptr;
     1124        while ((start = xmalloc_fgets(state_fp)) != NULL) {
     1125            /* We should only need to check for a single character */
     1126            end_ptr = start + strcspn(start, " \t\n");
     1127            *end_ptr = '\0';
     1128            llist_add_to(&state_list, start);
     1129        }
     1130        fclose(state_fp);
     1131    }
     1132    return state_list;
     1133}
     1134
     1135
     1136int ifupdown_main(int argc, char **argv);
    10811137int ifupdown_main(int argc, char **argv)
    10821138{
    1083     int (*cmds) (struct interface_defn_t *) = NULL;
     1139    int (*cmds)(struct interface_defn_t *) = NULL;
    10841140    struct interfaces_file_t *defn;
    1085     llist_t *state_list = NULL;
    10861141    llist_t *target_list = NULL;
    10871142    const char *interfaces = "/etc/network/interfaces";
    1088     const char *statefile = "/var/run/ifstate";
    1089 
    1090 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1091     int run_mappings = 1;
    1092 #endif
    1093     int do_all = 0;
    1094     int force = 0;
    1095     int any_failures = 0;
    1096     int i;
    1097 
    1098     if (bb_applet_name[2] == 'u') {
     1143    bool any_failures = 0;
     1144
     1145    cmds = iface_down;
     1146    if (applet_name[2] == 'u') {
    10991147        /* ifup command */
    11001148        cmds = iface_up;
     1149    }
     1150
     1151    getopt32(argv, OPTION_STR, &interfaces);
     1152    if (argc - optind > 0) {
     1153        if (DO_ALL) bb_show_usage();
    11011154    } else {
    1102         /* ifdown command */
    1103         cmds = iface_down;
    1104     }
    1105 
    1106 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1107     while ((i = getopt(argc, argv, "i:hvnamf")) != -1)
    1108 #else
    1109         while ((i = getopt(argc, argv, "i:hvnaf")) != -1)
    1110 #endif
    1111         {
    1112             switch (i) {
    1113                 case 'i':   /* interfaces */
    1114                     interfaces = optarg;
    1115                     break;
    1116                 case 'v':   /* verbose */
    1117                     verbose = 1;
    1118                     break;
    1119                 case 'a':   /* all */
    1120                     do_all = 1;
    1121                     break;
    1122                 case 'n':   /* no-act */
    1123                     no_act = 1;
    1124                     break;
    1125 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1126                 case 'm':   /* no-mappings */
    1127                     run_mappings = 0;
    1128                     break;
    1129 #endif
    1130                 case 'f':   /* force */
    1131                     force = 1;
    1132                     break;
    1133                 default:
    1134                     bb_show_usage();
    1135                     break;
    1136             }
    1137         }
    1138 
    1139     if (argc - optind > 0) {
    1140         if (do_all) {
    1141             bb_show_usage();
    1142         }
    1143     } else {
    1144         if (!do_all) {
    1145             bb_show_usage();
    1146         }
     1155        if (!DO_ALL) bb_show_usage();
    11471156    }
    11481157
     
    11521161
    11531162    if (!defn) {
    1154         exit(EXIT_FAILURE);
    1155     }
     1163        return EXIT_FAILURE;
     1164    }
     1165
     1166    startup_PATH = getenv("PATH");
     1167    if (!startup_PATH) startup_PATH = "";
    11561168
    11571169    /* Create a list of interfaces to work on */
    1158     if (do_all) {
    1159         if (cmds == iface_up) {
    1160             target_list = defn->autointerfaces;
    1161         } else {
    1162             /* iface_down */
    1163             const llist_t *list = state_list;
    1164             while (list) {
    1165                 llist_add_to_end(&target_list, bb_xstrdup(list->data));
    1166                 list = list->link;
    1167             }
    1168             target_list = defn->autointerfaces;
    1169         }
     1170    if (DO_ALL) {
     1171        target_list = defn->autointerfaces;
    11701172    } else {
    11711173        llist_add_to_end(&target_list, argv[optind]);
    11721174    }
    1173 
    11741175
    11751176    /* Update the interfaces */
     
    11801181        char *liface;
    11811182        char *pch;
    1182         int okay = 0;
    1183         int cmds_ret;
    1184 
    1185         iface = bb_xstrdup(target_list->data);
     1183        bool okay = 0;
     1184        unsigned cmds_ret;
     1185
     1186        iface = xstrdup(target_list->data);
    11861187        target_list = target_list->link;
    11871188
     
    11891190        if (pch) {
    11901191            *pch = '\0';
    1191             liface = bb_xstrdup(pch + 1);
     1192            liface = xstrdup(pch + 1);
    11921193        } else {
    1193             liface = bb_xstrdup(iface);
    1194         }
    1195 
    1196         if (!force) {
     1194            liface = xstrdup(iface);
     1195        }
     1196
     1197        if (!FORCE) {
     1198            llist_t *state_list = read_iface_state();
    11971199            const llist_t *iface_state = find_iface_state(state_list, iface);
    11981200
     
    12051207            } else {
    12061208                /* ifdown */
    1207                 if (iface_state) {
     1209                if (!iface_state) {
    12081210                    bb_error_msg("interface %s not configured", iface);
    12091211                    continue;
    12101212                }
    12111213            }
    1212         }
    1213 
    1214 #ifdef CONFIG_FEATURE_IFUPDOWN_MAPPING
    1215         if ((cmds == iface_up) && run_mappings) {
     1214            llist_free(state_list, free);
     1215        }
     1216
     1217#if ENABLE_FEATURE_IFUPDOWN_MAPPING
     1218        if ((cmds == iface_up) && !NO_MAPPINGS) {
    12161219            struct mapping_defn_t *currmap;
    12171220
    12181221            for (currmap = defn->mappings; currmap; currmap = currmap->next) {
    1219 
     1222                int i;
    12201223                for (i = 0; i < currmap->n_matches; i++) {
    12211224                    if (fnmatch(currmap->match[i], liface, 0) != 0)
    12221225                        continue;
    1223                     if (verbose) {
     1226                    if (VERBOSE) {
    12241227                        printf("Running mapping script %s on %s\n", currmap->script, liface);
    12251228                    }
     
    12301233        }
    12311234#endif
    1232 
    12331235
    12341236        iface_list = defn->ifaces;
     
    12461248                cmds_ret = cmds(currif);
    12471249                if (cmds_ret == -1) {
    1248                     bb_error_msg("Don't seem to have all the variables for %s/%s.",
     1250                    bb_error_msg("don't seem to have all the variables for %s/%s",
    12491251                            liface, currif->address_family->name);
    1250                     any_failures += 1;
     1252                    any_failures = 1;
    12511253                } else if (cmds_ret == 0) {
    1252                     any_failures += 1;
     1254                    any_failures = 1;
    12531255                }
    12541256
     
    12571259            iface_list = iface_list->link;
    12581260        }
    1259         if (verbose) {
    1260             printf("\n");
    1261         }
    1262 
    1263         if (!okay && !force) {
    1264             bb_error_msg("Ignoring unknown interface %s", liface);
    1265             any_failures += 1;
    1266         } else {
     1261        if (VERBOSE) {
     1262            puts("");
     1263        }
     1264
     1265        if (!okay && !FORCE) {
     1266            bb_error_msg("ignoring unknown interface %s", liface);
     1267            any_failures = 1;
     1268        } else if (!NO_ACT) {
     1269            /* update the state file */
     1270            FILE *state_fp;
     1271            llist_t *state;
     1272            llist_t *state_list = read_iface_state();
    12671273            llist_t *iface_state = find_iface_state(state_list, iface);
    12681274
    12691275            if (cmds == iface_up) {
    1270                 char *newiface = bb_xasprintf("%s=%s", iface, liface);
     1276                char * const newiface = xasprintf("%s=%s", iface, liface);
    12711277                if (iface_state == NULL) {
    12721278                    llist_add_to_end(&state_list, newiface);
     
    12761282                }
    12771283            } else {
    1278                 /* Remove an interface from the linked list */
     1284                /* Remove an interface from state_list */
     1285                llist_unlink(&state_list, iface_state);
    12791286                free(llist_pop(&iface_state));
    12801287            }
    1281         }
    1282     }
    1283 
    1284     /* Actually write the new state */
    1285     if (!no_act) {
    1286         FILE *state_fp = NULL;
    1287 
    1288         state_fp = bb_xfopen(statefile, "w");
    1289         while (state_list) {
    1290             if (state_list->data) {
    1291                 fputs(state_list->data, state_fp);
    1292                 fputc('\n', state_fp);
    1293             }
    1294             state_list = state_list->link;
    1295         }
    1296         fclose(state_fp);
    1297     }
    1298 
    1299     if (any_failures)
    1300         return 1;
    1301     return 0;
    1302 }
     1288
     1289            /* Actually write the new state */
     1290            state_fp = xfopen(CONFIG_IFUPDOWN_IFSTATE_PATH, "w");
     1291            state = state_list;
     1292            while (state) {
     1293                if (state->data) {
     1294                    fprintf(state_fp, "%s\n", state->data);
     1295                }
     1296                state = state->link;
     1297            }
     1298            fclose(state_fp);
     1299            llist_free(state_list, free);
     1300        }
     1301    }
     1302
     1303    return any_failures;
     1304}
Note: See TracChangeset for help on using the changeset viewer.