add proper return to savegateway() from Mike Muuss (mike@brl.mil)
[unix-history] / usr / src / old / htable / htable.c
index cee5094..02974e9 100644 (file)
@@ -1,6 +1,18 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif not lint
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)htable.c   4.3 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)htable.c   5.5 (Berkeley) %G%";
+#endif not lint
 
 /*
  * htable - convert NIC host table into a UNIX format.
 
 /*
  * htable - convert NIC host table into a UNIX format.
@@ -10,34 +22,61 @@ static char sccsid[] = "@(#)htable.c        4.3 (Berkeley) %G%";
 #include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
 #include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
-#include <sys/socket.h>
 
 #include "htable.h"            /* includes <sys/types.h> */
 
 
 #include "htable.h"            /* includes <sys/types.h> */
 
+#include <sys/socket.h>
 #include <netinet/in.h>
 
 #include <netinet/in.h>
 
-#define        INTERNET        10      /* gag */
+#define        DATELINES       3       /* these lines usually contain the date */
+#define        MAXNETS         30      /* array size for local, connected nets */
 
 FILE   *hf;                    /* hosts file */
 FILE   *gf;                    /* gateways file */
 FILE   *nf;                    /* networks file */
 
 FILE   *hf;                    /* hosts file */
 FILE   *gf;                    /* gateways file */
 FILE   *nf;                    /* networks file */
+struct gateway *savegateway(), *gatewayto();
+
+int connected_nets[MAXNETS];
+int nconnected;
+int local_nets[MAXNETS];
+int nlocal;
+char *myname;
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
-       if (argc > 2) {
-               fprintf(stderr, "usage: %s [ input-file ]\n",
-                       argv[0]);
-               exit(1);
-       }
+       int errs;
+
        infile = "(stdin)";
        infile = "(stdin)";
-       if (argc == 2) {
-               infile = argv[1];
-               if (freopen(infile, "r", stdin) == NULL) {
-                       perror(infile);
-                       exit(1);
+       myname = argv[0];
+       argc--;
+       argv++;
+       while (argc--) {
+               if (*argv[0] == '-') {
+                       switch (argv[0][1]) {
+                       case 'c':
+                               nconnected = addlocal(argv[1], connected_nets);
+                               argv++;
+                               argc--;
+                               break;
+                       case 'l':
+                               nlocal = addlocal(argv[1], local_nets);
+                               argv++;
+                               argc--;
+                               break;
+                       default:
+                               usage();
+                               /*NOTREACHED*/
+                       }
+               } else {
+                       infile = argv[0];
+                       if (freopen(infile, "r", stdin) == NULL) {
+                               perror(infile);
+                               exit(1);
+                       }
                }
                }
+               argv++;
        }
        hf = fopen("hosts", "w");
        if (hf == NULL) {
        }
        hf = fopen("hosts", "w");
        if (hf == NULL) {
@@ -50,14 +89,63 @@ main(argc, argv)
                perror("gateways");
                exit(1);
        }
                perror("gateways");
                exit(1);
        }
-       copylocal(gf, "localgateways");
+       copygateways(gf, "localgateways");
        nf = fopen("networks", "w");
        if (nf == NULL) {
                perror("networks");
                exit(1);
        }
        copylocal(nf, "localnetworks");
        nf = fopen("networks", "w");
        if (nf == NULL) {
                perror("networks");
                exit(1);
        }
        copylocal(nf, "localnetworks");
