#ifndef lint static char *sccsid = "@(#)arpatxt.c 9.1 87/10/04"; #endif /* * convert hosts.txt into pathalias format. * * alias rule: "host.dom.ain,nickname.arpa,..." -> host = nickname, ... */ /* remove the next line for standard or research unix */ #define BSD #ifdef BSD #define strchr index #endif /* BSD */ #include #include typedef struct node node; struct node { node *child; /* subdomain or member host */ node *parent; /* parent domain */ node *next; /* sibling in domain tree or host list */ char *name; node *alias; node *bucket; node *gateway; int flag; }; node *Top; int Atflag; int Fflag, Iflag; char *DotArpa = ".ARPA"; char Fname[256], *Fstart; node *newnode(), *find(); char *strsave(), *lowercase(); void crcinit(); long fold(); FILE *mkfile(); extern char *malloc(), *strchr(), *calloc(), *gets(), *strcpy(), *fgets(); extern FILE *fopen(); #define ISADOMAIN(n) ((n) && *((n)->name) == '.') /* for node.flag */ #define COLLISION 1 /* for formatprint() */ #define PRIVATE 0 #define HOSTS 1 #define SUBDOMAINS 2 /* for usage() */ #define USAGE "usage: %s [-i@] [-g gateway] [-p privatefile] [-f | -d directory] [file ...]\n" main(argc, argv) char **argv; { int c; char *progname; extern char *optarg; extern int optind; if ((progname = strchr(argv[0], '/')) != 0) progname++; else progname = argv[0]; crcinit(); Top = newnode(); /* needed for adding gateways */ while ((c = getopt(argc, argv, "d:fg:ip:@")) != EOF) switch(c) { case 'd': strcpy(Fname, optarg); break; case 'f': /* filter mode -- write on stdout */ Fflag++; break; case 'g': gateway(optarg); break; case 'i': Iflag++; break; case 'p': readprivates(optarg); break; case '@': Atflag++; break; default: usage(progname); } if (Fflag && *Fname) usage(progname); if (Iflag) (void) lowercase(DotArpa); if (Top->gateway == 0) fprintf(stderr, "%s: warning: no gateway to top level domains\n", progname); Fstart = Fname + strlen(Fname); if (Fstart != Fname) { *Fstart++ = '/'; *Fstart = 0; } /* should do the mkdir here instead of the shell script ...*/ Top->name = "internet"; if (optind == argc) scan(); else for ( ; optind < argc; optind++) { if (freopen(argv[optind], "r", stdin) == 0) { perror(argv[optind]); continue; } scan(); } merge(); dump(Top); return 0; } scan() { static first; char buf0[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; if (first++ == 0) (void) re_comp("^HOST.*SMTP"); while (gets(buf0) != 0) { if (re_exec(buf0) == 0) continue; if (sscanf(buf0, "HOST : %[^:] : %[^: ]", buf1, buf2) != 2) continue; if (Iflag) (void) lowercase(buf2); insert(buf2); } } /* * format of private file: * one per line, optionally followed by white space and comments * line starting with # is comment */ readprivates(pfile) char *pfile; { FILE *f; node *n; char buf[BUFSIZ], *bptr; if ((f = fopen(pfile, "r")) == 0) { perror(pfile); return; } while (fgets(buf, BUFSIZ, f) != 0) { if (*buf == '#') continue; if ((bptr = strchr(buf, ' ')) != 0) *bptr = 0; if ((bptr = strchr(buf, '\t')) != 0) *bptr = 0; if (*buf == 0) continue; n = newnode(); n->name = strsave(buf); hash(n); } (void) fclose(f); } usage(progname) char *progname; { fprintf(stderr, USAGE, progname); exit(1); } dumpgateways(ndom, f) node *ndom; FILE *f; { node *n; for (n = ndom->gateway; n; n = n->next) { fprintf(f, "%s ", n->name); if (Atflag) putc('@', f); fprintf(f, "%s(%s)\t# gateway\n", ndom->name, ndom == Top ? "DEDICATED" : "LOCAL"); } } gateway(buf) char *buf; { node *n, *dom; char *dot; dot = strchr(buf, '.'); if (dot) { dom = find(dot); *dot = 0; } else dom = Top; n = newnode(); n->name = strsave(buf); n->next = dom->gateway; dom->gateway = n; } insert(buf) char *buf; { char host[BUFSIZ], *hptr, *dot; node *n; for (hptr = host; *hptr = *buf++; hptr++) if (*hptr == ',') break; if (*hptr == ',') *hptr = 0; else buf = 0; /* no aliases */ if ((dot = strchr(host, '.')) == 0) abort(); /* can't happen */ if (strcmp(dot, DotArpa) == 0) buf = 0; /* no aliases */ n = find(dot); *dot = 0; addchild(n, host, buf); } node * find(domain) char *domain; { char *dot; node *parent, *child; if (domain == 0) return Top; if ((dot = strchr(domain+1, '.')) != 0) { parent = find(dot); *dot = 0; } else parent = Top; for (child = parent->child; child; child = child->next) if (strcmp(domain, child->name) == 0) break; if (child == 0) { child = newnode(); child->next = parent->child; parent->child = child; child->parent = parent; child->name = strsave(domain); } return child; } node * newnode() { node *n; if ((n = (node *) calloc(1, sizeof(node))) == 0) abort(); return n; } char * strsave(buf) char *buf; { char *mstr; if ((mstr = malloc(strlen(buf)+1)) == 0) abort(); strcpy(mstr, buf); return mstr; } addchild(n, host, aliases) node *n; char *host, *aliases; { node *child; /* check for dups? nah! */ child = newnode(); child->name = strsave(host); child->parent = n; child->next = n->child; makealiases(child, aliases); n->child = child; } /* yer basic tree walk */ dump(n) node *n; { node *child; FILE *f; int hadprivates = 0; if (n->child == 0) return; f = mkfile(n); if (n != Top && ! ISADOMAIN(n)) abort(); hadprivates = domprint(n, f); dumpgateways(n, f); if (hadprivates || n == Top) fputs("private {}\n", f); /* end scope of privates */ if (!Fflag) (void) fclose(f); else putc('\n', f); for (child = n->child; child; child = child->next) dump(child); } qcmp(a, b) node **a, **b; { return strcmp((*a)->name, (*b)->name); } domprint(n, f) node *n; FILE *f; { node *table[10240], *child, *alias; char *cost = 0; int nelem, i, rval = 0; /* dump private definitions */ /* sort hosts and aliases in table */ i = 0; for (child = n->child; child; child = child->next) { table[i++] = child; for (alias = child->alias; alias; alias = alias->next) table[i++] = alias; } qsort((char *) table, i, sizeof(table[0]), qcmp); formatprint(f, table, i, PRIVATE, "private", cost); /* rval == 0 IFF no privates */ while (i-- > 0) if (table[i]->flag & COLLISION) { rval = 1; break; } /* dump domains and aliases */ /* sort hosts (only) in table */ i = 0; for (child = n->child; child; child = child->next) table[i++] = child; qsort((char *) table, i, sizeof(table[0]), qcmp); /* cost is DEDICATED for hosts in top-level domains, LOCAL o.w. */ if (n->parent == Top && strchr(n->name + 1, '.') == 0) cost = "DEDICATED"; else cost = "LOCAL"; formatprint(f, table, i, HOSTS, n->name, cost); formatprint(f, table, i, SUBDOMAINS, n->name, "0"); /* dump aliases */ nelem = i; for (i = 0; i < nelem; i++) { if ((alias = table[i]->alias) == 0) continue; fprintf(f, "%s = %s", table[i]->name, alias->name); for (alias = alias->next; alias; alias = alias->next) fprintf(f, ", %s", alias->name); putc('\n', f); } return rval; } /* for debugging */ dtable(comment, table, nelem) char *comment; node **table; { int i; fprintf(stderr, "\n%s\n", comment); for (i = 0; i < nelem; i++) fprintf(stderr, "%3d\t%s\n", i, table[i]->name); } formatprint(f, table, nelem, type, lhs, cost) FILE *f; node **table; char *lhs, *cost; { int i, didprint; char buf[128], *bptr; sprintf(buf, "%s%s{" /*}*/, lhs, type == PRIVATE ? " " : " = "); bptr = buf + strlen(buf); didprint = 0; for (i = 0; i < nelem; i++) { if (type == PRIVATE && ! (table[i]->flag & COLLISION)) continue; else if (type == HOSTS && ISADOMAIN(table[i]) ) continue; else if (type == SUBDOMAINS && ! ISADOMAIN(table[i]) ) continue; if ((bptr - buf) + strlen(table[i]->name) > 69) { *bptr = 0; fprintf(f, "%s\n ", buf); /* continuation */ bptr = buf; } sprintf(bptr, "%s, ", table[i]->name); bptr += strlen(bptr); didprint++; } *bptr = 0; if ( ! didprint ) return; fprintf(f, /*{*/ "%s}", buf); if (type != PRIVATE) fprintf(f, "(%s)", cost); putc('\n', f); } FILE * mkfile(n) node *n; { node *parent; char *bptr; FILE *f; /* build up the domain name in Fname[] */ bptr = Fstart; if (n == Top) strcpy(bptr, n->name); else { strcpy(bptr, n->name + 1); /* skip leading dot */ bptr = bptr + strlen(bptr); parent = n->parent; while (ISADOMAIN(parent)) { strcpy(bptr, parent->name); bptr += strlen(bptr); parent = parent->parent; } *bptr = 0; } /* get a stream descriptor */ if (Fflag) { printf("# %s\n", Fstart); f = stdout; } else { #ifndef BSD Fstart[14] = 0; #endif if ((f = fopen(Fname, "w")) == 0) { perror(Fname); exit(1); } } if (n == Top) fprintf(f, "private {%s}\ndead {%s}\n", Top->name, Top->name); return f; } /* map to lower case in place. return parameter for convenience */ char * lowercase(buf) char *buf; { char *str; for (str = buf ; *str; str++) if (isupper(*str)) *str -= 'A' - 'a'; return buf; } /* get the interesting aliases, attach to n->alias */ makealiases(n, line) node *n; char *line; { char *next, *dot; node *a; if (line == 0 || *line == 0) return; for ( ; line; line = next) { next = strchr(line, ','); if (next) *next++ = 0; if ((dot = strchr(line, '.')) == 0) continue; if (strcmp(dot, DotArpa) != 0) continue; *dot = 0; if (strcmp(n->name, line) == 0) continue; a = newnode(); a->name = strsave(line); a->next = n->alias; n->alias = a; } } #define NHASH 13309 node *htable[NHASH]; merge() { node *n; setuniqflag(Top); for (n = Top->child; n; n = n->next) { if (n->flag & COLLISION) { fprintf(stderr, "illegal subdomain: %s\n", n->name); abort(); } promote(n); } } /* * for domains like cc.umich.edu and cc.berkeley.edu, it's inaccurate * to describe cc as a member of umich.edu or berkeley.edu. (i.e., the * lousy scoping rules for privates don't permit a clean syntax.) so. * * to prevent confusion, tack on to any such domain name its parent domain * and promote it in the tree. e.g., make cc.umich and cc.berkeley * subdomains of edu. */ promote(parent) node *parent; { node *prev, *child, *next; char buf[BUFSIZ]; prev = 0; for (child = parent->child; child; child = next) { next = child->next; if (!ISADOMAIN(child)) { prev = child; continue; } if ((child->flag & COLLISION) || child->gateway) { /* * dup domain name or gateway found. don't bump * prev: this node is moving up the tree. */ /* qualify child domain name */ sprintf(buf, "%s%s", child->name, parent->name); cfree(child->name); child->name = strsave(buf); /* unlink child out of sibling chain */ if (prev) prev->next = child->next; else parent->child = child->next; /* link child in as peer of parent */ child->next = parent->next; parent->next = child; child->parent = parent->parent; /* * reset collision flag; may promote again on * return to caller. */ child->flag &= ~COLLISION; hash(child); } else { /* this domain is uninteresting (so bump prev) */ promote(child); prev = child; } } } setuniqflag(n) node *n; { node *child, *alias; /* mark this node in the hash table */ hash(n); /* mark the aliases of this node */ for (alias = n->alias; alias; alias = alias->next) hash(alias); /* recursively mark this node's children */ for (child = n->child; child; child = child->next) setuniqflag(child); } hash(n) node *n; { node **bucket, *b; bucket = &htable[fold(n->name) % NHASH]; for (b = *bucket; b; b = b->bucket) { if (strcmp(n->name, b->name) == 0) { b->flag |= COLLISION; n->flag |= COLLISION; return; } } n->bucket = *bucket; *bucket = n; } /* stolen from pathalias:addnode.c, q.v. */ #define POLY 0x48000000 /* 31-bit polynomial */ long CrcTable[128]; void crcinit() { register int i,j; register long sum; for (i = 0; i < 128; i++) { sum = 0; for (j = 7-1; j >= 0; --j) if (i & (1 << j)) sum ^= POLY >> j; CrcTable[i] = sum; } } long fold(s) register char *s; { register long sum = 0; register int c; while (c = *s++) sum = (sum >> 7) ^ CrcTable[(sum ^ c) & 0x7f]; return sum; }