Files
Arquivotheca.SunOS-4.1.3/lib/libc/net/gethostent.c
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

405 lines
8.4 KiB
C

#if !defined(lint) && defined(SCCSIDS)
static char sccsid[] = "@(#)gethostent.c 1.1 92/07/30 Copyr 1990 Sun Micro";
#endif
/*
* Copyright (c) 1990 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <rpcsvc/ypclnt.h>
struct hostent *_gethostent();
/*
* Internet version.
*/
static struct hostdata {
FILE *hostf;
char *current;
int currentlen;
int stayopen;
#define MAXALIASES 20
char *host_aliases[MAXALIASES];
#define MAXADDRS 10
#define HOSTADDRSIZE 4 /* assumed == sizeof u_long */
char hostaddr[MAXADDRS][HOSTADDRSIZE];
char *addr_list[MAXADDRS+1];
char line[BUFSIZ+1];
struct hostent host;
char *domain;
char *map;
int notusingyellow;
} *hostdata, *_hostdata();
static struct hostent *interpret();
struct hostent *gethostent();
char *inet_ntoa();
char *strpbrk();
static char *HOSTDB = "/etc/hosts";
/*
* Internal routine to allocate hostdata on heap, instead of
* putting lots of stuff into the data segment.
*/
static struct hostdata *
_hostdata()
{
register struct hostdata *d = hostdata;
if (d == 0) {
d = (struct hostdata *)calloc(1, sizeof (struct hostdata));
hostdata = d;
(void) yp_get_default_domain(&d->domain);
}
return (d);
}
/*
* NIS use strategy:
* gethostbyaddr() and gethostbyname() always try NIS first.
* gethostent() tries NIS first, if it fails with an indication
* that NIS is not running it sets a flag so that subsequent
* calls will not try NIS. If sethostent() is called
* the next gethostent() will try NIS first. An intervening
* gethostbyaddr() or gethostbyname() will also
* clear the flag so that gethostent() will go back to trying NIS
*/
struct hostent *
gethostbyaddr(addr, len, type)
char *addr;
register int len, type;
{
register struct hostdata *d = _hostdata();
register struct hostent *p;
char *adrstr, *val = NULL;
int vallen;
int stat;
h_errno = NO_RECOVERY;
if (d == 0)
return ((struct hostent*)NULL);
d->map = "hosts.byaddr";
sethostent(0);
if (d->domain ) {
/*try to yp_match it*/
adrstr = inet_ntoa(*(struct in_addr *)addr);
stat = yp_match(d->domain, d->map, adrstr, strlen(adrstr),
&val, &vallen);
switch (stat) {
case 0:
p = interpret(val, vallen);
free(val);
h_errno = 0;
return(p);
case YPERR_KEY:
h_errno = HOST_NOT_FOUND;
return(NULL);
case YPERR_NOMORE:
h_errno = TRY_AGAIN;
return(NULL);
}
}
h_errno = HOST_NOT_FOUND;
_sethostent(0);
while (p = _gethostent()) {
if (p->h_addrtype != type || p->h_length != len)
continue;
if (bcmp(p->h_addr_list[0], addr, len) == 0) {
h_errno = 0;
break;
}
}
endhostent();
return (p);
}
struct hostent *
gethostbyname(name)
register char *name;
{
register struct hostdata *d = _hostdata();
register struct hostent *p;
register char **cp;
register char *name2;
char *val = NULL;
int vallen,stat;
h_errno = NO_RECOVERY;
if (d == 0)
return ((struct hostent*)NULL);
d->map = "hosts.byname";
sethostent(0);
if (d->domain ) {
/*
* try to yp_match it first
*/
name2 = name;
for (val=d->line; *name2; name2++)
*val++ = isupper((unsigned char)*name2) ? tolower(*name2) : *name2;
*val = '\0';
stat = yp_match(d->domain, d->map,
d->line, val - d->line, &val, &vallen);
switch (stat) {
case 0:
h_errno = 0;
p = interpret(val, vallen);
free(val);
return(p);
case YPERR_KEY:
h_errno = HOST_NOT_FOUND;
return(NULL);
case YPERR_NOMORE:
h_errno = TRY_AGAIN;
return(NULL);
}
}
/* yp_match said NIS isn't running or domain is null */
h_errno = HOST_NOT_FOUND;
_sethostent(0);
while (p = _gethostent()) {
if (strcasecmp(p->h_name, name) == 0) {
h_errno = 0;
break;
}
for (cp = p->h_aliases; *cp != 0; cp++)
if (strcasecmp(*cp, name) == 0) {
h_errno = 0;
goto found;
}
}
found:
endhostent();
return (p);
}
sethostent(f)
int f;
{
/*Doesn't open file if not needed*/
/*f!=0 -> makes it open file */
register struct hostdata *d = _hostdata();
if (d == 0)
return;
d->notusingyellow = 0; /*try yellow again if off*/
if (f) {
_sethostent(f);
return;
}
if (d->hostf)
rewind(d->hostf); /*if its open rewind it*/
if (d->current)
free(d->current);
d->current = NULL;
}
static _sethostent(f)
int f;
{
register struct hostdata *d = _hostdata();
if (d == 0)
return;
if (d->hostf == NULL)
d->hostf = fopen(HOSTDB, "r");
else
rewind(d->hostf);
if (d->current)
free(d->current);
d->current = NULL;
d->stayopen |= f;
}
endhostent()
{
register struct hostdata *d = _hostdata();
if (d == 0)
return;
if (d->current && !d->stayopen) {
free(d->current);
d->current = NULL;
}
if (d->hostf && !d->stayopen) {
(void) fclose(d->hostf);
d->hostf = NULL;
}
}
struct hostent *
gethostent()
{
register struct hostdata *d = _hostdata();
struct hostent *hp;
char *key = NULL, *val = NULL;
int keylen, vallen, stat;
if (d == 0)
return ((struct hostent*)NULL);
d->map = "hosts.byaddr";
if (d->domain && !(d->notusingyellow)) {
if (d->current == NULL) {
stat = yp_first(d->domain, d->map, &key, &keylen,
&val, &vallen);
} else {
stat = yp_next(d->domain, d->map,
d->current, d->currentlen, &key, &keylen,
&val, &vallen);
}
switch (stat) {
case YPERR_NOMORE:
return(NULL);
case YPERR_KEY:
return(NULL); /* first might return this*/
case 0:
if (d->current)
free(d->current);
d->current = key;
d->currentlen = keylen;
hp = interpret(val, vallen);
free(val);
return (hp);
}
/*All other cases mean no NIS!*/
d->notusingyellow = 1;
}
return(_gethostent()); /*The hard way*/
}
static struct hostent *
_gethostent()
{
register struct hostdata *d = _hostdata();
if (d->hostf == NULL && (d->hostf = fopen(HOSTDB, "r")) == NULL)
return (NULL);
if (fgets(d->line, BUFSIZ, d->hostf) == NULL)
return (NULL);
return (interpret(d->line, strlen(d->line)));
}
/*
* Take the line read from /etc/hosts or from the NIS map, and parse it
* into a hostent structure. Multiple lines are used to encode multiple
* addresses for the same name. This should only happen when NIS talks to
* the Domain Name Service, but it should not hurt to put it here.
*/
static struct hostent *
interpret(val, len)
char *val;
int len;
{
register struct hostdata *d = _hostdata();
char *p, *z;
register char *cp, **q;
int i;
if (d == 0)
return (0);
(void) strncpy(d->line, val, len);
p = d->line;
d->line[len] = '\n';
d->line[len+1] = '\0';
/*
* Note that these are recursive calls, and thus should only
* happen when reading /etc/hosts.
*/
if ((*p == '#') || (*p == '\n')) /* Check for special cases */
return (gethostent());
cp = strpbrk(p, "#\n");
if (cp == NULL)
return (gethostent());
z = cp;
if (*z == '#')
z = strpbrk(cp, "\n");
*cp = '\0';
/*
* This is what causes the blank line bug, we find the \n but no
* whitespace after it and return NULL. fixed by special casing the
* blank lines above.
*/
cp = strpbrk(p, " \t");
if (cp == NULL)
return (NULL);
*cp++ = '\0';
/* THIS STUFF IS INTERNET SPECIFIC */
d->addr_list[0] = d->hostaddr[0];
d->addr_list[1] = NULL;
d->host.h_addr_list = d->addr_list;
*((u_long *)d->hostaddr[0]) = inet_addr(p);
d->host.h_length = HOSTADDRSIZE;
d->host.h_addrtype = AF_INET;
while (*cp == ' ' || *cp == '\t')
cp++;
d->host.h_name = cp;
q = d->host.h_aliases = d->host_aliases;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q < &(d->host_aliases[MAXALIASES - 1]))
*q++ = cp;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
}
*q = NULL;
/*
* Reached end of the line -- see if there are any more lines.
* At this point, z points to the END of the first line (\n character),
* i is the index of addr_list[]. (We only look at the addresses)
*/
i = 1;
while (z) {
cp = z+1;
if (*cp == '\0')
break;
while (*cp == '\n' || *cp == ' ' || *cp == '\t')
cp++;
p = cp;
cp = strpbrk(cp, " \t\n");
if (cp == NULL)
break;
z = cp;
if (*cp != '\n')
z = strpbrk(cp, "\n");
*cp = '\0';
/*
* At this point p points to the start of the address,
* past any white space, cp points to the end, and
* z points to the end of the current line.
*/
d->addr_list[i] = d->hostaddr[i];
*((u_long *)d->hostaddr[i]) = inet_addr(p);
i++;
d->addr_list[i] = NULL;
}
return (&d->host);
}