-       exit(yyparse());
+       copycomments(stdin, hf, DATELINES);
+       errs = yyparse();
+       dogateways();
+       exit(errs);
+}
+
+usage()
+{
+       fprintf(stderr,
+       "usage: %s [ -c connected-nets ] [-l local-nets ] [ input-file ]\n",
+               myname);
+       exit(1);
+}
+
+/*
+ *  Turn a comma-separated list of network names or numbers in dot notation
+ *  (e.g.  "arpanet, 128.32") into an array of net numbers.
+ */
+addlocal(arg, nets)
+       char *arg;
+       int *nets;
+{
+       register char *p, c;
+       register int nfound = 0;
+
+       do {
+               p = arg;
+               while (*p && *p != ',' && !isspace(*p))
+                       p++;
+               c = *p;
+               *p = 0;
+               while (*arg && isspace(*arg))
+                       arg++;
+               if (*arg == 0)
+                       continue;
+               if (nfound == MAXNETS) {
+                       fprintf(stderr, "%s: Too many networks in list\n",
+                               myname);
+                       return (nfound);
+               }
+               if (getnetaddr(arg, &nets[nfound]))
+                       nfound++;
+               else {
+                       fprintf(stderr, "%s: %s: unknown network\n",
+                               myname, arg);
+                       exit(1);
+               }
+               arg = p + 1;
+       } while (c);
+       return (nfound);
 }
 
 struct name *
 }
 
 struct name *
@@ -84,6 +172,8 @@ lower(str)
        while (*cp) {
                if (isupper(*cp))
                        *cp = tolower(*cp);
        while (*cp) {
                if (isupper(*cp))
                        *cp = tolower(*cp);
+               if (*cp == '.')
+                       break;
                cp++;
        }
        return (str);
                cp++;
        }
        return (str);
