16-bit pathalias, part 2 of 2
Larry Campbell
campbell at maynard.BSW.COM
Mon Dec 15 15:02:51 AEST 1986
#! /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 at maynard.bsw.com 120 Fulton Street, Boston MA 02109
uucp: {alliant,wjh12}!maynard!campbell +1 617 367 6846
ARPA: campbell%maynard.uucp at harvisr.harvard.edu MCI: LCAMPBELL
More information about the Comp.sources.unix
mailing list