/* * mkhost [-sri] [-i ifile] [-o ofile] * * build binary network map */ #include "stdio.h" #include "ctype.h" #include "netlib.h" #include "netmap.h" #include "netfiles.h" /* * table space parameters */ #define NARGS 100 /* max arguments/line */ #define NACHR 1000 /* max argument chars */ #define NNETS 200 /* max networks */ #define NHOSTS 500 /* max hosts */ #define NCHARS 8000 /* space for names */ #define NDIALS 400 /* space for dial digits */ #define EOS '\0' /* end-of-string */ char *progname; /* program name for cmderr */ char *ifile; /* input file */ int srifmt; /* input file format flag */ char *ofile; /* output file */ /* * official map names */ char curmap[] = MAP_BIN; char oldmap[] = MAP_OBIN; char newmap[] = MAP_NBIN; /* * input variables */ unsigned lineno; /* for diagnostics */ int nerror; /* input error count */ /* * argument parsing space */ char **atop; /* top of arg list */ char *ctop; /* top of char space */ char *abuf[NARGS]; /* argument list */ char cbuf[NACHR]; /* space for arguments */ typedef struct { /* arglist structure */ int narg; /* count */ char **argv; /* -> arg list */ } arglist; /* * parsing functions */ arglist parse1(); /* white space parser */ arglist parse2(); /* comma list parser */ /* * table space for building map */ int net_cnt; /* # networks */ net_ent net_tab[NNETS]; /* networks */ int host_cnt; /* # hosts */ host_ent host_tab[NHOSTS]; /* hosts */ int name_cnt; /* # names */ int char_cnt; /* # chars */ char char_buf[NCHARS]; /* name buffer */ int dial_cnt; /* # dial digits */ char dial_buf[NDIALS]; /* dial digit buffer */ #define nameof(x) (&char_buf[x]) /* * miscellaneous functions */ netaddr _nhosta(); /* numeric network address (from library) */ char *_atouiv(); /* ascii (dec or oct) to unsigned */ char *_atoulv(); /* ascii (dec or oct) to unsigned long */ typedef unsigned int uint; typedef long ulong; main(ac, av) char **av; { char *ap; FILE *fp; /* * get progname for cmderr * process option arguments */ progname = *av++; while (ap = *av++) { if (seq(ap, "-i")) { /* * input file override */ if (!(ap = *av++)) ecmderr(0, "missing argument for -i\n"); if (ifile) ecmderr(0, "duplicate argument for -i\n"); ifile = ap; continue; } if (seq(ap, "-ai") || seq(ap, "-sri")) { /* * sri input file format */ srifmt = 1; continue; } if (seq(ap, "-o")) { /* * output file override */ if (!(ap = *av++)) ecmderr(0, "missing argument for -o\n"); if (ofile) ecmderr(0, "duplicate argument for -o\n"); ofile = ap; continue; } cmderr(0, "argument %s ignored\n", ap); } /* read ascii input */ readit(); /* sort host table and fill in network table */ sorter(); /* make network search list */ chainit(); /* generate binary map file */ genmap(); /* if doing official version, update */ if (ofile == newmap) chgmap(); exit(0); } readit() { FILE *fp; /* * determine input and read it */ if (!ifile) ifile = srifmt? MAP_SRI : MAP_BBN; printf("input file = %s\n", ifile); if ((fp = fopen(ifile, "r")) == NULL) ecmderr(-1, "cannot open %s\n", ifile); while (reader(fp)) nerror += srifmt? parsesri() : parsebbn(); fclose(fp); /* * print statistics */ printf("%d nets, %d hosts, %d names, %d name chars, %d dial digits\n", net_cnt, host_cnt, name_cnt, char_cnt, dial_cnt); if (nerror) ecmderr(0, "%d errors reading input\n", nerror); } /* * read a line of input * increment lineno * reset arg list pointers * truncate after semicolon * convert to lower case */ reader(fp) register FILE *fp; { register int c, eol; atop = abuf; ctop = cbuf; ++lineno; eol = 0; while ((c = getc(fp)) != EOF) { if (c == '\n') { addchr(EOS); return 1; } if (eol) continue; if (c == ';') { eol = 1; continue; } addchr(isupper(c)? tolower(c) : c); } return 0; } /* * parse BBN style host map * * input format: * * NET name number [synonym ...] * * [HOST] name address,network[,capability] [synonym ...] */ parsebbn() { arglist a1, a2; netnumb net; /* network number */ netaddr hosta; /* host address */ uint cap = 0; /* capability word */ a1 = parse1(cbuf); if (a1.narg == 0) return 0; if (seq(a1.argv[0], "net")) { if (a1.narg < 3) { cmderr(0, "line %u: bad number of arguments\n", lineno); return 1; } a2 = parse2(a1.argv[2]); if (a2.narg < 1 || a2.narg > 2) { cmderr(0, "line %u: bad network number %s\n", lineno, a1.argv[2]); return 1; } if (*_atoulv(a2.argv[0], &net) != EOS) { cmderr(0, "line %u: bad net number %s\n", lineno, a1.argv[2]); return 1; } if (a2.narg == 2 && *_atouiv(a2.argv[1], &cap) != EOS) { cmderr(0, "line %u: bad net capability %s\n", lineno, a2.argv[1]); return 1; } return addnet(a1.argv[1], &a1.argv[3], net, cap); } if (seq(a1.argv[0], "host")) --a1.narg, ++a1.argv; if (a1.narg < 2) { cmderr(0, "line %u: bad host arguments\n", lineno); return 1; } a2 = parse2(a1.argv[1]); if (a2.narg < 2 || a2.narg > 3) { cmderr(0, "line %u: bad host address\n", lineno, a1.argv[1]); return 1; } if (!makeaddr(a2.argv[0], a2.argv[1], &hosta)) return 1; if (a2.narg == 3 && *_atouiv(a2.argv[2], &cap) != EOS) { cmderr(0, "line %u: bad host capability %s\n", lineno, a2.argv[2]); return 1; } return addhost(a1.argv[0], &a1.argv[2], hosta, cap); } /* * parse SRI style network map * * NET name,number * * HOST name,address(es),status,system,machine,synonym(s) * */ parsesri() { ecmderr(0, "SRI not implemented yet\n"); } /* * parser for BBN style input lines * words separated by white space */ arglist parse1(sp) register char *sp; { register int c, inword; arglist args; args.argv = atop; inword = 0; while (c = *sp++) { if (isspace(c)) { if (inword) { inword = 0; addchr(EOS); } continue; } if (!inword) { inword = 1; addarg(1); } addchr(c); } if (inword) addchr(EOS); args.narg = atop - args.argv; addarg(0); return args; } /* * parser for comma separated list */ arglist parse2(sp) register char *sp; { register int c, inword; arglist args; args.argv = atop; inword = 0; while (c = *sp++) { if (c == ',') { if (!inword) addarg(1); inword = 0; addchr(EOS); continue; } if (!inword) { if (isspace(c)) continue; inword = 1; addarg(1); } addchr(c); } if (inword) addchr(EOS); args.narg = atop - args.argv; addarg(0); return args; } /* * add an argument to the list */ addarg(f) { if (atop >= &abuf[NARGS]) ecmderr(0, "line %u: too many arguments\n", lineno); *atop++ = f? ctop : NULL; } /* * add a character to the argument buffer */ addchr(c) { if (ctop >= &cbuf[NACHR]) ecmderr(0, "line %u: too many argument characters\n", lineno); *ctop++ = c; } /* * add a network */ addnet(name, syns, net, cap) char *name; /* primary name */ char **syns; /* -> aliases */ netnumb net; /* network number */ uint cap; /* capability */ { register net_ent *np; if (net_cnt <= net) net_cnt = net + 1; if (net_cnt >= NNETS) ecmderr(0, "line %u: out of network table space\n", lineno); np = &net_tab[net]; np->net_name = addname(name); np->net_cap = cap; if (syns) while (*syns) addname(*syns++); addname(NULL); return 0; } /* * add host to host table */ addhost(name, syns, hosta, hostc) char *name; /* primary name */ char **syns; /* -> aliases */ netaddr hosta; /* host address */ uint hostc; /* host capability */ { register host_ent *hp; if (host_cnt >= NHOSTS) ecmderr(0, "line %u: out of host table space\n", lineno); hp = &host_tab[host_cnt++]; hp->host_addr = hosta; hp->host_cap = hostc; hp->host_name = addname(name); if (syns) while (*syns) addname(*syns++); addname(NULL); return 0; } /* * find network name */ findnet(name, netp) char *name; netnumb *netp; { register char *lp, *tp; register net_ent *np; register int nn; for (np = &net_tab[0], nn = net_cnt; nn-- > 0; ++np) for (lp = &char_buf[np->net_name]; *lp; ++lp) { tp = name; while (*tp++ == *lp) if (*lp++ == EOS) { *netp = np - net_tab; return 1; } while (*lp != EOS) ++lp; } cmderr(0, "line %u: unknown network %s\n", lineno, name); return 0; } /* * build host address */ makeaddr(haddr, nname, hostp) char *haddr; /* host address */ char *nname; /* network name */ netaddr *hostp; /* -> network address */ { netnumb net; /* network number */ netaddr hosta; /* actual address */ if (!findnet(nname, &net)) return 0; /* * parse the host address */ hosta = _nhosta(haddr, net); if (isbadhost(hosta)) { cmderr(0, "line %u: bad host address %s\n", haddr); return 0; } *hostp = hosta; return 1; } /* * return pointer to network entry * actually a substitute for the library routine of the same name * used by _nhosta() */ net_ent * _nnetp(net) netnumb net; { if (net >= net_cnt) ecmderr(0, "bad net number %D supplied by _nhosta\n", net); return &net_tab[net]; } /* * add name to list * return index of entry * an empty string is considered an error here * since it is used to terminate lists */ addname(name) char *name; { int x; register char *p; p = name; if (p == NULL) p = ""; /* NULL implies empty */ else if (*p == EOS) ecmderr(0, "internal error: empty string in addname\n"); x = char_cnt; do if (char_cnt >= NCHARS) ecmderr(0, "line %u: out of character space\n", lineno); while (char_buf[char_cnt++] = *p++); ++name_cnt; return x; } /* * add dial digits to dial buffer * same algorithm as addname() * this routine supplants the one supplied by the library * used by _nhosta() */ unsigned _dialstr(digits) char *digits; { unsigned x; register char *p; p = digits; if (p == NULL || *p == EOS) ecmderr(0, "internal error: null or empty dial digits\n"); x = dial_cnt; do if (dial_cnt >= NDIALS) ecmderr(0, "line %u: out of dial digit space\n", lineno); while (dial_buf[dial_cnt++] = *p++); return x; } /* * sort host array */ sorter() { register int hi; register host_ent *hp; register net_ent *np; netnumb nnet, hnet; int hostcmp(); /* * sort host table by net,imp,hoi */ qsort(host_tab, host_cnt, sizeof(host_ent), hostcmp); /* * find 1st host for each net and # hosts/net */ nnet = -1; for (hi = 0; hi < host_cnt; ++hi) { hp = &host_tab[hi]; hnet = net_part(hp->host_addr); if (hnet < nnet) ecmderr(0, "internal error: bad sort\n"); if (hnet > nnet) { nnet = hnet; np = &net_tab[nnet]; np->net_host = hi; np->net_nhost = 0; } ++np->net_nhost; } } /* * compare two network addresses, piece by piece */ hostcmp(h1, h2) host_ent *h1, *h2; { register int i; if (i = net_part(h1->host_addr) - net_part(h2->host_addr)) return i; if (i = imp_part(h1->host_addr) - imp_part(h2->host_addr)) return i; if (i = hoi_part(h1->host_addr) - hoi_part(h2->host_addr)) return i; return strcmp(nameof(h1->host_name), nameof(h2->host_name)); } /* * build network search chain */ chainit() { register map_index *pp; register net_ent *np; register int nn; pp = &net_tab[0].net_next; for (np = &net_tab[1], nn = net_cnt - 1; nn-- > 0; ++np) { if (np->net_nhost <= 0) continue; *pp = np - net_tab; pp = &np->net_next; } *pp = 0; } /* * generate binary host map */ genmap() { int ofd; map_head head; extern long lseek(); /* * determine appropriate output file and build binary map * if the default is used, maintain backup version */ if (!ofile) { ofile = newmap; if (access(newmap, 0) == 0 && unlink(newmap) != 0) ecmderr(-1, "%s cannot be removed\n", newmap); } printf("output file = %s\n", ofile); /* * create output file */ if ((ofd = creat(ofile, fmodes(ofile))) < 0) ecmderr(-1, "can't create %s\n", ofile); /* * Initialize the fields of the header. */ head.map_nnet = net_cnt; head.map_nhost = host_cnt; head.map_nchar = char_cnt; head.map_ndial = dial_cnt; /* * Write header onto output file. */ ckwrite(ofd, (char *)&head, sizeof head); ckwrite(ofd, (char *)net_tab, net_cnt * sizeof(net_ent)); ckwrite(ofd, (char *)host_tab, host_cnt * sizeof(host_ent)); ckwrite(ofd, (char *)char_buf, char_cnt); ckwrite(ofd, (char *)dial_buf, dial_cnt); printf("map size = %D bytes\n", lseek(ofd, 0L, 1)); close(ofd); } /* * write something, die if it doesn't work */ ckwrite(fd, buf, cnt) char *buf; { if (write(fd, buf, cnt) != cnt) ecmderr(-1, "write error fdes %d\n", fd); } /* * change the official binary network map */ chgmap() { if (access(curmap, 0) == 0) { unlink(oldmap); if (link(curmap, oldmap) == -1) ecmderr(-1, "can't link %s to %s\n", curmap, oldmap); if (unlink(curmap) == 1) ecmderr(-1, "can't unlink %s\n", curmap); printf("%s renamed %s\n", curmap, oldmap); } if (link(newmap, curmap) == -1) { cmderr(-1, "can't link %s to %s\n", newmap, curmap); if (link(oldmap, curmap) == 0) { unlink(oldmap); ecmderr(0, "%s restored\n", curmap); } ecmderr(-1, "can't relink %s to %s\n", oldmap, curmap); } printf("%s renamed %s\n", newmap, curmap); unlink(newmap); }