@@ -96,8 +186,8 @@ do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
 {
        register struct addr *al, *al2;
        register struct name *nl;
 {
        register struct addr *al, *al2;
        register struct name *nl;
-       struct addr *inetal;
-       int count;
+       struct addr *connect_addr;
+       char *cp;
 
        switch (keyword) {
 
 
        switch (keyword) {
 
@@ -105,7 +195,7 @@ do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
                nl = namelist;
                if (nl == NONAME) {
                        fprintf(stderr, "htable: net");
                nl = namelist;
                if (nl == NONAME) {
                        fprintf(stderr, "htable: net");
-                       putnet(stderr, addrlist->addr_val);
+                       putnet(stderr, inet_netof(addrlist->addr_val));
                        fprintf(stderr, " missing names.\n");
                        break;
                }
                        fprintf(stderr, " missing names.\n");
                        break;
                }
@@ -114,7 +204,7 @@ do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
                while (al = al2) {
                        char *cp;
 
                while (al = al2) {
                        char *cp;
 
-                       putnet(nf, al->addr_val);
+                       putnet(nf, inet_netof(al->addr_val));
                        cp = "\t%s";
                        while (nl = nl->name_link) {
                                fprintf(nf, cp, lower(nl->name_val));
                        cp = "\t%s";
                        while (nl = nl->name_link) {
                                fprintf(nf, cp, lower(nl->name_val));
@@ -124,55 +214,66 @@ do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
                        al2 = al->addr_link;
                        free((char *)al);
                }
                        al2 = al->addr_link;
                        free((char *)al);
                }
-               goto alreadyfree;
+               break;
 
        case KW_GATEWAY:
 
        case KW_GATEWAY:
-               /*
-                * Kludge here: take only gateways directly connected to
-                * the Internet.  Should really calculate closure on
-                * connectivity matrix to identify gateways to all networks
-                * described in data base, but that's real work.
-                */
-               /* locate Internet address, if one */
+               /* locate locally connected address, if one */
                for (al = addrlist; al; al = al->addr_link)
                for (al = addrlist; al; al = al->addr_link)
-                       if (inet_netof(al->addr_val) == INTERNET)
+                       if (connectedto(inet_netof(al->addr_val)))
                                break;
                                break;
-               if (al == NULL)
-                       break;
-               inetal = al;
-               for (count = 0, al = al->addr_link; al; al = al->addr_link) {
+               if (al == NULL) {
+                       /*
+                        * Not connected to known networks.  Save for later.
+                        */
+                       struct gateway *gw, *firstgw = (struct gateway *) NULL;
+
+                       for (al = addrlist; al; al = al->addr_link) {
+                               register int net;
+
+                               net = inet_netof(al->addr_val);
+                               gw = savegateway(namelist, net,
+                                   al->addr_val, 0);
+                               if (firstgw == (struct gateway *) NULL)
+                                       firstgw = gw;
+                               gw->g_firstent = firstgw;
+                       }
+                       freeaddrs(addrlist);
+                       goto dontfree;
+               }
+               /*
+                * Connected to a known network.
+                * Mark this as the gateway to all other networks
+                * that are on the addrlist (unless we already have
+                * gateways to them).
+                */
+               connect_addr = al;
+               for (al = addrlist; al; al = al->addr_link) {
                        register int net;
                        register int net;
-                       register struct netent *np;
 
 
-                       if (al == inetal)
-                               continue;
                        /* suppress duplicates -- not optimal */
                        net = inet_netof(al->addr_val);
                        /* suppress duplicates -- not optimal */
                        net = inet_netof(al->addr_val);
-                       if (checkgateway(net))
-                               break;
-                       count++;
-                       fprintf(gf, "net ");
-                       np = getnetbyaddr(net, AF_INET);
-                       if (np)
-                               fprintf(gf, "%s", np->n_name);
-                       else
-                               putnet(gf, net);
-                       /* this is a kludge */
-                       fprintf(gf, " gateway %s metric 1 passive\n",
-                               lower(namelist->name_val));
-                       savegateway(net);
+                       if (connectedto(net) || gatewayto(net))
+                               continue;
+                       printgateway(net, namelist->name_val, 1);
+                       (void) savegateway(namelist, net, al->addr_val, 1);
                }
                }
-               if (count > 0) {
-                       putaddr(hf, inetal->addr_val);
-                       fprintf(hf, "%s\t# gateway\n",
-                               lower(namelist->name_val));
+               /*
+                * Put the gateway in the hosts file.
+                */
+               putaddr(hf, connect_addr->addr_val);
+               cp = "%s";
+               for (nl = namelist; nl; nl = nl->name_link) {
+                       fprintf(hf, cp, lower(nl->name_val));
+                       cp = " %s";
                }
                }
-               break;
+               fprintf(hf, "\t# gateway\n");
+               freeaddrs(addrlist);
+               goto dontfree;
 
        case KW_HOST:
                al2 = addrlist;
                while (al = al2) {
 
        case KW_HOST:
                al2 = addrlist;
                while (al = al2) {
-                       if (inet_netof(al->addr_val) != LOCALNET) {
+                       if (!local(inet_netof(al->addr_val))) {
                                char *cp;
 
                                putaddr(hf, al->addr_val);
                                char *cp;
 
                                putaddr(hf, al->addr_val);
@@ -186,19 +287,33 @@ do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
                        al2 = al->addr_link;
                        free((char *)al);
                }
                        al2 = al->addr_link;
                        free((char *)al);
                }
-               goto alreadyfree;
+               break;
 
        default:
                fprintf(stderr, "Unknown keyword: %d.\n", keyword);
        }
 
        default:
                fprintf(stderr, "Unknown keyword: %d.\n", keyword);
        }
-       al2 = addrlist;
-       while (al = al2)
-               al2 = al->addr_link, free((char *)al);
-alreadyfree:
        freenames(namelist);
        freenames(namelist);
+dontfree:
        freenames(protos);
 }
 
        freenames(protos);
 }
 
+printgateway(net, name, metric)
+       int net;
+       char *name;
+       int metric;
+{
+       struct netent *np;
+
+       fprintf(gf, "net ");
+       np = getnetbyaddr(net, AF_INET);
+       if (np)
+               fprintf(gf, "%s", np->n_name);
+       else
+               putnet(gf, net);
+       fprintf(gf, " gateway %s metric %d passive\n",
+               lower(name), metric);
+}
+
 copylocal(f, filename)
        FILE *f;
        char *filename;
 copylocal(f, filename)
        FILE *f;
        char *filename;
@@ -222,20 +337,118 @@ copylocal(f, filename)
        fclose(lhf);
 }
 
        fclose(lhf);
 }
 
+copygateways(f, filename)
+       FILE *f;
+       char *filename;
+{
+       register FILE *lhf;
+       struct name *nl;
+       char type[80];
+       char dname[80];
+       char gname[80];
+       char junk[80];
+       char buf[500];
+       u_long addr;
+       int net, metric;
+       extern int errno;
+
+       lhf = fopen(filename, "r");
+       if (lhf == NULL) {
+               if (errno != ENOENT) {
+                       perror(filename);
+                       exit(1);
+               }
+               fprintf(stderr, "Warning, no %s file.\n", filename);
+               return;
+       }
+       /* format: {net | host} XX gateway XX metric DD [passive]\n */
+       for (;;) {
+               junk[0] = 0;
+               if (fgets(buf, sizeof(buf), lhf) == (char *)NULL)
+                       break;
+               fputs(buf, gf);
+               if (buf[0] == '#' ||
+                   sscanf(buf, "%s %s gateway %s metric %d %s",
+                   type, dname, gname, &metric, junk) < 5)
+                       continue;
+               if (strcmp(type, "net"))
+                       continue;
+               if (!getnetaddr(dname, &net))
+                       continue;
+               if (!gethostaddr(gname, &addr))
+                       continue;
+               nl = newname(gname);
+               (void) savegateway(nl, net, addr, metric);
+       }
+       fclose(lhf);
+}
+
+getnetaddr(name, addr)
+       char *name;
+       int *addr;
+{
+       struct netent *np = getnetbyname(name);
+       int n;
+
+       if (np == 0) {
+               *addr = inet_network(name);
+               return (*addr != -1);
+       } else {
+               if (np->n_addrtype != AF_INET)
+                       return (0);
+               *addr = np->n_net;
+               return (1);
+       }
+}
+
+gethostaddr(name, addr)
+       char *name;
+       u_long *addr;
+{
+       struct hostent *hp;
+
+       hp = gethostbyname(name);
+       if (hp) {
+               *addr = *(u_long *)(hp->h_addr);
+               return (1);
+       }
+       *addr = inet_addr(name);
+       return (*addr != -1);
+}
+
+copycomments(in, out, ccount)
+       FILE *in, *out;
+       int ccount;
+{
+       char buf[BUFSIZ];
+       int length;
+       int count;
+       char *fgets();
+
+       for (count=0; count < ccount; count++) {
+               if ((fgets(buf, sizeof(buf), in) == NULL) || (buf[0] != ';'))
+                       return;
+               buf[0] = '#';
+               fputs(buf, out);
+       }
+       return;
+}
 #define        UC(b)   (((int)(b))&0xff)
 
 #define        UC(b)   (((int)(b))&0xff)
 
+/*
+ * Print network number in internet-standard dot notation;
+ * v is in host byte order.
+ */
 putnet(f, v)
        FILE *f;
 putnet(f, v)
        FILE *f;
-       u_long v;
+       register int v;
 {
 {
-       register char *a = (char *)&v;
-
-       if (UC(a[0]&0x80) == 0)
-               fprintf(f, "%d", UC(a[0]));
-       else if ((UC(a[0])&0x40) == 0)
-               fprintf(f, "%d.%d", UC(a[0]), UC(a[1]));
+       if (v < 128)
+               fprintf(f, "%d", v);
+       else if (v < 65536)
+               fprintf(f, "%d.%d", UC(v >> 8), UC(v));
        else
        else
-               fprintf(f, "%d.%d.%d", UC(a[0]), UC(a[1]), UC(a[2]));
+               fprintf(f, "%d.%d.%d", UC(v >> 16), UC(v >> 8), UC(v));
 }
 
 putaddr(f, v)
 }
 
 putaddr(f, v)
@@ -261,26 +474,37 @@ freenames(list)
                free((char *)nl);
        }
 }
                free((char *)nl);
        }
 }
