Fixed a memory leak in lash. It seems that close_all was calling close()
[oweals/busybox.git] / ifconfig.c
index a3e2c0fdbb7da0a40f6e86896b05a2f2d76f5dbb..2a50a96056bea63e2bf7bf5d194ad565ae37c99e 100644 (file)
  * Foundation;  either  version 2 of the License, or  (at
  * your option) any later version.
  *
- * $Id: ifconfig.c,v 1.3 2001/02/20 06:14:07 andersen Exp $
+ * $Id: ifconfig.c,v 1.4 2001/03/06 00:48:59 andersen Exp $
+ *
+ * Majorly hacked up by Larry Doolittle <ldoolitt@recycle.lbl.gov> 
  *
  */
 
+#include "busybox.h"
+#include <sys/types.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>   // strcmp and friends
 #include <ctype.h>    // isdigit and friends
-#include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <linux/if_ether.h>
-#include "busybox.h"
 
 static int sockfd;  /* socket fd we use to manipulate stuff with */
 
+#define TESTME 0
+#if TESTME
+#define ioctl test_ioctl
+char *saddr_to_a(struct sockaddr *s)
+{
+       if (s->sa_family == ARPHRD_ETHER) {
+               static char hw[18];
+               sprintf(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+                       s->sa_data[0], s->sa_data[1], s->sa_data[2],
+                       s->sa_data[3], s->sa_data[4], s->sa_data[5]);
+               return hw;
+       } else if (s->sa_family == AF_INET) {
+               struct sockaddr_in *ss = (struct sockaddr_in *) s;
+               return inet_ntoa(ss->sin_addr);
+       } else {
+               return NULL;
+       }
+}
+
+int test_ioctl(int __fd, unsigned long int __request, void *param)
+{
+       struct ifreq *i=(struct ifreq *)param;
+       printf("ioctl fd=%d, request=%ld\n", __fd, __request);
+       
+       switch(__request) {
+               case SIOCGIFFLAGS:   printf("  SIOCGIFFLAGS\n");       i->ifr_flags = 0;   break;
+               case SIOCSIFFLAGS:   printf("  SIOCSIFFLAGS, %x\n",    i->ifr_flags);     break;
+               case SIOCSIFMETRIC:  printf("  SIOCSIFMETRIC, %d\n",   i->ifr_metric);    break;
+               case SIOCSIFMTU:     printf("  SIOCSIFMTU, %d\n",      i->ifr_mtu);       break;
+               case SIOCSIFBRDADDR: printf("  SIOCSIFBRDADDR, %s\n",  saddr_to_a(&(i->ifr_broadaddr))); break;
+               case SIOCSIFDSTADDR: printf("  SIOCSIFDSTADDR, %s\n",  saddr_to_a(&(i->ifr_dstaddr  ))); break;
+               case SIOCSIFNETMASK: printf("  SIOCSIFNETMASK, %s\n",  saddr_to_a(&(i->ifr_netmask  ))); break;
+               case SIOCSIFADDR:    printf("  SIOCSIFADDR, %s\n",     saddr_to_a(&(i->ifr_addr     ))); break;
+               case SIOCSIFHWADDR:  printf("  SIOCSIFHWADDR, %s\n",   saddr_to_a(&(i->ifr_hwaddr   ))); break;  /* broken */
+               default:
+       }
+       return 0;
+}
+#endif
+
+
 /* print usage and exit */
 
 #define _(x) x
@@ -49,7 +92,7 @@ set_flag(char *ifname, short flag)
        strcpy(ifr.ifr_name, ifname);
        if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
                perror("SIOCGIFFLAGS"); 
-               return (-1);
+               return -1;
        }
        strcpy(ifr.ifr_name, ifname);
        ifr.ifr_flags |= flag;
@@ -57,7 +100,7 @@ set_flag(char *ifname, short flag)
                perror("SIOCSIFFLAGS");
                return -1;
        }
-       return (0);
+       return 0;
 }
 
 
@@ -78,9 +121,62 @@ clr_flag(char *ifname, short flag)
                perror("SIOCSIFFLAGS");
                return -1;
        }
-       return (0);
+       return 0;
 }
 
