+ for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
+ for (argv[0]++; *argv[0]; argv[0]++)
+ switch (*argv[0]) {
+ case 'f':
+ doflush++;
+ break;
+ case 'n':
+ nflag++;
+ break;
+ }
+ }
+ if (doflush)
+ flushroutes();
+ if (argc > 0) {
+ if (strcmp(*argv, "add") == 0)
+ newroute(argc, argv);
+ else if (strcmp(*argv, "delete") == 0)
+ newroute(argc, argv);
+ else if (strcmp(*argv, "change") == 0)
+ changeroute(argc-1, argv+1);
+ else
+ printf("%s: huh?\n", *argv);
+ }
+}
+
+/*
+ * Purge all entries in the routing tables not
+ * associated with network interfaces.
+ */
+#include <nlist.h>
+
+struct nlist nl[] = {
+#define N_RTHOST 0
+ { "_rthost" },
+#define N_RTNET 1
+ { "_rtnet" },
+#define N_RTHASHSIZE 2
+ { "_rthashsize" },
+ "",
+};
+
+flushroutes()
+{
+ struct mbuf mb;
+ register struct rtentry *rt;
+ register struct mbuf *m;
+ struct mbuf **routehash;
+ int rthashsize, i, doinghost = 1, kmem;
+ char *routename(), *netname();
+
+ nlist("/vmunix", nl);
+ if (nl[N_RTHOST].n_value == 0) {
+ printf("route: \"rthost\", symbol not in namelist\n");
+ exit(1);
+ }
+ if (nl[N_RTNET].n_value == 0) {
+ printf("route: \"rtnet\", symbol not in namelist\n");
+ exit(1);
+ }
+ if (nl[N_RTHASHSIZE].n_value == 0) {
+ printf("route: \"rthashsize\", symbol not in namelist\n");
+ exit(1);
+ }
+ kmem = open("/dev/kmem", 0);
+ if (kmem < 0) {
+ perror("route: /dev/kmem");
+ exit(1);
+ }
+ lseek(kmem, nl[N_RTHASHSIZE].n_value, 0);
+ read(kmem, &rthashsize, sizeof (rthashsize));
+ routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
+
+ lseek(kmem, nl[N_RTHOST].n_value, 0);
+ read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
+ printf("Flushing routing tables:\n");
+again:
+ for (i = 0; i < rthashsize; i++) {
+ if (routehash[i] == 0)
+ continue;
+ m = routehash[i];
+ while (m) {
+ lseek(kmem, m, 0);
+ read(kmem, &mb, sizeof (mb));
+ rt = mtod(&mb, struct rtentry *);
+ if (rt->rt_flags & RTF_GATEWAY) {
+ printf("%-20.20s ", doinghost ?
+ routename(&rt->rt_dst) :
+ netname(&rt->rt_dst));
+ printf("%-20.20s ", routename(&rt->rt_gateway));
+ if (ioctl(s, SIOCDELRT, (caddr_t)rt) < 0)
+ error("delete");
+ else
+ printf("done\n");
+ }
+ m = mb.m_next;
+ }
+ }
+ if (doinghost) {
+ lseek(kmem, nl[N_RTNET].n_value, 0);
+ read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
+ doinghost = 0;
+ goto again;
+ }
+ close(kmem);
+ free(routehash);
+}
+
+char *
+routename(sa)
+ struct sockaddr *sa;
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+ char *index();
+ char *ns_print();
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ cp = 0;
+ if (in.s_addr == INADDR_ANY)
+ cp = "default";
+ if (cp == 0 && !nflag) {
+ hp = gethostbyaddr(&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp)
+ strcpy(line, cp);
+ else {
+#define C(x) ((x) & 0xff)
+ in.s_addr = ntohl(in.s_addr);
+ (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ }
+ break;
+ }
+
+ case AF_NS:
+ return (ns_print((struct sockaddr_ns *)sa));
+
+ default:
+ { u_short *s = (u_short *)sa->sa_data;
+
+ (void)sprintf(line, "af %d: %x %x %x %x %x %x %x",
+ sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
+ break;
+ }
+ }
+ return (line);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+char *
+netname(sa)
+ struct sockaddr *sa;
+{
+ char *cp = 0;
+ static char line[50];
+ struct netent *np = 0;
+ u_long net, mask;
+ register u_long i;
+ int subnetshift;
+ char *ns_print();
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ i = in.s_addr = ntohl(in.s_addr);
+ if (in.s_addr == 0)
+ cp = "default";
+ else if (!nflag) {
+ if (IN_CLASSA(i)) {
+ mask = IN_CLASSA_NET;
+ subnetshift = 8;
+ } else if (IN_CLASSB(i)) {
+ mask = IN_CLASSB_NET;
+ subnetshift = 8;
+ } else {
+ mask = IN_CLASSC_NET;
+ subnetshift = 4;
+ }
+ /*
+ * If there are more bits than the standard mask
+ * would suggest, subnets must be in use.
+ * Guess at the subnet mask, assuming reasonable
+ * width subnet fields.
+ */
+ while (in.s_addr &~ mask)
+ mask = (long)mask >> subnetshift;
+ net = in.s_addr & mask;
+ while ((mask & 1) == 0)
+ mask >>= 1, net >>= 1;
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp)
+ strcpy(line, cp);
+ else if ((in.s_addr & 0xffffff) == 0)
+ (void)sprintf(line, "%u", C(in.s_addr >> 24));
+ else if ((in.s_addr & 0xffff) == 0)
+ (void)sprintf(line, "%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16));
+ else if ((in.s_addr & 0xff) == 0)
+ (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8));
+ else
+ (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8),
+ C(in.s_addr));
+ break;
+ }
+
+ case AF_NS:
+ return (ns_print((struct sockaddr_ns *)sa));
+ break;
+
+ default:
+ { u_short *s = (u_short *)sa->sa_data;
+
+ (void)sprintf(line, "af %d: %x %x %x %x %x %x %x",
+ sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
+ break;
+ }
+ }
+ return (line);