-struct gateway {
-       struct  gateway *g_link;
-       int     g_net;
-};
+
+freeaddrs(list)
+       struct addr *list;
+{
+       register struct addr *al, *al2;
+
+       al2 = list;
+       while (al = al2)
+               al2 = al->addr_link, free((char *)al);
+}
 
 struct gateway *gateways = 0;
 
 struct gateway *gateways = 0;
+struct gateway *lastgateway = 0;
 
 
-checkgateway(net)
+struct gateway *
+gatewayto(net)
        register int net;
 {
        register struct gateway *gp;
 
        for (gp = gateways; gp; gp = gp->g_link)
        register int net;
 {
        register struct gateway *gp;
 
        for (gp = gateways; gp; gp = gp->g_link)
-               if (gp->g_net == net)
-                       return (1);
-       return (0);
+               if ((gp->g_net == net) && (gp->g_metric > 0))
+                       return (gp);
+       return ((struct gateway *) NULL);
 }
 
 }
 
-savegateway(net)
-       int net;
+struct gateway *
+savegateway(namelist, net, addr, metric)
+       struct name *namelist;
+       u_long addr;
+       int net, metric;
 {
        register struct gateway *gp;
 
 {
        register struct gateway *gp;
 
@@ -289,8 +513,89 @@ savegateway(net)
                fprintf(stderr, "htable: out of memory\n");
                exit(1);
        }
                fprintf(stderr, "htable: out of memory\n");
                exit(1);
        }