+/* which element in struct ifreq to frob */
+enum frob {
+       L_METRIC,
+       L_MTU,
+       L_DATA,
+       L_BROAD,
+       L_DEST,
+       L_MASK,
+       L_HWAD,
+};
+
+
+struct flag_map {
+       char *name;
+       enum frob frob;
+       int flag;
+       int sflag;
+       int action;
+};
+
+/* action:
+ *  2   set
+ *  4   clear
+ *  6   set/clear
+ *  8   clear/set
+ *  10  numeric
+ *  12  address
+ *  14  address/clear
+ */
+const static struct flag_map flag_table[] = {
+       {"arp",         0,  IFF_NOARP,             0, 6},
+       {"trailers",    0,  IFF_NOTRAILERS,        0, 6},
+       {"promisc",     0,  IFF_PROMISC,           0, 8},
+       {"multicast",   0,  IFF_MULTICAST,         0, 8},
+       {"allmulti",    0,  IFF_ALLMULTI,          0, 8},
+       {"up",          0, (IFF_UP | IFF_RUNNING), 0, 2},
+       {"down",        0,  IFF_UP,                0, 4},
+       {"metric",      L_METRIC,              0, SIOCSIFMETRIC,  10},
+       {"mtu",         L_MTU,                 0, SIOCSIFMTU,     10},
+#ifdef SIOCSKEEPALIVE
+       {"keepalive",   L_DATA,                0, SIOCSKEEPALIVE, 10},
+#endif
+#ifdef SIOCSOUTFILL
+       {"outfill",     L_DATA,                0, SIOCSOUTFILL,   10},
+#endif
+       {"broadcast",   L_BROAD, IFF_BROADCAST,   SIOCSIFBRDADDR, 14},
+       {"dstaddr",     L_DEST,                0, SIOCSIFDSTADDR, 12},
+       {"netmask",     L_MASK,                0, SIOCSIFNETMASK, 12},
+       {"pointopoint", L_DEST,  IFF_POINTOPOINT, SIOCSIFDSTADDR, 14},
+       {"hw",          L_HWAD,                0, SIOCSIFHWADDR,  14},
+};
+
+
 /* resolve XXX.YYY.ZZZ.QQQ -> binary */
 
 static int
@@ -90,15 +186,16 @@ INET_resolve(char *name, struct sockaddr_in *sin)
        sin->sin_port = 0;
 
        /* Default is special, meaning 0.0.0.0. */
-       if (!strcmp(name, "default")) {
+       if (strcmp(name, "default")==0) {
                sin->sin_addr.s_addr = INADDR_ANY;
-               return (1);
+               return 1;
        }
        /* Look to see if it's a dotted quad. */
        if (inet_aton(name, &sin->sin_addr)) {
                return 0;
        }
        /* guess not.. */
+       errno = EINVAL;
        return -1;
 }
 
@@ -127,12 +224,12 @@ in_ether(char *bufp, struct sockaddr *sap)
                        val = c - 'A' + 10;
                else {
 #ifdef DEBUG
-                       fprintf(stderr,
-                               _("in_ether(%s): invalid ether address!\n"),
+                       error_msg(
+                               _("in_ether(%s): invalid ether address!"),
                                orig);
 #endif
                        errno = EINVAL;
-                       return (-1);
+                       return -1;
                }
                val <<= 4;
                c = *bufp;
@@ -146,22 +243,19 @@ in_ether(char *bufp, struct sockaddr *sap)
                        val >>= 4;
                else {
 #ifdef DEBUG
-                       fprintf(stderr,
-                               _("in_ether(%s): invalid ether address!\n"),
+                       error_msg(
+                               _("in_ether(%s): invalid ether address!"),
                                orig);
 #endif
                        errno = EINVAL;
-                       return (-1);
+                       return -1;
                }
                if (c != 0)
                        bufp++;
                *ptr++ = (unsigned char) (val & 0377);
                i++;
                
-               /* We might get a semicolon here - not required. */
-               if (*bufp == ':')
-                       bufp++;
-               
+               /* optional colon already handled, don't swallow a second */
        }
 
        if(i != ETH_ALEN) {
@@ -171,25 +265,37 @@ in_ether(char *bufp, struct sockaddr *sap)
 
        return 0;
 }
+               
+#ifdef BB_FEATURE_IFCONFIG_STATUS
+extern int display_interfaces(void);
+#else
+int display_interfaces(void)
+{
+    show_usage();
+}
+#endif
 
 int ifconfig_main(int argc, char **argv)
 {
        struct ifreq ifr;
        struct sockaddr_in sa;
-       struct sockaddr sa2;
-       char **spp;
+       char **spp, *cmd;
        int goterr = 0;
-       int r, didnetmask = 0;
+       int r;
+       /* int didnetmask = 0;   special case input error detection no longer implemented */
        char host[128];
+       const struct flag_map *ft;
+       int i, sense;
+       int a, ecode;
+       struct sockaddr *d;
 
        if(argc < 2) {
-               show_usage();
+               return(display_interfaces());
        }
 
        /* Create a channel to the NET kernel. */
        if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               perror("socket");
-               exit(1);
+               perror_msg_and_die("socket");
        }
 
        /* skip argv[0] */
@@ -205,235 +311,84 @@ int ifconfig_main(int argc, char **argv)
 
        /* Process the remaining arguments. */
        while (*spp != (char *) NULL) {
-               if (!strcmp(*spp, "arp")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "-arp")) {
-                       goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
-                       spp++;
-                       continue;
-               }
-               
-               if (!strcmp(*spp, "trailers")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_NOTRAILERS);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "-trailers")) {
-                       goterr |= set_flag(ifr.ifr_name, IFF_NOTRAILERS);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "promisc")) {
-                       goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "-promisc")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "multicast")) {
-                       goterr |= set_flag(ifr.ifr_name, IFF_MULTICAST);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "-multicast")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_MULTICAST);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "allmulti")) {
-                       goterr |= set_flag(ifr.ifr_name, IFF_ALLMULTI);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "-allmulti")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_ALLMULTI);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "up")) {
-                       goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "down")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_UP);
-                       spp++;
-                       continue;
-               }
-
-               if (!strcmp(*spp, "metric")) {
-                       if (*++spp == NULL)
-                               show_usage();
-                       ifr.ifr_metric = atoi(*spp);
-                       if (ioctl(sockfd, SIOCSIFMETRIC, &ifr) < 0) {
-                               fprintf(stderr, "SIOCSIFMETRIC: %s\n", strerror(errno));
-                               goterr++;
-                       }
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "mtu")) {
-                       if (*++spp == NULL)
-                               show_usage();
-                       ifr.ifr_mtu = atoi(*spp);
-                       if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
-                               fprintf(stderr, "SIOCSIFMTU: %s\n", strerror(errno));
-                               goterr++;
-                       }
-                       spp++;
-                       continue;
+               cmd = *spp;
+               sense=0;
+               if (*cmd=='-') {
+                       sense=1;
+                       cmd++;
                }
