Newsgroups: comp.sources.unix From: rogers@amadeus.wr.tek.com (Roger S. Southwick) Subject: v25i093: hostcvt - convert /etc/hosts files into DNS zone files Sender: sources-moderator@pa.dec.com Approved: vixie@pa.dec.com Submitted-By: rogers@amadeus.wr.tek.com (Roger S. Southwick) Posting-Number: Volume 25, Issue 93 Archive-Name: hostcvt Here is a couple of programs for converting /etc/hosts files into files useful for the BIND Nameserver. Roger S. Southwick rogers@amadeus.wr.tek.com #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh Makefile <<'END_OF_Makefile' X# X# Makefile for hostcvt and nextserial X# X# $Id: Makefile,v 1.4 91/11/25 17:44:43 rogers Release $ X# X XBINDIR = /etc/named_data/bin XMANDIR = /usr/manl/man8 X XCFLAGS = -O XLDFLAGS = -s X Xall : hostcvt nextserial X Xhostcvt : main.o gethostent.o egetopt.o X cc $(LDFLAGS) -o hostcvt main.o gethostent.o egetopt.o X Xnextserial : nextserial.c X cc $(CFLAGS) $(LDFLAGS) -o nextserial nextserial.c X Xegetopt : egetopt.c X cc $(CFLAGS) $(LDFLAGS) -c egetopt.c X X Xinstall : $(BINDIR)/hostcvt $(BINDIR)/nextserial \ X $(MANDIR)/hostcvt.8 $(MANDIR)/nextserial.8 X X$(BINDIR)/hostcvt : hostcvt X install -c -m 0755 hostcvt $(BINDIR) X X$(BINDIR)/nextserial : nextserial X install -c -m 0755 nextserial $(BINDIR) X X$(MANDIR)/hostcvt.8 : hostcvt.8 X install -c -m 0644 hostcvt.8 $(MANDIR) X X$(MANDIR)/nextserial.8 : nextserial.8 X install -c -m 0644 nextserial.8 $(MANDIR) X Xlint : main.c gethostent.c nextserial.c X lint main.c gethostent.c X lint nextserial.c X Xclean : X rm -f hostcvt nextserial *.o make.out X END_OF_Makefile if test 972 -ne `wc -c README <<'END_OF_README' XPrograms to convert /etc/hosts files into BIND files. X XNo warrenty written or implied. You are free to use this program Xas long as you don't make money with it. If you find bugs or Xmake enhancements, please send me a patch file. X XMany thanks to Mark Frost (mfrost@pyramid.com) who modified Xthe code to handle multiple domains and different files. X X -Roger (rogers@amadeus.wr.tek.com) X UUCP: ...!uunet!tektronix!amadeus.wr.tek.com!rogers X ARPA: <@RELAY.CS.NET:rogers@amadeus.wr.tek.com> END_OF_README if test 498 -ne `wc -c egetopt.c <<'END_OF_egetopt.c' X/* X * egetopt.c -- Extended 'getopt'. X * X * A while back, a public-domain version of getopt() was posted to the X * net. A bit later, a gentleman by the name of Keith Bostic made some X * enhancements and reposted it. X * X * In recent weeks (i.e., early-to-mid 1988) there's been some X * heated discussion in comp.lang.c about the merits and drawbacks X * of getopt(), especially with regard to its handling of '?'. X * X * In light of this, I have taken Mr. Bostic's public-domain getopt() X * and have made some changes that I hope will be considered to be X * improvements. I call this routine 'egetopt' ("Extended getopt"). X * The default behavior of this routine is the same as that of getopt(), X * but it has some optional features that make it more useful. These X * options are controlled by the settings of some global variables. X * By not setting any of these extra global variables, you will have X * the same functionality as getopt(), which should satisfy those X * purists who believe getopt() is perfect and can never be improved. X * If, on the other hand, you are someone who isn't satisfied with the X * status quo, egetopt() may very well give you the added capabilities X * you want. X * X * Look at the enclosed README file for a description of egetopt()'s X * new features. X * X * The code was originally posted to the net as getopt.c by ... X * X * Keith Bostic X * ARPA: keith@seismo X * UUCP: seismo!keith X * X * Current version: added enhancements and comments, reformatted code. X * X * Lloyd Zusman X * Master Byte Software X * Los Gatos, California X * Internet: ljz@fx.com X * UUCP: ...!ames!fxgrp!ljz X * X * May, 1988 X */ X X#ifndef lint Xstatic char *RCSid = "$Id: egetopt.c,v 1.1 91/11/25 17:45:07 rogers Release $"; X#endif X X/* X * If you want, include stdio.h or something where EOF and NULL are defined. X * However, egetopt() is written so as not to need stdio.h, which should X * make it significantly smaller on some systems. X */ X X#ifndef EOF X# define EOF (-1) X#endif /* ! EOF */ X X#ifndef NULL X# define NULL (char *)0 X#endif /* ! NULL */ X X/* X * None of these constants are referenced in the executable portion of X * the code ... their sole purpose is to initialize global variables. X */ X#define BADCH (int)'?' X#define NEEDSEP (int)':' X#define MAYBESEP (int)'\0' X#define ERRFD 2 X#define EMSG "" X#define START "-" X X/* X * Here are all the pertinent global variables. X */ Xint opterr = 1; /* if true, output error message */ Xint optind = 1; /* index into parent argv vector */ Xint optopt; /* character checked for validity */ Xint optbad = BADCH; /* character returned on error */ Xint optchar = 0; /* character that begins returned option */ Xint optneed = NEEDSEP; /* flag for mandatory argument */ Xint optmaybe = MAYBESEP;/* flag for optional argument */ Xint opterrfd = ERRFD; /* file descriptor for error text */ Xchar *optarg; /* argument associated with option */ Xchar *optstart = START; /* list of characters that start options */ X X X/* X * Macros. X */ X X/* X * Conditionally print out an error message and return (depends on the X * setting of 'opterr' and 'opterrfd'). Note that this version of X * TELL() doesn't require the existence of stdio.h. X */ X#define TELL(S) { \ X if (opterr && opterrfd >= 0) { \ X char option = optopt; \ X (void)write(opterrfd, *nargv, strlen(*nargv)); \ X (void)write(opterrfd, (S), strlen(S)); \ X (void)write(opterrfd, &option, 1); \ X (void)write(opterrfd, "\n", 1); \ X } \ X return (optbad); \ X} X X/* X * This works similarly to index() and strchr(). I include it so that you X * don't need to be concerned as to which one your system has. X */ Xstatic char * X_sindex(string, ch) Xchar *string; Xint ch; X{ X if (string != NULL) { X for (; *string != '\0'; ++string) { X if (*string == (char)ch) { X return (string); X } X } X } X X return (NULL); X} X X/* X * Here it is: X */ Xint Xegetopt(nargc, nargv, ostr) Xint nargc; Xchar **nargv; Xchar *ostr; X{ X static char *place = EMSG; /* option letter processing */ X register char *oli; /* option letter list index */ X register char *osi = NULL; /* option start list index */ X X if (nargv == (char **)NULL) { X return (EOF); X } X X if (nargc <= optind || nargv[optind] == NULL) { X return (EOF); X } X X if (place == NULL) { X place = EMSG; X } X X /* X * Update scanning pointer. X */ X if (*place == '\0') { X place = nargv[optind]; X if (place == NULL) { X return (EOF); X } X osi = _sindex(optstart, *place); X if (osi != NULL) { X optchar = (int)*osi; X } X if (optind >= nargc || osi == NULL || *++place == '\0') { X return (EOF); X } X X /* X * Two adjacent, identical flag characters were found. X * This takes care of "--", for example. X */ X if (*place == place[-1]) { X ++optind; X return (EOF); X } X } X X /* X * If the option is a separator or the option isn't in the list, X * we've got an error. X */ X optopt = (int)*place++; X oli = _sindex(ostr, optopt); X if (optopt == optneed || optopt == optmaybe || oli == NULL) { X /* X * If we're at the end of the current argument, bump the X * argument index. X */ X if (*place == '\0') { X ++optind; X } X TELL(": illegal option -- "); /* byebye */ X } X X /* X * If there is no argument indicator, then we don't even try to X * return an argument. X */ X ++oli; X if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) { X /* X * If we're at the end of the current argument, bump the X * argument index. X */ X if (*place == '\0') { X ++optind; X } X optarg = NULL; X } X /* X * If we're here, there's an argument indicator. It's handled X * differently depending on whether it's a mandatory or an X * optional argument. X */ X else { X /* X * If there's no white space, use the rest of the X * string as the argument. In this case, it doesn't X * matter if the argument is mandatory or optional. X */ X if (*place != '\0') { X optarg = place; X } X /* X * If we're here, there's whitespace after the option. X * X * Is it a mandatory argument? If so, return the X * next command-line argument if there is one. X */ X else if (*oli == optneed) { X /* X * If we're at the end of the argument list, there X * isn't an argument and hence we have an error. X * Otherwise, make 'optarg' point to the argument. X */ X if (nargc <= ++optind) { X place = EMSG; X TELL(": option requires an argument -- "); X } X else { X optarg = nargv[optind]; X } X } X /* X * If we're here it must have been an optional argument. X */ X else { X if (nargc <= ++optind) { X place = EMSG; X optarg = NULL; X } X else { X optarg = nargv[optind]; X if (optarg == NULL) { X place = EMSG; X } X /* X * If the next item begins with a flag X * character, we treat it like a new X * argument. This is accomplished by X * decrementing 'optind' and returning X * a null argument. X */ X else if (_sindex(optstart, *optarg) != NULL) { X --optind; X optarg = NULL; X } X } X } X place = EMSG; X ++optind; X } X X /* X * Return option letter. X */ X return (optopt); X} END_OF_egetopt.c if test 6954 -ne `wc -c gethostent.c <<'END_OF_gethostent.c' X/* X * Copyright (c) 1983 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#include X#include X#include X#include X#include X X#ifndef lint Xstatic char *RCSid = "$Id: gethostent.c,v 1.2 90/10/03 22:50:29 rogers Release $"; X#endif X X/* X * Internet version. X */ X#define MAXALIASES 35 X#define MAXADDRSIZE 14 X Xstatic FILE *hostf = NULL; Xstatic char line[BUFSIZ+1]; Xstatic char hostaddr[MAXADDRSIZE]; Xstatic struct hostent host; Xstatic char *host_aliases[MAXALIASES]; Xstatic char *host_addrs[] = { X hostaddr, X NULL X}; X X/* X * The following is shared with gethostnamadr.c X */ X Xstatic char *any(); X X#ifdef NOTUSEDINHOSTCVT X Xmysethostent() X{ X if (hostf != NULL) X rewind(hostf); X} X Xmyendhostent() X{ X if (hostf != NULL) { X (void)fclose(hostf); X hostf = NULL; X } X} X#endif /* NOTUSEDINHOSTCVT */ X Xstruct hostent * Xmygethostent(fname) Xchar *fname; X{ X u_long inet_addr(); X char *p; X register char *cp, **q; X X if (hostf == NULL && (hostf = fopen(fname, "r" )) == NULL) X return (NULL); Xagain: X if ((p = fgets(line, BUFSIZ, hostf)) == NULL) X return (NULL); X if (*p == '#') X goto again; X cp = any(p, "#\n"); X if (cp == NULL) X goto again; X *cp = '\0'; X cp = any(p, " \t"); X if (cp == NULL) X goto again; X *cp++ = '\0'; X /* THIS STUFF IS INTERNET SPECIFIC */ X host.h_addr_list = host_addrs; X *((u_long *)host.h_addr) = inet_addr(p); X host.h_length = sizeof (u_long); X host.h_addrtype = AF_INET; X while (*cp == ' ' || *cp == '\t') X cp++; X host.h_name = cp; X q = host.h_aliases = host_aliases; X cp = any(cp, " \t"); X if (cp != NULL) X *cp++ = '\0'; X while (cp && *cp) { X if (*cp == ' ' || *cp == '\t') { X cp++; X continue; X } X if (q < &host_aliases[MAXALIASES - 1]) X *q++ = cp; X cp = any(cp, " \t"); X if (cp != NULL) X *cp++ = '\0'; X } X *q = NULL; X return (&host); X} X Xstatic char * Xany(cp, match) X register char *cp; X char *match; X{ X register char *mp, c; X X while (c = *cp) { X for (mp = match; *mp; mp++) X if (*mp == c) X return (cp); X cp++; X } X return ((char *)0); X} END_OF_gethostent.c if test 2771 -ne `wc -c hostcvt.8 <<'END_OF_hostcvt.8' X.\" X.\" $Id: hostcvt.8,v 1.2 91/11/25 17:45:24 rogers Release $ X.\" X.TH HOSTCVT 8 "10-3-90" X.SH NAME Xhostcvt - Convert hosts(5) file to BIND files X.SH SYNOPSIS X.B hostcvt X[ -s X.I soabasefile X] [ -n X.I netfile X] X[ -h X.I hostfile X] X.br X [ -o X.I outputfile X] domain X.SH DESCRIPTION X.LP X.I hostcvt Xreads a hosts(5) file specified by the X.I hostfile Xargument ("hosts.thisdomain" by default), and converts them to XBIND hostname-to-address and reverse tables for the argument X.I Xdomain. XThe names of the reverse files are specified in the argument X.I netfile X("netlist" by default). XIf no output file is specified, the hostname to address table is put Xinto a file in the current directory named X.I domain. XAll files are prepended with the X.I soabasefile X("soabasefile" by default) which is the SOA record for this domain (see example Xbelow). X.LP X.B Hostcvt Xissues warnings for any duplicated names (name to name, name to Xaliases, aliases to name and aliases to aliases) and will only allow Xthe first instance of a name from X.I hostsfile Xto be in the outputfile and the reverse table files. Lines in X.I hostsfile Xthat have an IP address but no hostname are ignored and a warning message is Xprinted. X.LP X.SH OPTIONS X.TP X.BI \-h " hostsfile" XSpecify a file in hosts(5) format to read hosts from. The default is X"hosts.thisdomain". X.TP X.BI \-n " netfile" XSpecify a X.I netfile. XThis file specifies the names of the reverse tables. The default is "netlist". X.LP X.TP X.BI \-o " outputfile" XSpecify an output file for the hostname-to-address file. If unspecified, this Xfile is the same as X.I domainname. X.LP X.TP X.BI \-s " soabasefile" XSpecify an SOA file. The default is "soabasefile". X.SH "FORMAT OF THE NETLIST FILE" X.LP X.I netfile Xhas the format: X.RS X.nf X Xnetportion file X.fi X.RE X.LP XThe X.I netportion Xdescribes the portion of the address field which hostcvt is to pay attention Xto. The X.I netportion Xshould be all digits and dots necessary to do a strncmp() against the Xaddress portion of X.I hostsfile, Xtaking into account how the X.I named.boot Xfile is set up for the reverse address translation. X.LP XThe X.I file Xis the path to the file the reverse address for this X.I netportion. X.LP XFor example, suppose named.boot file has the following reverse translations: X.RS X.nf X Xprimary 36.in-addr.arpa net/net36 Xprimary 0.101.in-addr.arpa net/net101 Xprimary 0.0.100.in-addr.arpa net/net127 Xprimary 63.134.in-addr.arpa reversefile X.fi X.RE X.LP XFor the net 36 addresses, the X.I hostsfile Xwould have entries of 36.xx.yy.zz, where all three lower portions Xwould be used. For the net 101 addresses, the X.I hosts.thisdomain Xfile would have 101.0.yy.zz entries. And so forth. X.LP XThe corresponding X.I netfile Xwould show: X.RS X.nf X X36. net/net36 X101.0. net/net101 X100.0.0. net/net100 X134.63. reversefile X.fi X.RE X.LP XIt is VERY important that the trailing dot be in the X.I netportion Xof the X.I netfile. XThe program does a strncmp() against the host address field of X.I hostsfile Xusing the X.I netportion Xstring and it's length to get the exact match (O.K., so the program is Xa hack). X.LP X.B Hostcvt Xignores lines starting with a # (pound sign) or empty (i.e. ^$ in egrep terms) Xlines in the X.I netlist Xfile. These may be used for comments or separation. X.SH "FORMAT OF THE SOABASEFILE" X.LP XThe X.I soabasefile Xis the SOA record which is prepended to all output files, and should Xbe a valid SOA format. Here is the X.I soabasefile Xfor our domain (wr.tek.com): X.RS X.nf X X@ IN SOA wrgate.wr.tek.com. wrap.wrgate.wr.tek.com. ( X 1 ; Serial X 3600 ; Refresh X 300 ; Retry X 3600000 ; Expire X 14400 ) ; Minimum X IN NS wrgate.wr.tek.com. X.fi X.RE X.LP XNote that the Serial number in the X.I soabasefile Xshould be advanced before X.B hostcvt Xis run, rather than trying to change all the SOA records in the resulting Xfiles. The X.B nextserial Xprogram is a convenient tool for changing the Serial numbers in files. X.SH "EXAMPLE USAGE" X.LP XThe following is what I do to convert my X.I hostsfile Xinto files for my domain: X.RS X.nf Xnextserial soabasefile Xhostcvt -s soabasefile wr.tek.com X.fi X.RE X.SH "SEE ALSO" Xhosts(5), nextserial(8) X.SH BUGS XIt would also be nice to retain comments made in X.I hostsfile. X.LP X.SH AUTHOR XRoger S. Southwick X.br Xrogers@amadeus.wr.tek.com X.LP XModifications by Mark Frost X.br Xmfrost@pyramid.com END_OF_hostcvt.8 if test 4360 -ne `wc -c main.c <<'END_OF_main.c' X#include X#include X#include X#include X#include X#include X#include X#include X X#ifndef lint Xstatic char *RCSid = "$Id: main.c,v 1.4 91/11/25 17:46:06 rogers Release $"; X X#endif X Xstruct netlist { X char *nl_net; /* Net number portion */ X int nl_netlen; /* Length of above */ X char *nl_file; /* File name */ X FILE *nl_fp; /* Pointer to above */ X struct netlist *nl_next; /* Next one */ X}; X Xtypedef struct netlist nl_t; Xtypedef struct netlist *nl_tp; X Xstruct host_names { X char *h_name; X char **h_aliases; X struct host_names *h_next; X}; X Xtypedef struct host_names hn_t; Xtypedef struct host_names *hn_tp; X Xchar *soa = NULL; /* The soa from argv[] */ Xchar *domain = NULL; /* Domain name from argv[] */ Xnl_tp ntop = NULL; /* Top of linked list */ Xhn_tp hntop = NULL; /* Top of list of hostnames */ Xchar *hostsfile, *netfile, *soafile, *outputfile; Xextern char *optarg; /* for egetopt() */ X Xextern int optind; /* for egetopt() */ Xextern int errno; Xextern char *sys_errlist[]; X X#define ERR sys_errlist[errno], errno X Xvoid exit(); X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X FILE *fopen(); X char *strsave(), *malloc(); X struct hostent *mygethostent(); X register struct hostent *hp; X register FILE *fp; X register char *ipaddr, **cpp; X register nl_tp np; X struct in_addr foo; X X char ch; X int hostflag, soaflag, netflag, errflag, outputflag, domainflag; X X hostflag = soaflag = netflag = errflag = outputflag = domainflag = 0; X hostsfile = soafile = netfile = domain = outputfile = NULL; X X X while ((ch = egetopt(argc, argv, "h:n:o:s:")) != -1) X switch (ch) { X case 'h': /* assign name for "hosts" file (sourcefile) */ X if (hostflag){ X errflag++; X } X else { X hostsfile = strsave(optarg); X hostflag++; X } X break; X X case 'n': /* assign name for "netlist" */ X if (netflag){ X errflag++; X } X else { X netfile = strsave(optarg); X netflag++; X } X break; X X case 'o': /* assign name for main output file */ X if (outputflag){ X errflag++; X } X else { X outputfile = strsave(optarg); X outputflag++; X } X break; X X case 's': /* assign name for "soabasefile" */ X if (soaflag){ X errflag++; X } X else { X soafile = strsave(optarg); X soaflag++; X } X break; X X case '?': /* anything else that might show up */ X errflag++; X X } /* switch */ X X for (; optind < argc; optind++) { X if (domainflag) { X errflag++; X break; X } /* if */ X else { X domain = strsave(argv[optind]); X domainflag++; X } /* else */ X } /* for */ X X if (errflag || domain == NULL || (strlen(domain) < 2)) { X (void) fprintf(stderr, "usage: hostcvt [-h hostsfile] [-n netlistfile]\n\t\t[-s soabasefile] [-o outputfile] domain\n"); X exit(2); X } X X if (!netflag){ X netfile = strsave("netlist"); X } X X if (!hostflag){ X hostsfile = strsave("hosts.thisdomain"); X } X X if (!soafile) { X soafile = strsave("soabasefile"); X } X if (!outputflag){ X outputfile = domain; X } X X rdsoa(soafile); X X (void)close(0); X (void)close(1); X X if((fp = fopen(outputfile, "w")) == NULL) { X (void) fprintf(stderr, "hostcvt: could not open %s\n", outputfile); X exit(1); X } X X if(access(hostsfile, R_OK) == -1) { X (void) fprintf(stderr, "hostcvt: no host file %s\n", hostsfile); X exit(1); X } X X if(soa != NULL) { X (void) fputs(soa, fp); X } X X rdnetlist(); X X while ((hp = mygethostent(hostsfile)) != NULL) { X foo.s_addr = (u_long) * ((u_long *) hp->h_addr); X ipaddr = inet_ntoa(foo); X if (outnet(ipaddr, hp->h_name)) { X X if (isdup(hp)){ X continue; X } X X if (strlen(hp->h_name) == 0) { X (void)fprintf(stderr, "No name found for %s -- ignoring...\n", ipaddr); X } X else { X savehp(hp); X X (void) fprintf(fp, "%s\t\tIN\tA\t%s\n", hp->h_name, ipaddr); X X for (cpp = hp->h_aliases; *cpp != NULL; cpp++) { X if (strcasecmp(*cpp, hp->h_name) != 0) { X (void) fprintf(fp, "%s\t\tIN\tCNAME\t%s\n", *cpp, hp->h_name); X } X } /* else */ X } X } X } X (void) fflush(fp); X (void) fclose(fp); X for (np = ntop; np != NULL; np = np->nl_next) { X (void) fflush(np->nl_fp); X (void) fclose(np->nl_fp); X } X X return(0); X} X X/* X * See if the new hostname or any of it's aliases X * are already known. X */ X Xint Xisdup(hp) Xregister struct hostent *hp; X{ X register hn_tp np; X register char **cpp, **acp; X X /* X * For each node in our linked list of known names.... X */ X X for (np = hntop; np != NULL; np = np->h_next) { X X /* X * See if the new name matches directly X */ X X if (strcasecmp(hp->h_name, np->h_name) == 0) { X (void) fprintf(stderr, "hostcvt: duplicated name: %s\n", hp->h_name); X return (1); X } X X /* X * See if the new name matches an alias X */ X X for (acp = np->h_aliases; *acp != NULL; acp++) { X if (strcasecmp(hp->h_name, *acp) == 0) { X (void) fprintf(stderr, "hostcvt: duplicated name to alias: %s\n", hp->h_name); X return (1); X } X } X X /* X * For each of the new machines aliases X */ X X for (cpp = hp->h_aliases; *cpp != NULL; cpp++) { X X /* X * See if the alias matches the real name X */ X X if (strcasecmp(*cpp, np->h_name) == 0) { X (void) fprintf(stderr, "hostcvt: duplicated alias to name: %s\n", hp->h_name); X return (1); X } X X /* X * See if the alias matches one of our aliases X */ X X for (acp = np->h_aliases; *acp != NULL; acp++) { X if (strcasecmp(*acp, *cpp) == 0) { X (void) fprintf(stderr, "hostcvt: duplicated alias to alias: %s\n", hp->h_name); X return (1); X } X } X } X } X X return (0); /* No match */ X} X Xsavehp(hp) Xregister struct hostent *hp; X{ X char *malloc(), *strsave(); X register char **cpp, **acp; X register int cnt; X register hn_tp np; X X if ((np = (hn_tp) malloc(sizeof(hn_t))) == NULL) { X (void) fprintf(stderr, "hostcvt: could not malloc in savehp()!\n"); X exit(1); X } X X np->h_name = strsave(hp->h_name); X X for (cnt = 1, cpp = hp->h_aliases; *cpp != NULL; cpp++) X cnt++; X X if ((np->h_aliases = (char **) malloc((unsigned) (cnt * sizeof(char **)))) == NULL) { X (void) fprintf(stderr, "hostcvt: could not malloc in savehp()!\n"); X exit(1); X } X X for (cpp = hp->h_aliases, acp = np->h_aliases; *cpp != NULL; cpp++, acp++) { X *acp = strsave(*cpp); X } X *acp = NULL; X X np->h_next = hntop; X hntop = np; X} X X/* X * Add the host named "name" at the IP address "ip" to X * the proper net file. Return 1 if done OK, 0 if not. X */ X Xint Xoutnet(ip, name) Xchar *ip, *name; X{ X char *strcpy(), *index(), *strsave(); X register nl_tp np; X register int i; X register char *last, *cp, *ipaddr; X char dig[4][20]; X X ipaddr = strsave(ip); X X for (np = ntop; np != NULL; np = np->nl_next) { X if (strncmp(ipaddr, np->nl_net, np->nl_netlen) == 0) { X last = ipaddr + np->nl_netlen; X bzero((char *) dig, sizeof(dig)); X X for (i = 0; *last != '\0'; i++) { X if ((cp = index(last, '.')) == NULL){ X break; X } X X *cp = '\0'; X (void) strcpy(dig[i], last); X last = cp + 1; X } X X (void) fprintf(np->nl_fp, "%s", last); X X for (i = 3; i >= 0; i--) { X if (dig[i][0] != '\0'){ X (void) fprintf(np->nl_fp, ".%s", dig[i]); X } X } X (void) fprintf(np->nl_fp, "\t\tIN\tPTR\t%s.%s.\n", name, domain); X return (1); X } X } X (void) fprintf(stderr, "hostcvt: could not find file for %s (add= %s)\n", name, ipaddr); X return (0); X} X Xrdnetlist() X{ X char *strsave(), *malloc(), *index(); X FILE *fopen(); X register FILE *fp; X register nl_tp np; X register int i, cnt; X char nbuf[256], fbuf[512], buf[BUFSIZ]; X X if ((fp = fopen(netfile, "r")) == NULL) { X (void) fprintf(stderr, "hostcvt: could not open %s\n", netfile); X exit(1); X } X X for (i = 1, cnt = 0; fgets(buf, BUFSIZ, fp) != NULL; i++) { X if (buf[0] == '#' || buf[0] == '\n'){ /* allow comments and blanks */ X continue; X } X X if (sscanf(buf, "%s %s", nbuf, fbuf) != 2) { X (void) fprintf(stderr, "hostcvt: error on line #%d in %s, contents= %s", i, netfile, buf); X continue; X } X X if ((np = (nl_tp) malloc(sizeof(nl_t))) == NULL) { X (void) fprintf(stderr, "hostcvt: could not malloc!\n"); X exit(1); X } X np->nl_net = strsave(nbuf); X np->nl_netlen = strlen(nbuf); X np->nl_file = strsave(fbuf); X np->nl_fp = NULL; X np->nl_next = ntop; X ntop = np; X cnt++; X } X (void) fclose(fp); X X /* X * figure out how many open files we can have: Max (getdtablesize) minus: X * 1 for stderr (stdin & stdout closed) 1 for domain (output) file X * (argv[1]) X */ X X i = getdtablesize() - 2; X if (cnt > i) { X (void) fprintf(stderr, "hostcvt: can not have more than %d entries (you have %d)\n", i, cnt); X exit(1); X } X X for (np = ntop; np != NULL; np = np->nl_next) { X if ((np->nl_fp = fopen(np->nl_file, "w")) == NULL) { X (void) fprintf(stderr, "hostcvt: could not open %s for write\n", np->nl_file); X continue; X } X if (soa != NULL) { X (void) fputs(soa, np->nl_fp); X } X } X} X Xrdsoa(file) Xchar *file; X{ X int read(), open(), fstat(); X register int fd, rv; X struct stat stb; X X if ((fd = open(file, O_RDONLY, 0)) == -1) { X soa = NULL; X (void) fprintf(stderr, "hostcvt: could not open SOA file, skipping\n"); X return; X } X X if (fstat(fd, &stb) == -1) { X (void) fprintf(stderr, "hostcvt: could not fstat %s (%d)\n", ERR); X exit(1); X } X X if ((soa = malloc((unsigned) stb.st_size)) == NULL) { X (void) fprintf(stderr, "hostcvt: could not malloc enough for SOA file (%s)\n", file); X exit(1); X } X X if ((rv = read(fd, soa, (int) stb.st_size)) != stb.st_size) { X (void) fprintf(stderr, "hostcvt: asked to read %d, got %d", (int) stb.st_size, rv); X if (rv == -1){ X (void) fprintf(stderr, " - %s (%d)", ERR); X } X X (void) fprintf(stderr, "\n"); X exit(1); X } X X (void) close(fd); X} X Xchar * Xstrsave(str) Xregister char *str; X{ X char *malloc(), *strcpy(); X register char *cp; X X if (str == NULL) X return (NULL); X X if ((cp = malloc((unsigned) (strlen(str) + 1))) != NULL) X (void) strcpy(cp, str); X X return (cp); X} END_OF_main.c if test 10143 -ne `wc -c nextserial.8 <<'END_OF_nextserial.8' X.\" X.\" $Id: nextserial.8,v 1.1 90/10/03 23:34:03 rogers Release $ X.\" X.TH NEXTSERIAL 8 "10-3-90" X.SH NAME Xnextserial - Increment the BIND SOA Serial number in a file X.SH SYNOPSIS X.B nextserial X.I soafile X.SH DESCRIPTION X.LP X.I nextserial Xreads the X.I soafile Xfile for a line containing the (regular expression) pattern "Serial". XThis line is assumed to be the line containing the SOA Serial Xnumber. The number is read from the line and incremented. The Xline is then written with the new serial number. All other lines Xare put through unchanged. X.SH "EXAMPLE" X.LP XGiven the X.I soafile Xfor our domain (wr.tek.com): X.RS X.nf X X@ IN SOA wrgate.wr.tek.com. wrap.wrgate.wr.tek.com. ( X 1 ; Serial X 3600 ; Refresh X 300 ; Retry X 3600000 ; Expire X 14400 ) ; Minimum X IN NS wrgate.wr.tek.com. X.fi X.RE X.LP XRunning X.I "nextserial soafile" Xwould result in the X.I soafile Xlooking like: X.RS X.nf X X@ IN SOA wrgate.wr.tek.com. wrap.wrgate.wr.tek.com. ( X 2 ; Serial X 3600 ; Refresh X 300 ; Retry X 3600000 ; Expire X 14400 ) ; Minimum X IN NS wrgate.wr.tek.com. X.fi X.RE X.SH "SEE ALSO" Xhostcvt(8) X.SH BUGS XSince the program uses regex() to find the line with "Serial" on it, Xthe X.I soafile Xshould have no other lines with that string on it. X.SH AUTHOR XRoger S. Southwick X.br Xrogers@dadla.wr.tek.com END_OF_nextserial.8 if test 1311 -ne `wc -c nextserial.c <<'END_OF_nextserial.c' X#include X X#ifndef lint Xstatic char *RCSid = "$Id: nextserial.c,v 1.1 90/10/03 22:56:42 rogers Release $"; X#endif X X#define PAT "Serial" X Xextern int errno; Xextern char *sys_errlist[]; X#define ERR sys_errlist[errno] X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X FILE *fopen(); X char *re_comp(), *fgets(), *index(), *mktemp(); X register char *cp; X register FILE *infp, *outfp; X register char *tmpname; X char buf[BUFSIZ]; X int serial; X X (void)umask(022); X X if(argc != 2){ X (void)fprintf(stderr, "usage: nextserial soafile\n"); X exit(1); X } X X if((cp = re_comp(PAT)) != NULL){ X (void)fprintf(stderr, "nextserial: %s\n", cp); X exit(1); X } X X tmpname = mktemp(".nxtXXXXXX"); X (void)unlink(tmpname); X X if(rename(argv[1], tmpname) == -1){ X (void)fprintf(stderr, "nextserial: could not rename(%s, %s) - %s (%d)\n", argv[1], tmpname, ERR); X exit(1); X } X X if((infp = fopen(tmpname, "r")) == NULL){ X (void)fprintf(stderr, "nextserial: could not open %s for read\n", tmpname); X X if(rename(tmpname, argv[1]) == -1) X (void)fprintf(stderr, "EKK! could not put %s back to %s!\n", tmpname, argv[1]); X exit(1); X } X X if((outfp = fopen(argv[1], "w")) == NULL){ X (void)fprintf(stderr, "nextserial: could not open %s for write\n", argv[1]); X X if(rename(tmpname, argv[1]) == -1) X (void)fprintf(stderr, "EKK! could not put %s back to %s!\n", tmpname, argv[1]); X exit(1); X } X X while(fgets(buf, BUFSIZ, infp) != NULL){ X switch(re_exec(buf)){ X case 0: X (void)fputs(buf, outfp); X break; X X case -1: X default: X (void)fprintf(stderr, "nextserial: regex internal error\n"); X exit(1); X X case 1: X if((cp = index(buf, '\n')) != NULL) X *cp = '\0'; X X if(sscanf(buf, "%d", &serial) != 1){ X (void)fprintf(stderr, "nextserial: could not decode [%s]\n", buf); X exit(1); X } X X (void)fprintf(outfp, "\t\t\t\t%d\t; %s\n", ++serial, PAT); X break; X } X } X (void)fclose(outfp); X (void)fclose(infp); X (void)unlink(tmpname); X exit(0); X} END_OF_nextserial.c if test 2026 -ne `wc -c