campbell@maynard.BSW.COM (Larry Campbell) (12/15/86)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # addlink.c # addnode.c # extern.c # local.c # main.c # mapit.c # mapaux.c # mem.c # putnode.c # parse.y # makedb.c # This archive created: Sun Dec 14 23:58:29 1986 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'addlink.c' then echo shar: "will not over-write existing file 'addlink.c'" else cat << \SHAR_EOF > 'addlink.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)addlink.c 8.1 (down!honey) 86/01/19"; #endif lint #include "def.h" static long Trace[NTRACE]; static int Tracecount; int addlink(ofrom, oto, cost, netchar, netdir) int ofrom; register int oto; Cost cost; char netchar; char netdir; { register link *l, *ltmp; node *ntmp; node *from; int prev = 0; /* if (Tflag) ltrace(from, to, cost, netchar, netdir); */ /* maintain uniqueness for dead links (only) */ from = getnode(ofrom); freenode(from); for (l = getlink(from->n_link); l->l_offset && l->l_flag & LDEAD; l = getlink(l->l_next)) { if (oto == l->l_to) { /* what the hell, use cheaper cost */ if (cost < l->l_cost) { l->l_cost = cost; netbits(l, netchar, netdir); } putlink(l); return(l->l_offset); } prev = l->l_offset; freelink(l); } freelink(l); /* allocate and link in the new link struct */ l = newlink(); if (cost != INF) /* ignore back links */ Lcount++; if (prev) { ltmp = getlink(prev); l->l_next = ltmp->l_next; ltmp->l_next = l->l_offset; putlink(ltmp); } else { ntmp = getnode(ofrom); l->l_next = ntmp->n_link; ntmp->n_link = l->l_offset; putnode(ntmp); } l->l_to = oto; l->l_cost = cost; if (netchar == 0) { netchar = DEFNET; netdir = DEFDIR; } netbits(l, netchar, netdir); putlink(l); return(l->l_offset); } int addgateway(ofrom, oto, cost, netchar, netdir) int ofrom; int oto; Cost cost; char netchar; char netdir; { register link *l; l = getlink(addlink(ofrom, oto, cost, netchar, netdir)); l->l_flag |= LGATEWAY; putlink(l); return(l->l_offset); } deadlink(s) char *s; { char *t, c; link *l; node *n; t = index(s, '!'); if (t) { c = *t; *t = 0; l = getlink(addlink(addnode(s), addnode(t + 1), INF / 2, c, DEFDIR)); l->l_flag |= LDEAD; putlink(l); } else n = getnode(addnode(s)); n->n_flag |= NDEAD; putnode(n); } netbits(l, netchar, netdir) link *l; char netchar, netdir; { char *nptr; if ((nptr = index(Netchars, netchar)) == 0) { fprintf(stderr, "%s: unknown network operator: %c\n", ProgName, netchar); badmagic(1); } l->l_flag &= ~(LNETCHARS|LDIR); l->l_flag |= (nptr - Netchars) | dirbits(netdir); } #ifdef FORGET_IT tracelink(arg) char *arg; { char *bang; link *l; if (Tracecount >= NTRACE) return(-1); l = newlink(); bang = index(arg, '!'); if (bang) { *bang = 0; l->l_to = addnode(bang+1); } else l->l_to = 0; l->l_from = (link *) addnode(arg); Trace[Tracecount++] = l; return(0); } #endif #ifdef FORGET_IT STATIC ltrace(from, to, cost, netchar, netdir) node *from, *to; Cost cost; char netchar; char netdir; { link *l; int i; for (i = 0; i < Tracecount; i++) { l = Trace[i]; /* overkill -- you asked for it! */ if ((l->l_to == 0 && (from == (node *) l->l_from || to == (node *) l->l_from)) || (from == (node *) l->l_from && to == l->l_to) || (to == (node *) l->l_from && from == l->l_to)) { ltrprint(from, to, cost, netchar, netdir); return; } } } #endif #ifdef FORGET_IT /* print a trace item */ STATIC ltrprint(from, to, cost, netchar, netdir) node *from, *to; Cost cost; char netchar; char netdir; { char buf[256], *bptr = buf; strcpy(bptr, from->n_name); bptr += strlen(bptr); *bptr++ = ' '; if (netdir == LRIGHT) /* @% */ *bptr++ = netchar; strcpy(bptr, to->n_name); bptr += strlen(bptr); if (netdir == LLEFT) /* !: */ *bptr++ = netchar; sprintf(bptr, "(%ld)", cost); yyerror(buf); } #endif #ifdef FORGET_IT atrace(n1, n2) node *n1, *n2; { link *l; int i; char buf[256]; for (i = 0; i < Tracecount; i++) { l = Trace[i]; if (l->l_to == 0 && ((node *) l->l_from == n1 || (node *) l->l_from == n2)) { sprintf(buf, "%s = %s", n1->n_name, n2->n_name); yyerror(buf); return; } } } #endif SHAR_EOF fi if test -f 'addnode.c' then echo shar: "will not over-write existing file 'addnode.c'" else cat << \SHAR_EOF > 'addnode.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)addnode.c 8.1 (down!honey) 86/01/19"; #endif #include "def.h" extern void lowercase(), rehash(); extern int isprivate(); extern long hash(); extern nodecount, linkcount; /* * these numbers are chosen because: * -> they are prime, * -> they are monotonic increasing, * -> each is a tad smaller than a multiple of 1024, * -> they form a fibonacci sequence (almost). * the first point yields good hash functions, the second is used for the * standard re-hashing implementation of open addressing, the third * optimizes for quirks in some mallocs i have seen, and the fourth simply * appeals to me. */ static int Primes[] = { /* #ifndef SQUANDER 1021, 2039, 3067, 5113, 8179, #endif 13309, 21499, 0 */ 21499, 0 }; static int Tabindex = -1; static int Collision; /* mark host name collisions in hash() */ int addnode(name) register char *name; { register i; register node *n; if (Iflag) lowercase(name); /* is it a private host? */ i = isprivate(name); if (i) return(i); i = hash(name, 0); if (Table[i]) return(Table[i]); n = newnode(); if (strlen(name) >= MAXNAME) { fprintf(stderr, "Name too long: %s\n", name); badmagic(1); } strcpy(n->n_name, name); Table[i] = n->n_offset; n->n_tloc = i; /* essentially a back link to the table */ if (Collision) n->n_flag |= COLLISION; /* name collision with private host */ putnode(n); return(n->n_offset); } alias(n1, n2) int n1, n2; { link *l; extern int addlink(); l = getlink(addlink(n1, n2, (Cost) 0, DEFNET, DEFDIR)); l->l_flag |= LALIAS; putlink(l); l = getlink(addlink(n2, n1, (Cost) 0, DEFNET, DEFDIR)); l->l_flag |= LALIAS; putlink(l); /* if (Tflag) atrace(n1, n2); */ } /* * fold a string into a long int. this algorithm ignores all but the last * eight bytes, which affects < 15% of all host names, many of which have * common prefixes anyway. */ STATIC long fold(str) register char *str; { register long sum; sum = *str++; while (*str) { sum <<= 4; sum += *str++; } if (sum < 0) sum = -sum; return(sum); } #define HASH1(n) ((n) % Tabsize); #define HASH2(n) (Tabsize - 2 - ((n) % (Tabsize-2))) /* princeton!rs */ /* * with a 0.75 high water mark, probes per access should be 1.84. * use long constant to force promotion. */ #define HIGHWATER 75L #define isfull(n, size) ((n) > ((size) * HIGHWATER) / 100) STATIC long hash(name, unique) char *name; { register long probe, hash2; register node *n; if (Tabindex < 0) { /* first time */ Tabindex = 0; Tabsize = Primes[0]; Table = newtable(Tabsize); } else if (isfull(Ncount, Tabsize)) rehash(); /* more, more! */ probe = fold(name); /* don't change the order of the next two lines */ hash2 = HASH2(probe); probe = HASH1(probe); /* thank you! */ /* * probe the hash table. * if unique is set, we require a fresh slot. * otherwise, use double hashing to find either * (1) an empty slot, or * (2) a non-private copy of this host name * * as a side effect, if we notice a collision with a private host * we mark the other so that it is skipped at output time. */ Collision = 0; while (Table[probe] != 0) { n = getnode(Table[probe]); if (strcmp(n->n_name, name) == 0) { if (unique) { n->n_flag |= COLLISION; putnode(n); } else if (n->n_flag & ISPRIVATE) { freenode(n); Collision++; } else { putnode(n); break; /* this is it! */ } } else freenode(n); probe -= hash2; if (probe < 0) probe += Tabsize; } return(probe); } STATIC void rehash() { register int *otable, *optr; node *n; register long probe; #ifdef DEBUG hashanalyze(); #endif optr = Table + Tabsize - 1; /* ptr to last */ otable = Table; Tabsize = Primes[++Tabindex]; if (Tabsize == 0) { /* need more prime numbers */ fprintf(stderr, "%s: > %d hosts\n", ProgName, Primes[Tabindex-1]); badmagic(1); } Table = newtable(Tabsize); do { if (*optr == 0) continue; /* empty slot in old table */ n = getnode(*optr); probe = hash(n->n_name, n->n_flag & ISPRIVATE); if (Table[probe] != 0) { fprintf(stderr, "%s: rehash error\n", ProgName); badmagic(1); } Table[probe] = *optr; regetnode(n); n->n_tloc = probe; putnode(n); } while (optr-- > otable); freetable(otable); } hashanalyze() { #ifdef FORGET_IT long probe, hash2; int count, i, collision[8]; int longest = 0, total = 0, slots = 0; int nslots = sizeof(collision)/sizeof(collision[0]); if (!Vflag) return; strclear((char *) collision, sizeof(collision)); for (i = 0; i < Tabsize; i++) { if (Table[i] == 0) continue; /* private hosts too hard to account for ... */ if (Table[i]->n_flag & ISPRIVATE) continue; count = 1; probe = fold(Table[i]->n_name); /* don't change the order of the next two lines */ hash2 = HASH2(probe); probe = HASH1(probe); /* thank you! */ while (Table[probe] != 0 && strcmp(Table[probe]->n_name, Table[i]->n_name) != 0) { count++; probe -= hash2; if (probe < 0) probe += Tabsize; } if (Table[probe] == 0) { fprintf(stderr, "%s: impossible hash error for %s\n", ProgName, Table[i]->n_name); badmagic(1); } total += count; slots++; if (count > longest) longest = count; if (count >= nslots) count = 0; collision[count]++; } for (i = 1; i < nslots; i++) if (collision[i]) fprintf(stderr, "%d chains: %d (%ld%%)\n", i, collision[i], (collision[i] * 100L)/ slots); if (collision[0]) fprintf(stderr, "> %d chains: %d (%ld%%)\n", nslots - 1, collision[0], (collision[0] * 100L)/ slots); fprintf(stderr, "%2.2f probes per access, longest chain: %d\n", (double) total / slots, longest); #endif } STATIC void lowercase(s) register char *s; { do { if (isupper(*s)) *s -= 'A' - 'a'; /* assumes ASCII */ } while (*s++); } /* * this might have to be recoded for performance if privates catch on */ STATIC int isprivate(name) register char *name; { register node *n; for (n = getnode(Private); n->n_offset != 0; n = getnode(n->n_private)) { if (strcmp(name, n->n_name) == 0) { freenode(n); return(n->n_offset); } freenode(n); } freenode(n); return(0); } fixprivate() { node *n, *next; register int i; for (n = getnode(Private); n->n_offset != 0; n = next) { n->n_flag |= ISPRIVATE; /* overkill, but safe */ putnode(n); n = getnode(n->n_offset); i = hash(n->n_name, 1); regetnode(n); if (Table[i] != 0) { fprintf(stderr, "%s: impossible private node error on %s\n", ProgName, n->n_name); badmagic(1); } Table[i] = n->n_offset; n->n_tloc = i; /* essentially a back link to the table */ next = getnode(n->n_private); n->n_private = 0; /* clear for later use */ putnode(n); } freenode(n); Private = 0; } int addprivate(name) register char *name; { register node *n; if (Iflag) lowercase(name); n = getnode(isprivate(name)); freenode(n); if (n->n_offset != 0) return(n->n_offset); n = newnode(); if (strlen(name) >= MAXNAME) { fprintf(stderr, "Name too long: %s\n", name); badmagic(1); } strcpy(n->n_name, name); n->n_private = Private; Private = n->n_offset; putnode(n); return(n->n_offset); } SHAR_EOF fi if test -f 'extern.c' then echo shar: "will not over-write existing file 'extern.c'" else cat << \SHAR_EOF > 'extern.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)extern.c 8.1 (down!honey) 86/01/19"; #endif lint #include "def.h" int Home; char *Cfile; char **Ifiles; char *ProgName; int fdnode, fdlink; /* File descriptors for temporary files */ int nodecount, linkcount; int Vflag; int Cflag; int Iflag; int Tflag; int Lineno = 1; char *Netchars = "!:@%"; /* sparse, but sufficient */ int Ncount; int Lcount; char *Graphout; char *Linkout; int *Table; /* hash table + priority queue */ long Tabsize; /* size of Table */ int Private; /* list of private nodes in this file */ long Hashpart; /* used while mapping -- above is heap */ int Scanstate = NEWLINE; /* scanner (yylex) state */ SHAR_EOF fi if test -f 'local.c' then echo shar: "will not over-write existing file 'local.c'" else cat << \SHAR_EOF > 'local.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)local.c 8.1 (down!honey) 86/01/19"; #endif lint #include <stdio.h> #include "config.h" #ifdef UNAME #include <sys/utsname.h> char * local() { static struct utsname utsname; uname(&utsname); return(utsname.nodename); } #else !UNAME char * local() { static char lname[64]; void gethostname(); gethostname(lname, sizeof(lname)); return(lname); } #ifndef GETHOSTNAME static void gethostname(name, len) char *name; { FILE *whoami, *fopen(), *popen(); char *ptr, *index(); *name = '\0'; /* try /etc/whoami */ if ((whoami = fopen("/etc/whoami", "r")) != 0) { (void) fgets(name, len, whoami); (void) fclose(whoami); if ((ptr = index(name, '\n')) != 0) *ptr = '\0'; } if (*name) return; /* try /usr/include/whoami.h */ if ((whoami = fopen("/usr/include/whoami.h", "r")) != 0) { while (!feof(whoami)) { char buf[100]; if (fgets(buf, 100, whoami) == 0) break; if (sscanf(buf, "#define sysname \"%[^\"]\"", name)) break; } (void) fclose(whoami); if (*name) return; } /* ask uucp */ if ((whoami = popen("uuname -l", "r")) != 0) { (void) fgets(name, len, whoami); (void) pclose(whoami); if ((ptr = index(name, '\n')) != 0) *ptr = '\0'; } if (*name) return; /* aw hell, i give up! is this a real unix? */ return; } #endif GETHOSTNAME #endif UNAME SHAR_EOF fi if test -f 'main.c' then echo shar: "will not over-write existing file 'main.c'" else cat << \SHAR_EOF > 'main.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)main.c 8.1 (down!honey) 86/01/19"; #endif #define MAIN /* for sccsid in header files */ #include "def.h" #define USAGE "usage: %s [-vci] [-l localname] [-d deadlink] [-t tracelink] [-g file] [-s file]\n" extern nodecount, linkcount; main(argc, argv) int argc; char *argv[]; { node *Homenode; char *locname = 0; int c, errflg = 0; int pstat; ProgName = argv[0]; (void) allocation(); /* initialize data space monitoring */ Cfile = "[deadlinks]"; /* for tracing dead links */ meminit(); while ((c = getopt(argc, argv, "cd:g:il:s:t:v")) != EOF) switch(c) { case 'c': /* print cost info */ Cflag++; break; case 'd': /* dead host or link */ deadlink(optarg); break; case 'g': /* graph output file */ Graphout = optarg; break; case 'i': /* ignore case */ Iflag++; break; case 'l': /* local name */ locname = optarg; break; case 's': /* show shortest path tree */ Linkout = optarg; break; /* case 't': /* trace this link */ /* if (tracelink(optarg) < 0) { fprintf(stderr, "%s: can trace only %d links\n", ProgName, NTRACE); exit(1); } Tflag = 1; break; */ case 'v': /* verbose stderr, mixed blessing */ Vflag++; break; default: errflg++; } if (errflg) { fprintf(stderr, USAGE, ProgName); exit(1); } argv += optind; /* kludge for yywrap() */ if (*argv) { Ifiles = argv; freopen("/dev/null", "r", stdin); } if (!locname) locname = local(); if (*locname == 0) { locname = "lostinspace"; fprintf(stderr, "%s: using \"%s\" for local name\n", ProgName, locname); } Home = addnode(locname); /* add home node */ Homenode = getnode(Home); Homenode->n_cost = 0; /* doesn't cost to get here */ putnode(Homenode); yyparse(); /* read in link info */ vprintf(stderr, "yyparse ends with %d, %d\n", nodecount, linkcount); if (Vflag > 1) hashanalyze(); vprintf(stderr, "%d vertices, %d edges\n", Ncount, Lcount); vprintf(stderr, "allocation is %uk after parsing\n", allocation()); vprintf(stderr, "hashanalyze ends with %d, %d\n", nodecount, linkcount); Cfile = "[backlinks]"; /* for tracing back links */ Lineno = 0; mapit(); /* compute shortest path tree */ vprintf(stderr, " mapit ends with %d, %d\n", nodecount, linkcount); vprintf(stderr, "allocation is %uk after mapping\n", allocation()); /* traverse tree and print paths */ if (Cflag) pstat = system(PRINTITC); else pstat = system(PRINTIT); vprintf(stderr, "printit ends with status %d\n", pstat); #ifndef DEBUG unlink(NTEMPFILE); unlink(LTEMPFILE); #endif exit(0); } SHAR_EOF fi if test -f 'mapit.c' then echo shar: "will not over-write existing file 'mapit.c'" else cat << \SHAR_EOF > 'mapit.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)mapit.c 8.1 (down!honey) 86/01/19"; #endif #include "def.h" /* privates */ extern void reheap(), insert(), heapswap(); extern int min_node(), rmlink(); extern Cost costof(); extern int nodecount, linkcount; static int Nheap; static long Heaphighwater; static int *Heap; /* transform the graph to a shortest-path tree by marking tree edges */ mapit() { register node *n, *next; register link *l; int olnext; int ol; int next_offset, olprev; Cost cost; /* * re-use the hash table space for the heap. */ Heap = (int *) Table; pack(); /* remove holes in the Table */ if (Linkout && *Linkout) /* dump cheapest links */ showlinks(); if (Graphout && *Graphout) /* dump the edge list */ dumpgraph(); /* invent and insert a link for Home to get things started */ l = newlink(); l->l_to = Home; (void) dehash(Home); putlink(l); insert(l->l_offset); /* main mapping loop */ remap: Heaphighwater = Nheap; while ((ol = min_node()) != 0) { l = tmpgetlink(ol); l->l_flag |= LTREE; n = getnode(l->l_to); n->n_flag |= MAPPED; putnode(n); putlink(l); n = tmpgetnode(l->l_to); /* add children to heap */ olprev = 0; for (l = tmpgetlink(n->n_link); l->l_offset != 0; l = tmpgetlink(olnext)) { next_offset = l->l_to; next = getnode(l->l_to); /* neighboring node */ if (next->n_flag & MAPPED) { olnext = rmlink(l->l_offset, olprev, n->n_offset); freenode(next); continue; } freenode(next); cost = costof(n->n_offset, l->l_offset); if (skiplink(l->l_offset, n->n_offset, cost)) { olnext = rmlink(l->l_offset, olprev, n->n_offset); continue; } /* * put this link in the heap, in a place where it may * percolate up, but not down. if new, or if cost is * being increased, move to end. otherwise, cost is * same or less, so leave it where it is. unfortunately, * freeing a link already in the heap is too costly at * this point. * * TODO: avoid heaping aliases and network members. */ next = getnode(next_offset); if (dehash(next_offset) == 0) { /* first time in heap */ insert(l->l_offset); /* insert at end */ regetnode(next); } else { regetnode(next); /* replace heaped link by this one */ if (cost > next->n_cost) { /* gateway */ /* move old link to end of heap */ heapswap((int) next->n_tloc, Nheap); regetnode(next); next->n_tloc = Nheap; } Heap[next->n_tloc] = l->l_offset; } next->n_cost = cost; next->n_parent = n->n_offset; putnode(next); reheap(l->l_offset); /* restore heap property */ /* * note whether we got here via a gatewayed net. * domains are presumed to require gateways. * aliases inherit parent's gateway status. */ next = getnode(next_offset); next->n_flag &= ~GATEWAYIN; n = tmpgetnode(n->n_offset); l = tmpgetlink(l->l_offset); if (l->l_flag & LALIAS) next->n_flag |= (n->n_flag & GATEWAYIN); else if (GATEWAYED(n)) next->n_flag |= GATEWAYIN; putnode(next); olprev = l->l_offset; /* this link's a keeper */ olnext = l->l_next; } } vprintf(stderr, "heap high water mark was %d\n", Heaphighwater); /* sanity check on implementation */ if (Nheap != 0) { fprintf(stderr, "%s: null entry found in heap\n", ProgName); badmagic(1); } if (Hashpart < Tabsize) { /* * add back links from unreachable hosts to reachable * neighbors, then remap. asymptotically, this is * quadratic. in practice, this is done exactly once. */ backlinks(); if (Nheap) goto remap; } if (Hashpart < Tabsize) { fputs("You can't get there from here:\n", stderr); for ( ; Hashpart < Tabsize; Hashpart++) { fprintf(stderr, "\t%s", tmpgetnode(Table[Hashpart])->n_name); if (tmpgetnode(Table[Hashpart])->n_flag & (ISPRIVATE|COLLISION)) fputs(" (private)", stderr); putc('\n', stderr); } } } /* * can this link be ignored? if yes, return 1, o.w. 0. * a link can be skipped if it is not in the shortest path tree. */ STATIC int skiplink(ol, oparent, cost) int ol; /* new link to this node */ int oparent; /* new parent of this node */ Cost cost; /* new cost to this node */ { link *l, *ltmp; node *parent; node *n; /* this node */ int lheap; /* existing link to this node */ l = getlink(ol); n = getnode(l->l_to); /* first time we've reached this node? */ if (n->n_tloc >= Hashpart) { freelink(l); freenode(n); return(0); } lheap = Heap[n->n_tloc]; ltmp = getlink(lheap); /* examine links to nets that require gateways */ if (GATEWAYED(n)) { /* if exactly one is a gateway, use it */ if ((ltmp->l_flag & LGATEWAY) && !(l->l_flag & LGATEWAY)) { freenode(n); freelink(l); freelink(ltmp); return(1); /* old is gateway */ } if (!(ltmp->l_flag & LGATEWAY) && (l->l_flag & LGATEWAY)) { freenode(n); freelink(l); freelink(ltmp); return(0); /* new is gateway */ } /* no gateway or both gateways; resolve in standard way ... */ } /* examine dup link (sanity check) */ parent = getnode(oparent); if (n->n_parent == oparent && ((ltmp->l_flag & LDEAD) || (l->l_flag & LDEAD))) { fprintf(stderr, "%s: dup dead link not eliminated: %s -> %s\n", ProgName, parent->n_name, n->n_name); badmagic(1); } freenode(parent); freelink(ltmp); /* examine cost */ if (cost < n->n_cost) { freenode(n); freelink(l); return(0); } if (cost > n->n_cost) { freenode(n); freelink(l); return(1); } /* all other things being equal, consult the oracle */ freelink(l); freenode(n); return(tiebreaker(n->n_offset, oparent)); } STATIC Cost costof(oprev, ol) register int oprev; register int ol; { link *l; node *prev; register node *next; register Cost cost; l = getlink(ol); next = getnode(l->l_to); prev = getnode(oprev); if (l->l_flag & LALIAS) { /* copy left/right bits */ next->n_flag &= ~(HASLEFT|HASRIGHT); next->n_flag |= (prev->n_flag & (HASLEFT|HASRIGHT)); putnode(next); freelink(l); freenode(prev); return(prev->n_cost); /* by definition */ } cost = prev->n_cost + l->l_cost; /* basic cost */ /* * heuristics: * charge for a dead link. * charge for getting out of a dead host. * charge for getting into a gatewayed net (except at a gateway). * discourage mixing of left and right syntax when next is a host. * charge for leaving a gatewayed net. * * life was simpler when pathalias computed true shortest paths. */ if (l->l_flag & LDEAD) /* dead link */ cost += INF/2; if (DEADHOST(prev)) /* dead host */ cost += INF/2; if (GATEWAYED(next) && !(l->l_flag & LGATEWAY)) /* not gateway */ cost += INF/2; if (!ISANET(next)) { /* charge for mixed syntax here */ if ((NETDIR(l) == LLEFT && (prev->n_flag & HASRIGHT)) || (NETDIR(l) == LRIGHT && (prev->n_flag & HASLEFT))) cost += DEFCOST; } /* * if reached by a gatewayed net, discourage further links. * this has some relevance to common carriers and the FCC ... * the penalty inheres to hosts, not aliases, nets, or domains. */ if ((prev->n_flag & GATEWAYIN) && !ISADOMAIN(prev) && !(prev->n_flag & NNET)) cost += INF/2; /* heavyweight, but appropriate */ /* set left/right bits */ next->n_flag &= ~(HASLEFT|HASRIGHT); if (NETDIR(l) == LLEFT || (prev->n_flag & HASLEFT)) next->n_flag |= HASLEFT; if (NETDIR(l) == LRIGHT || (prev->n_flag & HASRIGHT)) next->n_flag |= HASRIGHT; putnode(next); freenode(prev); freelink(l); return(cost); } STATIC int rmlink(ol, olprev, on) int ol, olprev; int on; { node *n; link *l, *lprev; l = getlink(ol); n = getnode(on); if (olprev) { lprev = getlink(olprev); lprev->l_next = l->l_next; putlink(lprev); freenode(n); } else { n->n_link = l->l_next; putnode(n); } freelink(l); return(l->l_next); } /* * binary heap implementation of priority queue. * TODO: make the heap smaller by giving inserting a placeholder * for net members when the net is extracted. this requires storing the * cost of a net in the net node itself -- yuck. is it worth it? */ STATIC void insert(ol) int ol; { link *l; register node *n; l = getlink(ol); n = getnode(l->l_to); Heap[n->n_tloc] = 0; if (Heap[Nheap+1] != 0) { fprintf(stderr, "%s: heap error in insert\n", ProgName); badmagic(1); } if (Nheap++ == 0) { Heap[1] = l->l_offset; n->n_tloc = 1; freelink(l); putnode(n); return; } if (Vflag && Nheap > Heaphighwater) Heaphighwater = Nheap; /* diagnostics */ /* insert at the end. caller must reheap(). */ Heap[Nheap] = l->l_offset; n->n_tloc = Nheap; freelink(l); putnode(n); } /* * replace existing link in heap by this one, then * "percolate" up the heap by exchanging with the parent */ STATIC void reheap(ol) int ol; { link *l, *ltmp; register int loc, parent; register Cost cost; register node *n, *np; l = getlink(ol); n = getnode(l->l_to); cost = n->n_cost; for (loc = n->n_tloc; loc > 1; loc = parent) { parent = loc / 2; /* sanity check on implementation */ if (Heap[parent] == 0) { fprintf(stderr, "%s: heap error in insert\n", ProgName); badmagic(1); } ltmp = getlink(Heap[parent]); np = getnode(ltmp->l_to); freelink(ltmp); if (cost > np->n_cost) { freenode(np); freenode(n); freelink(l); return; } /* move nets below hosts for output stability */ if (cost == np->n_cost && ((n->n_flag & NNET) || !(np->n_flag & NNET))) { freenode(np); freenode(n); freelink(l); return; } freenode(np); heapswap(loc, parent); regetlink(l); regetnode(n); } freenode(n); freelink(l); } /* extract min (== Heap[1]) from heap */ STATIC int min_node() { link *ltmp, *ltmp1; int orval; node *ntmp, *ntmp1; register int *regheap; register int i, child; if (Nheap == 0) return(0); regheap = Heap; /* in register -- heavily used */ orval = regheap[1]; /* return this one */ /* move last entry into root, percolate down */ regheap[1] = regheap[Nheap]; ltmp = getlink(regheap[1]); ntmp = getnode(ltmp->l_to); ntmp->n_tloc = 1; putnode(ntmp); freelink(ltmp); regheap[Nheap] = 0; if (--Nheap == 0) return(orval); i = 1; for (;;) { /* swap with smaller child down the tree */ child = i * 2; /* lhs child is 2i, rhs is 2i+1. */ if (child >= Nheap) return(orval); /* use rhs child if smaller than lhs child */ ltmp = getlink(regheap[child]); ntmp = getnode(ltmp->l_to); ltmp1 = getlink(regheap[child+1]); ntmp1 = getnode(ltmp1->l_to); if (ntmp->n_cost > ntmp1->n_cost || (ntmp->n_cost == ntmp1->n_cost && !ISANET(ntmp1))) child++; freenode(ntmp1); freelink(ltmp1); freenode(ntmp); freelink(ltmp); ltmp = getlink(regheap[child]); ntmp = getnode(ltmp->l_to); ltmp1 = getlink(regheap[i]); ntmp1 = getnode(ltmp1->l_to); if (ntmp1->n_cost < ntmp->n_cost) { freenode(ntmp1); freelink(ltmp1); freenode(ntmp); freelink(ltmp); return(orval); } /* move nets below hosts for output stability */ if (ntmp1->n_cost == ntmp->n_cost && (!ISANET(ntmp1) || ISANET(ntmp))) { freenode(ntmp1); freelink(ltmp1); freenode(ntmp); freelink(ltmp); return(orval); } freenode(ntmp1); freelink(ltmp1); freenode(ntmp); freelink(ltmp); heapswap(i, child); i = child; } /*NOTREACHED*/ } /* exchange Heap[i] and Heap[j] pointers */ STATIC void heapswap(i, j) int i, j; { register int temp; int *regheap; node *ntmp; link *ltmp; regheap = Heap; /* heavily used -- put in register */ temp = regheap[i]; regheap[i] = regheap[j]; regheap[j] = temp; ltmp = getlink(regheap[j]); ntmp = getnode(ltmp->l_to); ntmp->n_tloc = j; putnode(ntmp); freelink(ltmp); ltmp = getlink(regheap[i]); ntmp = getnode(ltmp->l_to); ntmp->n_tloc = i; putnode(ntmp); freelink(ltmp); } /* return 1 if n is already de-hashed (n_tloc < Hashpart), 0 o.w. */ dehash(on) register int on; { node *n, *ntmp; n = getnode(on); if (n->n_tloc < Hashpart) { freenode(n); return(1); } /* swap with entry in Table[Hashpart] */ ntmp = getnode(Table[Hashpart]); ntmp->n_tloc = n->n_tloc; putnode(ntmp); Table[n->n_tloc] = Table[Hashpart]; Table[Hashpart] = n->n_offset; n->n_tloc = Hashpart++; putnode(n); return(0); } backlinks() { link *l; node *n, *parent, *nomap; int i, ol; long tcost; for (i = Hashpart; i < Tabsize; i++) { nomap = getnode(Table[i]); parent = getnode(0); for (l = getlink(nomap->n_link); l->l_offset; l = getlink(l->l_next)) { n = getnode(l->l_to); if (!(n->n_flag & MAPPED)) { freenode(n); freelink(l); continue; } if (parent->n_offset == 0) { freenode(parent); parent = n; freelink(l); continue; } if (n->n_cost > parent->n_cost) { freenode(n); freelink(l); continue; } if (n->n_cost == parent->n_cost) { nomap->n_parent = parent->n_offset; putnode(nomap); nomap = getnode(nomap->n_offset); if (tiebreaker(nomap->n_offset, n->n_offset)) { freenode(n); freelink(l); continue; } } freenode(parent); parent = n; freelink(l); } freelink(l); if (parent->n_offset == 0) { freenode(parent); freenode(nomap); continue; } (void) dehash(nomap->n_offset); ol = addlink(parent->n_offset, nomap->n_offset, INF, DEFNET, DEFDIR); regetnode(nomap); regetnode(parent); nomap->n_parent = parent->n_offset; putnode(nomap); nomap = getnode(nomap->n_offset); tcost = costof(parent->n_offset, ol); regetnode(nomap); nomap->n_cost = tcost; putnode(nomap); freenode(parent); insert(ol); reheap(ol); } vprintf(stderr, "%d backlinks\n", Nheap); } SHAR_EOF fi if test -f 'mapaux.c' then echo shar: "will not over-write existing file 'mapaux.c'" else cat << \SHAR_EOF > 'mapaux.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)mapaux.c 8.2 (down!honey) 86/01/26"; #endif lint #include "def.h" void pack(); void pack() { int hole, next; node *n; /* find first "hole " */ for (hole = Tabsize - 1; hole >= 0 && Table[hole] != 0; --hole) ; /* repeatedly move next filled entry into last hole */ for (next = hole - 1; next >= 0; --next) { if (Table[next] != 0) { Table[hole] = Table[next]; n = getnode(Table[hole]); n->n_tloc = hole; putnode(n); Table[next] = 0; while (Table[--hole] != 0) /* find next hole */ ; } } Hashpart = hole + 1; } FILE *Gstream; dumpgraph() { int i; node *n; if ((Gstream = fopen(Graphout, "w")) == NULL) { fprintf(stderr, "%s: ", ProgName); perror(Graphout); } untangle(); /* untangle net cycles for proper output */ for (i = Hashpart; i < Tabsize; i++) { n = getnode(Table[i]); if (n->n_offset == 0) { freenode(n); continue; /* impossible, but ... */ } /* a minor optimization ... */ if (n->n_link == 0) { freenode(n); continue; } /* pathparse doesn't need these */ if (n->n_flag & NNET) { freenode(n); continue; } dumpnode(n->n_offset); freenode(n); } } dumpnode(ofrom) int ofrom; { link *l; node *from; node *to; char netbuf[BUFSIZ], *nptr = netbuf; from = getnode(ofrom); for (l = tmpgetlink(from->n_link) ; l->l_offset; l = tmpgetlink(l->l_next)) { if (ofrom == l->l_to) continue; /* oops -- it's me! */ to = tmpgetnode(l->l_to); if ((to->n_flag & NNET) == 0) { /* host -> host -- print host>host */ if (l->l_cost == INF) continue; /* phoney link */ fputs(from->n_name, Gstream); putc('>', Gstream); fputs(to->n_name, Gstream); putc('\n', Gstream); } else { /* host -> net -- just cache it for now */ while (to->n_root && to->n_offset != to->n_root) to = tmpgetnode(to->n_root); *nptr++ = ','; strcpy(nptr, to->n_name); nptr += strlen(nptr); } } /* dump nets */ if (nptr != netbuf) { /* nets -- print host@\tnet,net, ... */ *nptr = 0; fputs(from->n_name, Gstream); putc('@', Gstream); *netbuf = '\t'; /* insert tab by killing initial ',' */ fputs(netbuf, Gstream); /* skip initial ',' */ putc('\n', Gstream); } freenode(from); } /* * remove cycles in net definitions. * * depth-first search * * for each net, run dfs on its neighbors (nets only). if we return to * a visited node, that's a net cycle. mark the cycle with a pointer * in the n_root field (which gets us closer to the root of this * portion of the dfs tree). */ untangle() { int i; node *n; for (i = Hashpart; i < Tabsize; i++) { n = tmpgetnode(Table[i]); if (n->n_offset == 0 || (n->n_flag & NNET) == 0 || n->n_root) continue; dfs(n->n_offset); } } dfs(o) int o; { link *l; node *n, *next; n = getnode(o); n->n_flag |= INDFS; n->n_root = n->n_offset; putnode(n); n = getnode(n->n_offset); for (l = getlink(n->n_link); l->l_offset; l = getlink(l->l_next)) { next = getnode(l->l_to); if ((next->n_flag & NNET) == 0) { freenode(next); freelink(l); continue; } if ((next->n_flag & INDFS) == 0) { dfs(next->n_offset); regetnode(next); if (next->n_root != next->n_offset) { regetnode(n); n->n_root = next->n_root; putnode(n); n = getnode(n->n_offset); } } else { regetnode(n); n->n_root = next->n_root; putnode(n); n = getnode(n->n_offset); } freenode(next); freelink(l); } freelink(l); regetnode(n); n->n_flag &= ~INDFS; putnode(n); } showlinks() { link *l; node *n; int i; FILE *estream; if ((estream = fopen(Linkout, "w")) == 0) return; for (i = Hashpart; i < Tabsize; i++) { n = getnode(Table[i]); if (n->n_offset == 0) { /* impossible, but ... */ freenode(n); continue; } l = tmpgetlink(n->n_link); if (l->l_offset) { fprintf(estream, "%s\t%s(%d)", n->n_name, tmpgetnode(l->l_to)->n_name, l->l_cost ? l->l_cost : DEFCOST); for (l = tmpgetlink(l->l_next); l->l_offset; l = tmpgetlink(l->l_next)) fprintf(estream, ",\n\t%s(%d)", tmpgetnode(l->l_to)->n_name, l->l_cost ? l->l_cost : DEFCOST); fputc('\n', estream); } freenode(n); } (void) fclose(estream); } /* * n is node in heap, newp is candidate for new parent. * choose between newp and n->n_parent for parent. * return 0 to use newp, non-zero o.w. */ #define NEWP 0 #define OLDP 1 tiebreaker(o, onewp) int o, onewp; { register char *opname, *npname, *name; node *n, *newp, *oldp; int metric; n = getnode(o); newp = getnode(onewp); oldp = getnode(n->n_parent); /* * given the choice, avoid gatewayed nets, * thereby placating the FCC or some such. */ if (GATEWAYED(newp) && !GATEWAYED(oldp)) { freenode(n); freenode(newp); freenode(oldp); return(OLDP); } if (!GATEWAYED(newp) && GATEWAYED(oldp)) { freenode(n); freenode(newp); freenode(oldp); return(NEWP); } /* look at real parents, not nets */ while (oldp->n_flag & NNET) { freenode(oldp); oldp = getnode(oldp->n_parent); } while (newp->n_flag & NNET) { freenode(newp); newp = getnode(newp->n_parent); } /* use fewer hops, if possible */ metric = height(oldp->n_offset) - height(newp->n_offset); if (metric < 0) { freenode(oldp); freenode(newp); freenode(n); return(OLDP); } if (metric > 0) { freenode(oldp); freenode(newp); freenode(n); return(NEWP); } /* compare names */ opname = oldp->n_name; npname = newp->n_name; name = n->n_name; /* find point of departure */ while (*opname == *npname && *npname == *name) { if (*name == 0) { fprintf(stderr, "%s: error in tie breaker\n", ProgName); badmagic(1); } opname++; npname++; name++; } /* use longest match, if appl. */ if (*opname == *name || *opname == 0) { freenode(oldp); freenode(newp); freenode(n); return(OLDP); } if (*npname == *name || *npname == 0) { freenode(oldp); freenode(newp); freenode(n); return(NEWP); } /* use shorter host name, if appl. */ metric = strlen(opname) - strlen(npname); if (metric < 0) { freenode(oldp); freenode(newp); freenode(n); return(OLDP); } if (metric > 0) { freenode(oldp); freenode(newp); freenode(n); return(NEWP); } /* use larger lexicographically (no reason) */ metric = strcmp(opname, npname); freenode(oldp); freenode(newp); freenode(n); if (metric < 0) return(NEWP); return(OLDP); } height(o) register int o; { node *n; register int i = 0; n = getnode(o); freenode(n); n = getnode(n->n_parent); while (n->n_offset != 0) { if ((n->n_flag & NNET) == 0) i++; /* should count domains too ... */ freenode(n); n = getnode(n->n_parent); } freenode(n); return(i); } SHAR_EOF fi if test -f 'mem.c' then echo shar: "will not over-write existing file 'mem.c'" else cat << \SHAR_EOF > 'mem.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)mem.c 8.1 (down!honey) 86/01/19"; #endif #include "def.h" long lseek(); extern int fdlink, fdnode; extern int nodecount, linkcount; static nlinks, nnodes; /* imported */ extern char *sbrk(); link * newlink() { link *rval; int offset; if ((rval = (link * ) calloc(1, sizeof(link))) == 0) nomem(); linkcount++; nlinks++; offset = lseek(fdlink, 0l, 2) / sizeof(link); rval->l_next_from = 0; rval->l_offset = offset; rval->l_to = 0; rval->l_cost = 0; rval->l_flag = '\0'; if (write(fdlink, rval, sizeof(link)) == -1) { fprintf(stderr, "Temp file write error\n"); badmagic(1); } return(rval); } node * newnode() { node *rval; int offset; if ((rval = (node * ) calloc(1, sizeof(node))) == 0) nomem(); nodecount++; nnodes++; offset = lseek(fdnode, 0l, 2) / sizeof(node); rval->n_name[0] = '\0'; rval->n_offset = offset; rval->n_link = 0; rval->n_net_root = 0; rval->n_prvparent = 0; rval->n_cost = 0; rval->n_tloc = 0; rval->n_flag = 0; if (write(fdnode, rval, sizeof(node)) == -1) { fprintf(stderr, "Temp file write error\n"); badmagic(1); } Ncount++; return(rval); } #ifndef strclear void strclear(dst, len) register char *dst; register int len; { while (--len >= 0) *dst++ = 0; } #endif /*strclear*/ int * newtable(size) long size; { int *rval; if ((rval = (int *) calloc(1, (unsigned int) (size * sizeof(*rval)))) == 0) nomem(); return(rval); } freetable(t) int *t; { free((char *) t); } nomem() { fprintf(stderr, "%s: Out of memory (%uk allocated)\n", ProgName, allocation()); fprintf(stderr, "nodecount was %d, linkcount was %d\n", nodecount, linkcount); fprintf(stderr, "total nodes found %d, total links found %d\n", nnodes, nlinks); badmagic(1); } /* data space allocation -- main sets End very early */ allocation() { static char *dataspace; if (dataspace == 0) { /* first time */ dataspace = sbrk(0); /* &end? */ return(0); } return((sbrk(0) - dataspace)/1024); } SHAR_EOF fi if test -f 'putnode.c' then echo shar: "will not over-write existing file 'putnode.c'" else cat << \SHAR_EOF > 'putnode.c' /* putnode -- store node and link structrures temporarily in a disk file */ #include "def.h" long lseek(); extern int fdnode, fdlink; extern int nodecount, linkcount; static node tmpnode; static node nullnode; static link nulllink; static link tmplink; /* Opens temporary file */ meminit() { nodecount = 0; linkcount = 0; fdnode = creat(NTEMPFILE, 0600); close(fdnode); fdnode = open(NTEMPFILE, 2); if (fdnode < 0) { fprintf(stderr, "meminit: temporary node file open error\n"); badmagic(1); } fdlink = creat(LTEMPFILE, 0600); close(fdlink); fdlink = open(LTEMPFILE, 2); if (fdlink < 0) { fprintf(stderr, "meminit: temporary link file open error\n"); badmagic(1); } nullnode.n_name[0] = '\0'; nullnode.n_offset = 0; nullnode.n_link = 0; nullnode.n_net_root = 0; nullnode.n_prvparent = 0; nullnode.n_cost = 0; nullnode.n_tloc = 0; nullnode.n_flag = 0; write(fdnode, &nullnode, sizeof(nullnode)); nulllink.l_next_from = 0; nulllink.l_offset = 0; nulllink.l_to = 0; nulllink.l_cost = 0; nulllink.l_flag = '\0'; write(fdlink, &nulllink, sizeof(nulllink)); } /* Frees memory and stores node in temp file; takes pointer to node */ putnode(n) register node *n; { if (n->n_offset != 0) { lseek(fdnode, (long) (((long) n->n_offset) * sizeof(node)), 0); if (write(fdnode, n, sizeof(*n)) == -1) { fprintf(stderr, "putnode: temporary file write error\n"); badmagic(1); } } if (n != &tmpnode) { free((char *) n); nodecount--; } } /* Frees memory without rewriting into temp file; takes pointer to node */ freenode(n) register node *n; { if (n != &tmpnode) { free((char *) n); nodecount--; } } /* Frees memory and stores link in temp file; takes pointer to link */ putlink(l) register link *l; { if (l->l_offset != 0) { lseek(fdlink, (long) (((long) l->l_offset) * sizeof(link)), 0); if (write(fdlink, l, sizeof(*l)) == -1) { fprintf(stderr, "putlink: temporary file write error\n"); badmagic(1); } } if (l != &tmplink) { free((char *) l); linkcount--; } } /* Frees memory without rewriting into temp file; takes pointer to link */ freelink(l) register link *l; { if (l != &tmplink) { free((char *) l); linkcount--; } } /* Refreshes node from possibly modified disk image */ regetnode(oldnode) register node *oldnode; { long offset; if (oldnode->n_offset == 0) offset = nullnode.n_offset; else offset = oldnode->n_offset; lseek(fdnode, offset * sizeof(node), 0); if (read(fdnode, oldnode, sizeof(node)) <= 0) { fprintf(stderr, "regetnode: temporary file read error\n"); badmagic(1); } } /* Returns pointer to node; takes long constant offset */ node * getnode(offset) register int offset; { node *tnode; if (offset == 0) offset = nullnode.n_offset; lseek(fdnode, (long) (((long) offset) * sizeof(node)), 0); if ((tnode = (node * ) calloc(1, sizeof(node))) == 0) nomem(); nodecount++; if (read(fdnode, tnode, sizeof(tmpnode)) <= 0) { fprintf(stderr, "getnode: temporary file read error\n"); badmagic(1); } return(tnode); } /* Returns pointer to node; takes long constant offset */ /* Puts node in a temporary location */ node * tmpgetnode(offset) register int offset; { if (offset == 0) offset = nullnode.n_offset; lseek(fdnode, (long) (((long) offset) * sizeof(node)), 0); if (read(fdnode, &tmpnode, sizeof(tmpnode)) <= 0) { fprintf(stderr, "tmpgetnode: temporary file read error\n"); badmagic(1); } return(&tmpnode); } /* Returns pointer to link; takes long constant offset */ link * getlink(offset) register int offset; { link *tlink; if (offset == 0) offset = nulllink.l_offset; lseek(fdlink, (long) (((long) offset) * sizeof(link)), 0); if ((tlink = (link * ) calloc(1, sizeof(link))) == 0) nomem(); linkcount++; if (read(fdlink, tlink, sizeof(tmplink)) <= 0) { fprintf(stderr, "getlink: temporary file read error\n"); badmagic(1); } return(tlink); } /* Refreshes link from possibly modified disk image */ regetlink(oldlink) register link *oldlink; { long offset; if (oldlink->l_offset == 0) offset = nulllink.l_offset; else offset = oldlink->l_offset; lseek(fdlink, offset * sizeof(link), 0); if (read(fdlink, oldlink, sizeof(link)) <= 0) { fprintf(stderr, "regetlink: temporary file read error\n"); badmagic(1); } } /* Returns pointer to link; takes long constant offset */ /* Puts link in a temporary location */ link * tmpgetlink(offset) register int offset; { if (offset == 0) offset = nulllink.l_offset; lseek(fdlink, (long) (((long) offset) * sizeof(link)), 0); if (read(fdlink, &tmplink, sizeof(tmplink)) <= 0) { fprintf(stderr, "tmpgetlink: temporary file read error\n"); badmagic(1); } return(&tmplink); } badmagic(n) { if (n) { fprintf(stderr, "%s: cannot recover!\n", ProgName); #ifdef DEBUG abort(); #else exit(n); #endif } } SHAR_EOF fi if test -f 'parse.y' then echo shar: "will not over-write existing file 'parse.y'" else cat << \SHAR_EOF > 'parse.y' %{ /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)parse.y 8.2 (down!honey) 86/01/29"; #endif lint #include "def.h" /* I thank Paul Haahr and Greg Noel for helping to clean this up. */ node *ntmp; %} %union { int y_node; Cost y_cost; char y_net; char *y_name; struct { int ys_node; Cost ys_cost; char ys_net; char ys_dir; } y_s; } %type <y_s> site %type <y_node> links aliases plist network nlist host Psite Site %type <y_cost> cost cexpr %token <y_name> SITE HOST %token <y_cost> COST %token <y_net> NET %token NL PRIVATE %left '+' '-' %left '*' '/' %% map : /* empty */ | map NL | map links NL | map aliases NL | map network NL | map private NL | error NL ; links : host site cost { ntmp = getnode($2.ys_node); if (GATEWAYED(ntmp)) { freenode(ntmp); addgateway($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir); } else { freenode(ntmp); addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir); } } | links ',' site cost { ntmp = getnode($3.ys_node); if (GATEWAYED(ntmp)) { freenode(ntmp); addgateway($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir); } else { freenode(ntmp); addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir); } } | links ',' /* permit this benign error */ ; aliases : host '=' Site {alias($1, $3);} | aliases ',' Site {alias($1, $3);} | aliases ',' /* permit this benign error */ ; network : host '=' '{' nlist '}' cost {fixnet($1, $4, $6, DEFNET, DEFDIR);} | host '=' NET '{' nlist '}' cost {fixnet($1, $5, $7, $3, LRIGHT);} | host '=' '{' nlist '}' NET cost {fixnet($1, $4, $7, $6, LLEFT);} ; private : PRIVATE '{' plist '}' ; host : HOST {$$ = addnode($1);} | PRIVATE {$$ = addnode("private");} ; Site : SITE {$$ = addnode($1);} ; site : Site { $$.ys_node = $1; $$.ys_net = DEFNET; $$.ys_dir = DEFDIR; } | NET Site { $$.ys_node = $2; $$.ys_net = $1; $$.ys_dir = LRIGHT; } | Site NET { $$.ys_node = $1; $$.ys_net = $2; $$.ys_dir = LLEFT; } ; Psite : SITE {$$ = addprivate($1);} ; plist : Psite { ntmp = getnode($1); ntmp->n_flag |= ISPRIVATE; putnode(ntmp); } | plist ',' Psite {ntmp = getnode($3); ntmp->n_flag |= ISPRIVATE; putnode(ntmp); } | plist ',' /* permit this benign error */ ; nlist : Site | nlist ',' Site { ntmp = tmpgetnode($3); if (ntmp->n_net == 0) { ntmp->n_net = $1; putnode(ntmp); $$ = $3; } } | nlist ',' /* permit this benign error */ ; cost : {$$ = DEFCOST; /* empty -- cost is always optional */} | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')' {$$ = $3;} ; cexpr : COST | '(' cexpr ')' {$$ = $2;} | cexpr '+' cexpr {$$ = $1 + $3;} | cexpr '-' cexpr {$$ = $1 - $3;} | cexpr '*' cexpr {$$ = $1 * $3;} | cexpr '/' cexpr { if ($3 == 0) yyerror("zero divisor\n"); else $$ = $1 / $3; } ; %% yyerror(s) char *s; { /* a concession to bsd error(1) */ if (Cfile) fprintf(stderr, "\"%s\", ", Cfile); else fprintf(stderr, "%s: ", ProgName); fprintf(stderr, "line %d: %s\n", Lineno, s); } /* * patch in the costs of getting on/off the network. * * for each network member on netlist, add links: * network -> member cost = 0; * member -> network cost = parameter. * * if network and member both require gateways, assume network * is a gateway to member (but not v.v., to avoid such travesties * as topaz!seismo.css.gov.edu.rutgers). * * note that members can have varying costs to a network, by suitable * multiple declarations. this is a feechur, albeit a useless one. */ fixnet(network, nlist, cost, netchar, netdir) register network; int nlist; Cost cost; char netchar, netdir; { register int member, nextnet; node *nnetwork, *ntmp; nnetwork = getnode(network); nnetwork->n_flag |= NNET; putnode(nnetwork); /* now insert the links */ for (member = nlist ; member; member = nextnet) { nnetwork = getnode(network); ntmp = getnode(member); /* network -> member, cost is 0 */ if (GATEWAYED(nnetwork) && GATEWAYED(ntmp)) { freenode(nnetwork); freenode(ntmp); (void) addgateway(network, member, (Cost) 0, netchar, netdir); } else { freenode(nnetwork); freenode(ntmp); (void) addlink(network, member, (Cost) 0, netchar, netdir); } /* member -> network, cost is parameter */ (void) addlink(member, network, cost, netchar, netdir); ntmp = getnode(member); nextnet = ntmp->n_net; ntmp->n_net = 0; /* clear for later use */ putnode(ntmp); } } /* scanner */ #define LBRACE '{' #define RBRACE '}' #define LPAREN '(' #define RPAREN ')' #define QUOTE '"' Cost isacost(); yylex() { register int c; Cost cost; char errbuf[128]; static char buf[128]; /* for return to yacc part */ tailrecursion: if (feof(stdin) && yywrap()) return(EOF); if ((c = getchar()) == EOF) goto tailrecursion; while (c == ' ' || c == '\t') c = getchar(); if (c == '\n') { Lineno++; c = getchar(); if (c == ' ' || c == '\t') goto tailrecursion; ungetc(c, stdin); Scanstate = NEWLINE; return(NL); } if (c == '#') { while ((c = getchar()) != '\n') if (c == EOF) goto tailrecursion; ungetc(c, stdin); goto tailrecursion; } ungetc(c, stdin); switch(Scanstate) { case COSTING: if (isdigit(c)) { cost = 0; for (c = getchar(); isdigit(c); c = getchar()) cost = (cost * 10) + c - '0'; ungetc(c, stdin); yylval.y_cost = cost; return(COST); } if (getword(buf) == 0) { if ((yylval.y_cost = isacost(buf)) == 0) { sprintf(errbuf, "unknown cost (%s), using default", buf); yyerror(errbuf); yylval.y_cost = DEFCOST; } return(COST); } return(getchar()); /* can't be EOF */ case NEWLINE: Scanstate = OTHER; if (getword(buf) != 0) return(getchar()); /* can't be EOF */ /* `private' (but not `"private"')? */ if (c == 'p' && strcmp(buf, "private") == 0) return(PRIVATE); yylval.y_name = buf; return(HOST); } if (getword(buf) == 0) { yylval.y_name = buf; return(SITE); } c = getchar(); /* can't be EOF */ if (index(Netchars, c)) { yylval.y_net = c; return(NET); } return(c); } /* * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted * string that contains no newline. return -1 on failure or EOF, 0 o.w. */ getword(str) register char *str; { register int c; c = getchar(); if (c == QUOTE) { for ( ; (*str = getchar()) != '"'; str++) { if (*str == '\n') { yyerror("newline in quoted string\n"); ungetc('\n', stdin); return(-1); } } *str = 0; return(0); } /* host name must start with alphanumeric or `.' */ if (!isalnum(c) && c != '.') { ungetc(c, stdin); return(-1); } yymore: do { *str++ = c; c = getchar(); } while (isalnum(c) || c == '.' || c == '_'); if (c == '-' && Scanstate != COSTING) goto yymore; ungetc(c, stdin); *str = 0; return(0); } static struct ctable { char *cname; Cost cval; } ctable[] = { /* * this list is searched sequentially (with strcmps!). * it is too long. (they are ordered by frequency of * appearance in a "typical" dataset.) * * adding a 0 cost token breaks isacost(). don't do it. */ {"DEMAND", 300}, {"DAILY", 5000}, {"DIRECT", 200}, {"EVENING", 1800}, {"LOCAL", 25}, {"LOW", 5}, /* baud rate penalty */ {"HOURLY", 500}, {"POLLED", 5000}, {"DEDICATED", 95}, {"WEEKLY", 30000}, {"DEAD", INF/2}, {"HIGH", -5}, /* baud rate bonus */ /* the remainder are reviled */ {"ARPA", 100}, {"DIALED", 300}, {"A", 300}, {"B", 500}, {"C", 1800}, {"D", 5000}, {"E", 30000}, {"F", INF/2}, 0 }; STATIC Cost isacost(buf) register char *buf; { register struct ctable *ct; for (ct = ctable; ct->cname; ct++) if (strcmp(buf, ct->cname) == 0) return(ct->cval); return((Cost) 0); } yywrap() { char errbuf[100]; fixprivate(); /* munge private host definitions */ if (Ifiles == 0) return(1); fclose(stdin); while (*Ifiles) { Lineno = 1; if (fopen((Cfile = *Ifiles++), "r")) return(0); sprintf(errbuf, "%s: %s", ProgName, Cfile); perror(errbuf); } return(1); } SHAR_EOF fi if test -f 'makedb.c' then echo shar: "will not over-write existing file 'makedb.c'" else cat << \SHAR_EOF > 'makedb.c' /* pathalias -- by steve bellovin, as told to peter honeyman */ #ifndef lint static char *sccsid = "@(#)makedb.c 8.1 (down!honey) 86/01/19"; #endif lint #include <stdio.h> #include "config.h" typedef struct { char *dptr; int dsize; } datum; char *Ofile = ALIASDB, *ProgName; #define USAGE "%s [-o dbmname] [-a] [file ...]" main(argc, argv) char *argv[]; { char *ofptr; int c, append = 0; extern int optind; extern char *optarg; ProgName = argv[0]; while ((c = getopt(argc, argv, "o:av")) != EOF) switch(c) { case 'o': /* dbm output file */ Ofile = optarg; break; case 'a': /* append mode */ append++; break; default: fprintf(stderr, USAGE, ProgName); exit(1); break; } if ((ofptr = rindex(Ofile, '/')) != 0) ofptr++; else ofptr = Ofile; if (strlen(ofptr) > 10) { ofptr[10] = 0; fprintf(stderr, "%s: using %s for dbm output\n", ProgName, Ofile); } if (append == 0 && dbfile(Ofile) != 0) { perror_(Ofile); exit(1); } if (dbminit(Ofile) < 0) { perror_(Ofile); exit(1); } if (optind == argc) makedb((char *) 0); else for ( ; optind < argc; optind++) makedb(argv[optind]); exit(0); } dbfile(dbf) char *dbf; { return (dbcreat(dbf, "dir") != 0 || dbcreat(dbf, "pag") != 0); } dbcreat(dbf, suffix) char *dbf, *suffix; { char buf[BUFSIZ]; int fd; (void) sprintf(buf, "%s.%s", dbf, suffix); if ((fd = creat(buf, 0666)) < 0) return(-1); (void) close(fd); return(0); } makedb(ifile) char *ifile; { char line[BUFSIZ]; datum key, val; if (ifile && (freopen(ifile, "r", stdin) == NULL)) { perror_(ifile); return; } /* * keys and values are 0 terminated. this wastes time and (disk) space, * but does lend simplicity and backwards compatibility. */ key.dptr = line; while (fgets(line, sizeof(line), stdin) != NULL) { char *op, *end; end = line + strlen(line); end[-1] = 0; /* kill newline, stuff null terminator */ op = index(line, '\t'); if (op != 0) { *op++ = 0; key.dsize = op - line; /* 0 terminated */ val.dptr = op; val.dsize = end - op; /* 0 terminated */ } else { key.dsize = end - line; /* 0 terminated */ val.dptr = "\0"; /* why must i do this? */ val.dsize = 1; } if (store(key, val) < 0) perror_(Ofile); } } perror_(str) char *str; { fprintf(stderr, "%s: ", ProgName); perror(str); } SHAR_EOF fi exit 0 # End of shell archive -- Larry Campbell The Boston Software Works, Inc. Internet: campbell@maynard.bsw.com 120 Fulton Street, Boston MA 02109 uucp: {alliant,wjh12}!maynard!campbell +1 617 367 6846 ARPA: campbell%maynard.uucp@harvisr.harvard.edu MCI: LCAMPBELL