-#ifdef SIOCSKEEPALIVE
-               if (!strcmp(*spp, "keepalive")) {
-                       if (*++spp == NULL)
-                               show_usage();
-                       ifr.ifr_data = (caddr_t) atoi(*spp);
-                       if (ioctl(sockfd, SIOCSKEEPALIVE, &ifr) < 0) {
-                               fprintf(stderr, "SIOCSKEEPALIVE: %s\n", strerror(errno));
-                               goterr++;
-                       }
-                       spp++;
-                       continue;
-               }
-#endif
-
-#ifdef SIOCSOUTFILL
-               if (!strcmp(*spp, "outfill")) {
-                       if (*++spp == NULL)
-                               show_usage();
-                       ifr.ifr_data = (caddr_t) atoi(*spp);
-                       if (ioctl(sockfd, SIOCSOUTFILL, &ifr) < 0) {
-                               fprintf(stderr, "SIOCSOUTFILL: %s\n", strerror(errno));
-                               goterr++;
+               ft = NULL;
+               for (i=0; i<(sizeof(flag_table)/sizeof(struct flag_map)); i++) {
+                       if (strcmp(cmd, flag_table[i].name)==0) {
+                               ft=flag_table+i;
+                               spp++;
+                               break;
                        }
-                       spp++;
-                       continue;
                }
-#endif
+               if (ft) {
+                       switch (ft->action+sense) {
+                       case 4:
+                       case 7:
+                       case 8:
+                       case 15:
+                               goterr |= clr_flag(ifr.ifr_name, ft->flag);
+                               break;
+                       case 2:
+                       case 6:
+                       case 9:
+                               goterr |= set_flag(ifr.ifr_name, ft->flag);
+                               break;
+                       case 10:
+                               if (*spp == NULL)
+                                       show_usage();
+                               a = atoi(*spp++);
+                               switch (ft->frob) {
+                                       case L_METRIC: ifr.ifr_metric = a; break;
+                                       case L_MTU:    ifr.ifr_mtu    = a; break;
+                                       case L_DATA:   ifr.ifr_data   = (caddr_t) a; break;
+                                       default: error_msg_and_die("bugaboo");
+                               }
 
-               if (!strcmp(*spp, "-broadcast")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_BROADCAST);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "broadcast")) {
-                       if (*++spp != NULL) {
-                               safe_strncpy(host, *spp, (sizeof host));
-                               if (INET_resolve(host, &sa) < 0) {
+                               if (ioctl(sockfd, ft->sflag, &ifr) < 0) {
+                                       perror(ft->name);  /* imperfect */
                                        goterr++;
-                                       spp++;
-                                       continue;
                                }
-                               memcpy((char *) &ifr.ifr_broadaddr,
-                                      (char *) &sa,
-                                      sizeof(struct sockaddr));
-                               if (ioctl(sockfd, SIOCSIFBRDADDR, &ifr) < 0) {
-                                       perror("SIOCSIFBRDADDR");
-                                       goterr++;
+                               break;
+                       case 12:
+                       case 14:
+                               if (ft->action+sense==10 && *spp == NULL) {
+                                       show_usage();
+                                       break;
                                }
-                               spp++;
-                       }
-                       goterr |= set_flag(ifr.ifr_name, IFF_BROADCAST);
-                       continue;
-               }
-               if (!strcmp(*spp, "dstaddr")) {
-                       if (*++spp == NULL)
-                               show_usage();
-                       safe_strncpy(host, *spp, (sizeof host));
-                       if (INET_resolve(host, &sa) < 0) {
-                               goterr++;
-                               spp++;
-                               continue;
-                       }
-                       memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
-                              sizeof(struct sockaddr));
-                       if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
-                               fprintf(stderr, "SIOCSIFDSTADDR: %s\n",
-                                       strerror(errno));
-                               goterr++;
-                       }
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "netmask")) {
-                       if (*++spp == NULL || didnetmask)
-                               show_usage();
-                       safe_strncpy(host, *spp, (sizeof host));
-                       if (INET_resolve(host, &sa) < 0) {
-                               goterr++;
-                               spp++;
-                               continue;
-                       }
-                       didnetmask++;
-                       memcpy((char *) &ifr.ifr_netmask, (char *) &sa,
-                              sizeof(struct sockaddr));
-                       if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
-                               perror("SIOCSIFNETMASK");
-                               goterr++;
-                       }
-                       spp++;
-                       continue;
-               }
-
-               if (!strcmp(*spp, "-pointopoint")) {
-                       goterr |= clr_flag(ifr.ifr_name, IFF_POINTOPOINT);
-                       spp++;
-                       continue;
-               }
-               if (!strcmp(*spp, "pointopoint")) {
-                       if (*(spp + 1) != NULL) {
-                               spp++;
-                               safe_strncpy(host, *spp, (sizeof host));
-                               if (INET_resolve(host, &sa)) {
-                                       goterr++;
+                               if (*spp != NULL) {
+                                       safe_strncpy(host, *spp, (sizeof host));
                                        spp++;
-                                       continue;
+                                       if (ft->frob == L_HWAD) {
+                                               ecode = in_ether(host, &ifr.ifr_hwaddr);
+                                       } else {
+                                               switch (ft->frob) {
+                                                       case L_BROAD: d = &ifr.ifr_broadaddr; break;
+                                                       case L_DEST:  d = &ifr.ifr_dstaddr;   break;
+                                                       case L_MASK:  d = &ifr.ifr_netmask;   break;
+                                                       default: error_msg_and_die("bugaboo");
+                                               }
+                                               ecode = INET_resolve(host, (struct sockaddr_in *) d);
+                                       }
+                                       if (ecode < 0 || ioctl(sockfd, ft->sflag, &ifr) < 0) {
+                                               perror(ft->name);  /* imperfect */
+                                               goterr++;
+                                       }
                                }
-                               memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
-                                      sizeof(struct sockaddr));
-                               if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
-                                       perror("SIOCSIFDSTADDR");
-                                       goterr++;
+                               if (ft->flag != 0) {
+                                       goterr |= set_flag(ifr.ifr_name, ft->flag);
                                }
-                       }
-                       goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
-                       spp++;
-                       continue;
-               };
-
-               if (!strcmp(*spp, "hw")) {
-                       if (*++spp == NULL || strcmp("ether", *spp)) {
+                               break;
+                       default:
                                show_usage();
-                       }
-                               
-                       if (*++spp == NULL) {
-                               /* silently ignore it if no address */
-                               continue;
-                       }
-
-                       safe_strncpy(host, *spp, (sizeof host));
-                       if (in_ether(host, &sa2) < 0) {
-                               fprintf(stderr, "invalid hw-addr %s\n", host);
-                               goterr++;
-                               spp++;
-                               continue;
-                       }
-                       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sa2,
-                              sizeof(struct sockaddr));
-                       if (ioctl(sockfd, SIOCSIFHWADDR, &ifr) < 0) {
-                               perror("SIOCSIFHWADDR");
-                               goterr++;
-                       }
-                       spp++;
+                       } /* end of switch */
                        continue;
                }
-
+               
                /* If the next argument is a valid hostname, assume OK. */
                safe_strncpy(host, *spp, (sizeof host));
 
@@ -471,6 +426,6 @@ int ifconfig_main(int argc, char **argv)
 
        } /* end of while-loop */
 
-        exit(0);
+        return goterr;
 }