Add in a first pass at ifconfig status reporting.  It took a long while
hacking on the mess in net-tools-1.59, but it currently adds 12k and
supports ethernet, loop, ppp, and treats everything else as a generic
interface.  Works ok for me.
 -Erik
diff --git a/ifconfig.c b/ifconfig.c
index a3e2c0f..2a50a96 100644
--- a/ifconfig.c
+++ b/ifconfig.c
@@ -15,16 +15,19 @@
  * 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>
@@ -32,10 +35,50 @@
 #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 @@
 	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 @@
 		perror("SIOCSIFFLAGS");
 		return -1;
 	}
-	return (0);
+	return 0;
 }
 
 
@@ -78,9 +121,62 @@
 		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 @@
 	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 @@
 			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 @@
 			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 @@
 
 	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 @@
 
 	/* Process the remaining arguments. */
 	while (*spp != (char *) NULL) {
-		if (!strcmp(*spp, "arp")) {
-			goterr |= clr_flag(ifr.ifr_name, IFF_NOARP);
-			spp++;
-			continue;
+		cmd = *spp;
+		sense=0;
+		if (*cmd=='-') {
+			sense=1;
+			cmd++;
 		}
-		if (!strcmp(*spp, "-arp")) {
-			goterr |= set_flag(ifr.ifr_name, IFF_NOARP);
-			spp++;
+		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;
+			}
+		}
+		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 (ioctl(sockfd, ft->sflag, &ifr) < 0) {
+					perror(ft->name);  /* imperfect */
+					goterr++;
+				}
+				break;
+			case 12:
+			case 14:
+				if (ft->action+sense==10 && *spp == NULL) {
+					show_usage();
+					break;
+				}
+				if (*spp != NULL) {
+					safe_strncpy(host, *spp, (sizeof host));
+					spp++;
+					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++;
+					}
+				}
+				if (ft->flag != 0) {
+					goterr |= set_flag(ifr.ifr_name, ft->flag);
+				}
+				break;
+			default:
+				show_usage();
+			} /* end of switch */
 			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;
-		}
-#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++;
-			}
-			spp++;
-			continue;
-		}
-#endif
-
-		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) {
-					goterr++;
-					spp++;
-					continue;
-				}
-				memcpy((char *) &ifr.ifr_broadaddr,
-				       (char *) &sa,
-				       sizeof(struct sockaddr));
-				if (ioctl(sockfd, SIOCSIFBRDADDR, &ifr) < 0) {
-					perror("SIOCSIFBRDADDR");
-					goterr++;
-				}
-				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++;
-					spp++;
-					continue;
-				}
-				memcpy((char *) &ifr.ifr_dstaddr, (char *) &sa,
-				       sizeof(struct sockaddr));
-				if (ioctl(sockfd, SIOCSIFDSTADDR, &ifr) < 0) {
-					perror("SIOCSIFDSTADDR");
-					goterr++;
-				}
-			}
-			goterr |= set_flag(ifr.ifr_name, IFF_POINTOPOINT);
-			spp++;
-			continue;
-		};
-
-		if (!strcmp(*spp, "hw")) {
-			if (*++spp == NULL || strcmp("ether", *spp)) {
-				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++;
-			continue;
-		}
-
 		/* If the next argument is a valid hostname, assume OK. */
 		safe_strncpy(host, *spp, (sizeof host));
 
@@ -471,6 +426,6 @@
 
 	} /* end of while-loop */
 
-        exit(0);
+        return goterr;
 }