-       gp->g_link = gateways;
+       gp->g_link = (struct gateway *) NULL;
+       if (lastgateway)
+               lastgateway->g_link = gp;
+       else
+               gateways = gp;
+       lastgateway = gp;
+       gp->g_name = namelist;
        gp->g_net = net;
        gp->g_net = net;
-       gateways = gp;
+       gp->g_addr = addr;
+       gp->g_metric = metric;
+       if (metric == 1)
+               gp->g_dst = gp;
+       return (gp);
+}
+
+connectedto(net)
+       u_long net;
+{
+       register i;
+
+       for (i = 0; i < nconnected; i++)
+               if (connected_nets[i] == net)
+                       return(1);
+       return(0);
+}
+
+local(net)
+       u_long net;
+{
+       register i;
+
+       for (i = 0; i < nlocal; i++)
+               if (local_nets[i] == net)
+                       return(1);
+       return(0);
+}
+
+#define        MAXHOPS 10
+
+/*
+ * Go through list of gateways, finding connections for gateways
+ * that are not yet connected.
+ */
+dogateways()
+{
+       register struct gateway *gp, *gw, *ggp;
+       register int hops, changed = 1;
+       struct name *nl;
+       char *cp;
+
+       for (hops = 0; hops < MAXHOPS && changed; hops++, changed = 0) {
+           for (gp = gateways; gp; gp = gp->g_link)
+               if ((gp->g_metric == 0) && (gw = gatewayto(gp->g_net))) {
+                   /*
+                    * Found a new connection.
+                    * For each other network that this gateway is on,
+                    * add a new gateway to that network.
+                    */
+                   changed = 1;
+                   gp->g_dst = gw->g_dst;
+                   gp->g_metric = gw->g_metric + 1;
+                   for (ggp = gp->g_firstent; ggp->g_name == gp->g_name;
+                       ggp = ggp->g_link) {
+                           if (ggp == gp)
+                               continue;
+                           if (gatewayto(ggp->g_net))
+                               continue;
+                           ggp->g_dst = gp->g_dst;
+                           ggp->g_metric = gp->g_metric;
+                           printgateway(ggp->g_net,
+                                   gw->g_dst->g_name->name_val, gp->g_metric);
+                   }
+                   /*
+                    * Put the gateway in the hosts file,
+                    * using the address for the connected net.
+                    */
+                   putaddr(hf, gp->g_addr);
+                   cp = "%s";
+                   for (nl = gp->g_name; nl; nl = nl->name_link) {
+                           fprintf(hf, cp, lower(nl->name_val));
+                           cp = " %s";
+                   }
+                   fprintf(hf, "\t# gateway\n");
+               }
+       }
 }
 }
-