|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T l
Length: 29040 (0x7170)
Types: TextFile
Names: »lookup.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦2fafebccf⟧ »EurOpenD3/mail/smail3.1.19.tar.Z«
└─⟦bcd2bc73f⟧
└─⟦this⟧ »src/lookup.c«
/* @(#)lookup.c 3.23 3/11/89 10:37:16 */
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*/
/*
* lookup.c:
* search for values corresponding to keys using a specified
* access method.
*
* external functions: open_database, close_database, lookup_database
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include "defs.h"
#ifdef HAVE_NDBM
# include <ndbm.h>
#else
# ifdef HAVE_DBM
# undef NULL
# include <dbm.h>
# undef NULL /* we aren't interested in dbm's NULL */
# define NULL 0
# endif
#endif
#ifdef UNIX_BSD
# include <sys/file.h>
#endif
#ifdef HAVE_YP
# include <setjmp.h>
# include <rpcsvc/ypclnt.h>
#endif
#include "smail.h"
#include "lookup.h"
#include "dys.h"
#include "exitcodes.h"
#ifndef DEPEND
# include "extern.h"
# include "debug.h"
#endif
/* functions local to this file */
static int bsearch_open();
static void bsearch_close();
static int bsearch_lookup();
static int lsearch_open();
static void lsearch_close();
static int lsearch_lookup();
#if defined(HAVE_DBM) || defined(HAVE_NDBM)
static int dbmbase_open();
static void dbmbase_close();
static int dbmbase_lookup();
#endif
#ifdef HAVE_YP
static int yp_open();
static void yp_close();
static int yp_lookup();
static int aliasyp_open();
static void aliasyp_close();
static int aliasyp_lookup();
#endif
/*
* the following structure defines the available access methods.
* Methods are identified by name when open_database is called.
*/
static struct proto {
char *proto; /* name of the access method */
int (*open)(); /* open database function */
void (*close)(); /* close database function */
int (*lookup)(); /* lookup in database function */
} protos[] = {
{ "bsearch", /* binary search */
bsearch_open, bsearch_close, bsearch_lookup },
{ "lsearch",
lsearch_open, lsearch_close, lsearch_lookup },
#if defined(HAVE_DBM) || defined(HAVE_NDBM)
{ "dbm", /* DBM database search */
dbmbase_open, dbmbase_close, dbmbase_lookup },
#endif
#ifdef HAVE_YP
{ "yp", /* YP remote database search */
yp_open, yp_close, yp_lookup },
{ "aliasyp", /* mail.aliases-style YP database */
aliasyp_open, aliasyp_close, aliasyp_lookup },
#endif
};
/* point to end of protos table */
struct proto *end_protos = protos + sizeof(protos)/sizeof(protos[0]);
/* generic form of structure returned by database open calls */
struct generic_db {
struct proto *proto; /* access method */
};
/*
* open_database - open a database of the specified type
*
* given a database name and an access method return a pointer to opaque
* data that can be used to access that database.
*
* return:
* FILE_SUCCEED
* if the open was successful. The database info will
* be stored in *db.
* FILE_AGAIN if the open failed but may succeed at a later time
* (e.g., a remote host is down right now). An error will
* be stored in *error.
* FILE_FAIL if an unrecoverable failure occured. An error will be
* stored in *error.
* FILE_NOMATCH
* if the database does not appear to exist.
*/
int
open_database(name, proto, retries, interval, statp, db, error)
char *name; /* name of database */
char *proto; /* access method name */
int retries; /* retry count */
int interval; /* retry interval */
struct stat *statp; /* return a stat buffer */
char **db; /* store open database info here */
char **error; /* store error message here */
{
register struct proto *pp;
for (pp = protos; pp < end_protos; pp++) {
if (EQ(proto, pp->proto)) {
/* found the requested access method */
return (*pp->open)(name, pp, retries, interval, statp, db, error);
}
}
/* access method was not found */
*error = "unknown proto";
return FILE_FAIL;
}
/*
* close_database - close an open database and free its resources
*/
void
close_database(priv)
char *priv; /* database's private data */
{
register struct generic_db *gp = (struct generic_db *)priv;
(*gp->proto->close)(gp);
}
/*
* lookup_database - find a value corresponding to a key
*
* given an open database, perform a lookup operation to find a match for
* a given key.
*
* Return:
* DB_SUCCEED if the lookup was successful. The matched value will
* be stored in *value.
* DB_NOMATCH if the lookup operation did not find a match for the key.
* DB_AGAIN if the lookup operation failed but may succeed at a later
* time (e.g., a remote host is down right now). An error
* will be stored in *error.
* DB_FAIL if an unrecoverable failure occured. An error will be
* stored in *error.
* FILE_AGAIN if the lookup operation failed because of an error accessing
* the file. The file should be considered unreachable until
* some later time.
* FILE_FAIL if the lookup operation failed because of a permanent error
* accessing the file. Retrying at a later time is not assumed
* to be possible.
*/
int
lookup_database(db, key, value, error)
char *db; /* open database */
char *key; /* search key */
char **value; /* store value here */
char **error; /* store error message here */
{
register struct generic_db *gdb = (struct generic_db *)db;
return (*gdb->proto->lookup)(gdb, key, value, error);
}
/*
* bsearch access method:
*
* access a file containing sorted lines of data. keys
* are at the start of each line followed by a colon and/or
* white space.
*/
/* private data: */
struct bsearch_db {
struct proto *proto; /* access method table entry */
char *name; /* name of file */
FILE *f; /* open file */
long size; /* size of file */
};
/* bsearch_open - open a sorted file */
static int
bsearch_open(name, proto, retries, interval, statp, db, error)
char *name; /* name of file */
struct proto *proto; /* access method */
int retries; /* retry count */
int interval; /* retry interval */
struct stat *statp; /* save stat results here */
char **db; /* store open database info here */
char **error; /* store error message here */
{
register struct bsearch_db *priv;
register FILE *f;
name = make_lib_fn(name);
if (name == NULL) {
*error = "No directory for file";
return FILE_FAIL;
}
f = fopen(name, "r");
if (f == NULL) {
int left = retries;
while (left-- > 0) {
(void) sleep(interval);
if (f = fopen(name, "r")) break;
}
if (f == NULL) {
if (errno == ENOENT) {
return FILE_NOMATCH;
}
*error = strerrno();
return FILE_FAIL;
}
}
#ifdef lock_fd_rd_wait
if (lock_fd_rd_wait(fileno(f)) < 0) {
return FILE_AGAIN;
}
#endif
/* seek to the end of the file */
(void) fseek(f, 0L, 2);
/* build the private data */
priv = (struct bsearch_db *)xmalloc(sizeof(*priv));
priv->proto = proto;
priv->name = name;
priv->f = f;
priv->size = ftell(f); /* remember the fseek() */
if (statp) {
(void) fstat(fileno(f), statp);
}
*db = (char *)priv;
return FILE_SUCCEED;
}
/* bsearch_close - close the file */
static void
bsearch_close(db)
struct bsearch_db *db;
{
(void) fclose(db->f);
xfree((char *)db);
}
/*
* bsearch_lookup - look up key in ascii sorted key/data line database.
*
* This routine taken from smail version 2.3, though it has been
* modified to work with the new version and has also been
* generalized from the original routine getpath().
*/
/*ARGSUSED*/
static int
bsearch_lookup(db, key, value, error)
register struct bsearch_db *db;
char *key;
char **value;
char **error;
{
long middle, hi, lo;
int c;
int flag;
int len = strlen(key); /* length of comparison */
static struct str str; /* string in which to store data */
static int str_inited = FALSE; /* TRUE if str has been STR_INIT'd */
int i; /* temp */
DEBUG1(DBG_DRIVER_HI, "bsearch_lookup: looking for <%s>\n", key);
if (!str_inited) {
/*
* note, the string is reused in each call to bsearch.
*/
str_inited = TRUE;
STR_INIT(&str);
}
lo = 0;
hi = db->size;
/*
* "Binary search routines are never written right the first time around."
* - Robert G. Sheldon.
* << above comment retained 'cause I thought it was cute -- tron >>
*/
for( ;; ) {
int cnt;
middle = (hi + lo + 1)/2;
(void) fseek(db->f, middle, 0); /* find midpoint */
if (middle != 0) { /* to beginning of next line */
while((c = getc(db->f)) != EOF && c != '\n') ;
if (c == EOF && ferror(db->f)) {
*error = strerrno();
return FILE_FAIL;
}
}
str.i = 0;
cnt = 0;
while (cnt <= len && (c = getc(db->f)) != EOF && c != '\n') {
STR_NEXT(&str, c);
cnt++;
}
if (c == EOF && ferror(db->f)) {
*error = strerrno();
return FILE_FAIL;
}
STR_NEXT(&str, '\0');
flag = strncmpic(str.p, key, len);
if (flag == 0) {
/* make sure the names are the same length */
if (str.p[len] == ':' || isspace(str.p[len])) {
break; /* found it */
}
flag = 1; /* name is longer than target */
}
if ( lo>=middle ) { /* failure? */
return DB_NOMATCH;
}
if ( c != EOF && flag < 0 ) { /* close window */
lo = middle;
} else {
hi = middle - 1;
}
}
/*
* Now just copy the result.
*/
i = -1; /* index to last non-space */
str.i = 0; /* clear out the region */
while(((c = getc(db->f)) != EOF) && (c != '\n')) {
if (!isspace(c)) {
if (c == '#') {
/* comment puts an end to the entry */
break;
}
i = str.i;
}
STR_NEXT(&str, c);
}
if (c == EOF && ferror(db->f)) {
*error = strerrno();
return FILE_FAIL;
}
str.i = i + 1; /* backup to last interesting char */
/* backup to last non-space character */
STR_NEXT(&str, '\0');
DEBUG2(DBG_DRIVER_HI, "bsearch_lookup: found <%s> for <%s>\n", str.p, key);
*value = str.p;
return DB_SUCCEED;
}
/*
* lsearch access method:
*
* access a file containing lines of data, in the format expected
* by read_entry() in parse.c. Keys are at the start of each line
* followed by a colon and/or white space.
*/
/* private data: */
struct lsearch_db {
struct proto *proto; /* access method table entry */
char *name; /* name of file */
FILE *f; /* open file */
};
/* lsearch_open - open a file */
static int
lsearch_open(name, proto, retries, interval, statp, db, error)
char *name; /* name of file */
struct proto *proto; /* access method */
int retries; /* retry count */
int interval; /* retry interval */
struct stat *statp; /* save stat results here */
char **db; /* store open database info here */
char **error; /* store error message here */
{
register struct lsearch_db *priv;
register FILE *f;
name = make_lib_fn(name);
if (name == NULL) {
*error = "No directory for file";
return FILE_FAIL;
}
f = fopen(name, "r");
if (f == NULL) {
int left = retries;
while (left-- > 0) {
(void) sleep(interval);
if (f = fopen(name, "r")) break;
}
if (f == NULL) {
if (errno == ENOENT) {
return FILE_NOMATCH;
}
*error = strerrno();
return FILE_FAIL;
}
}
#ifdef lock_fd_rd_wait
if (lock_fd_rd_wait(fileno(f)) < 0) {
return FILE_AGAIN;
}
#endif
/* build the private data */
priv = (struct lsearch_db *)xmalloc(sizeof(*priv));
priv->proto = proto;
priv->name = name;
priv->f = f;
if (statp) {
(void) fstat(fileno(f), statp);
}
*db = (char *)priv;
return FILE_SUCCEED;
}
/* lsearch_close - close the file */
static void
lsearch_close(db)
struct lsearch_db *db;
{
(void) fclose(db->f);
xfree((char *)db);
}
/*
* lsearch_lookup - look up key with a linear search
*/
/*ARGSUSED*/
static int
lsearch_lookup(db, key, value, error)
register struct lsearch_db *db;
char *key;
char **value;
char **error;
{
int len = strlen(key); /* length of comparison */
register char *entry; /* entry from read_entry() */
register char *p; /* temp */
DEBUG1(DBG_DRIVER_HI, "lsearch_lookup: looking for <%s>\n", key);
/* always start from the beginning of the file */
(void) fseek(db->f, 0L, 0);
while (entry = read_entry(db->f)) {
if (strncmpic(entry, key, len) == 0 &&
(entry[len] == ':' || isspace(entry[len])))
{
char *ret; /* value to be returned */
/* found a matching entry in the file, find the data */
entry += len;
/*
* skip <whitespace>:<whitespace>
*/
while (isspace(*entry)) entry++;
if (*entry == ':') {
entry++;
while (isspace(*entry)) entry++;
}
/*
* skip comments
*/
while (*entry == '#') {
while (*entry && *entry != '\n') entry++;
while (isspace(*entry)) entry++;
}
ret = entry; /* return from this point on */
/* though do some more processing to the remainder */
p = entry - 1;
/* find the last character which is not white-space or comment */
while (*entry) {
if (!isspace(*entry)) {
if (*entry == '#') {
while (*entry && *entry != '\n') entry++;
continue;
}
p = entry;
}
entry++;
}
/* throw away after the last interesting character */
p[1] = '\0';
DEBUG1(DBG_DRIVER_HI, "lsearch_lookup: return <%s>\n", ret);
*value = ret;
return DB_SUCCEED;
}
}
if (ferror(db->f)) {
*error = strerrno();
return FILE_FAIL;
}
DEBUG1(DBG_DRIVER_HI, "lsearch_lookup: did not find <%s>\n", key);
return DB_NOMATCH;
}
#if defined(HAVE_DBM) || defined(HAVE_NDBM)
/*
* dbmbase access method:
*
* access a database stored as a DBM database. Note that the
* DBM semantics only allow for one DBM file in the life of
* a process. As a result, these files should never be closed
* and only one reference to a DBM-type database can exist in
* the application.
*
* If NDBM is being used, then multiple databases can be used.
*
* BUGS: extensive use of #ifdef within functions is ugly.
*/
#ifdef HAVE_NDBM
/*
* form for private data:
*/
struct dbmbase_db {
struct proto *proto; /* access method table entry */
char *name; /* name of database */
DBM *db; /* open database */
};
#else /* not HAVE_NDBM */
/* private data:
* NOTE: we only allow for one data structure, which is held
* as a static object. */
static struct dbmbase_db {
struct proto *proto; /* access method table entry */
char *name; /* name of database */
struct stat statbuf; /* stat on .pag part of database */
} dbmbase_private = {
NULL, NULL, /* initialize to unopened state */
};
#endif /* not HAVE_NDBM */
/* dbmbase_open - open a DBM database */
static int
dbmbase_open(name, proto, retries, interval, statp, db, error)
char *name; /* name of database */
struct proto *proto; /* access method */
int retries; /* retry count */
int interval; /* retry interval */
struct stat *statp; /* return a stat structure */
char **db; /* store open database info here */
char **error; /* store error message here */
{
char *pag_file; /* name of .pag file */
register struct dbmbase_db *priv;
name = make_lib_fn(name);
if (name == NULL) {
*error = "No directory for file";
return FILE_FAIL;
}
#ifdef HAVE_NDBM
priv = (struct dbmbase_db *)xmalloc(sizeof(*priv));
#else /* not HAVE_NDBM */
priv = &dbmbase_private;
if (priv->name && !EQ(priv->name, name)) {
*error = "Can't have multiple DBM databases";
return FILE_FAIL;
}
if (priv->name == NULL) {
#endif /* not HAVE_NDBM */
if (
#ifdef HAVE_NDBM
(priv->db = dbm_open(name, 0)) == NULL
#else
dbminit(name) < 0
#endif
)
{
int succeed = FAIL;
int left = retries;
if (left < 1) {
/* DBM databases cannot be moved atomicly, so require
* at least two retries */
left = 2;
}
if (interval < 2) {
/* require a somewhat reasonable interval as well */
interval = 2;
}
while (left-- > 0) {
(void) sleep(interval);
#ifdef HAVE_NDBM
if (priv->db = dbm_open(name, 0)) {
succeed = SUCCEED;
break;
}
if (errno != ENOENT) {
break;
}
#else
if ((succeed = dbminit(name)) >= 0) {
break;
}
#endif
}
if (succeed != DB_SUCCEED) {
*error = strerrno();
return FILE_FAIL;
}
}
#ifdef HAVE_NDBM
/* if required, get a stat structure from the .pag file */
if (statp) {
pag_file = xmalloc(strlen(name) + sizeof(".pag"));
(void) sprintf(pag_file, "%s.pag", name);
(void) stat(pag_file, statp);
xfree(pag_file);
}
priv->proto = proto;
priv->name = name;
*db = (char *)priv;
#ifdef lock_fd_rd_wait
if (lock_fd_rd_wait(dbm_pagfno(priv->db)) < 0) {
return FILE_AGAIN;
}
#endif
return FILE_SUCCEED;
#else /* not HAVE_NDBM */
/* get a stat structure from the .pag file */
pag_file = xmalloc(strlen(name) + sizeof(".pag"));
(void) sprintf(pag_file, "%s.pag", name);
(void) stat(pag_file, &priv->statbuf);
xfree(pag_file);
}
priv->proto = proto;
priv->name = name;
if (statp) {
*statp = priv->statbuf;
}
*db = (char *)priv;
return FILE_SUCCEED;
#endif /* not HAVE_NDBM */
}
/* dbmbase_close - if not NDBM don't close the database, since we can't */
/*ARGSUSED*/
static void
dbmbase_close(db)
struct dbmbase_db *db;
{
#ifdef HAVE_NDBM
(void) dbm_close(db->db);
xfree((char *)db);
#endif
return;
}
/* dbmbase_lookup - call on the DBM routines to find that data */
/*ARGSUSED*/
static int
dbmbase_lookup(db, key, value, error)
register struct dbmbase_db *db;
char *key;
char **value;
char **error;
{
datum the_key;
datum the_value;
static int temp_size; /* size of temp_key area */
static char *temp_data = NULL; /* growable temp area */
int len; /* length of key */
register char *p;
/*
* convert the key to lower case, as fetch() is case-sensitive
* for efficiency, keep around the malloc'd region used to store
* the down-cased key.
*/
len = strlen(key) + 1;
if (temp_data == NULL) {
temp_size = len;
temp_data = xmalloc(temp_size);
} else if (temp_size < len) {
temp_size = len;
temp_data = xrealloc(temp_data, temp_size);
}
for (p = temp_data; *key; p++, key++) {
*p = lowercase(*key);
}
*p = '\0';
the_key.dptr = temp_data;
the_key.dsize = len;
#ifdef HAVE_NDBM
the_value = dbm_fetch(db->db, the_key);
if (dbm_error(db->db)) {
return FILE_FAIL;
}
#else
the_value = fetch(the_key);
#endif
if (the_value.dptr) {
if (temp_size < the_value.dsize + 1) {
temp_size = the_value.dsize + 1;
temp_data = xrealloc(temp_data, temp_size);
}
(void) strcpy(temp_data, the_value.dptr);
*value = temp_data;
return DB_SUCCEED;
}
return DB_NOMATCH;
}
#endif /* HAVE_DBM || HAVE_NDBM */
#ifdef HAVE_YP
/*
* The YP database routines takes names of the form:
*
* domain:database_name
* or database_name
*
* in the former case, the `domain' specified is the YP domain to use
* for yp_match operations. In the second case, the default YP domain
* is used.
*
* There are two forms for the lookup: regular yp and aliasyp. The
* second form is used for accessing the standard Sun mail.aliases map
* format, which does not fit the form of other YP maps. The
* difference is that a nul-byte is counted in the length of a key for
* mail.aliases, while it is not counted for other maps.
*/
/*
* form for private data:
*/
struct yp_db {
struct proto *proto; /* access method table entry */
char *map; /* name of database */
char *domain; /* yp domain */
};
static char *default_yp_domain = NULL; /* from yp_get_default_domain(3N) */
#ifdef notyet
static jmp_buf alarm_jmp; /* jump here on SIGALRM */
static void yp_sigalrm(); /* catch SIGALRM for YP timeouts */
#define YP_TIMEOUT 30 /* 30 second timeout for YP */
#endif
/*
* yp_open, aliasyp_open - create a yp_private structure for a database
*
* yp_order(3N) is called to verify that the database is accessible.
*/
static int
aliasyp_open(name, proto, retries, interval, statp, db, error)
char *name; /* name of database */
struct proto *proto; /* access method */
int retries; /* retry count */
int interval; /* retry interval */
struct stat *statp; /* return a stat structure */
char **db; /* store open database info here */
char **error; /* store error message here */
{
return yp_open(name, proto, retries, interval, statp, db, error);
}
/*ARGSUSED*/
static int
yp_open(name, proto, retries, interval, statp, db, error)
char *name; /* name of database */
struct proto *proto; /* access method */
int retries; /* retry count */
int interval; /* retry interval */
struct stat *statp; /* return a stat structure */
char **db; /* store open database info here */
char **error; /* store error message here */
{
register struct yp_db *priv;
register char *p;
int err; /* error from yp functions */
int order; /* output from yp_order */
char *domain;
#ifdef notyet
int save_time; /* saved value from alarm() */
void (*save_sigalrm)(); /* previous SIGALRM handler */
#endif
priv = (struct yp_db *)xmalloc(sizeof(*priv));
/* is a YP domain specified? */
p = index(name, ':');
if (p == NULL) {
/* no, use the default YP domain */
priv->domain = NULL;
priv->map = name;
} else {
/* yes, make a copy and use it */
priv->domain = xmalloc(p - name + 1);
(void) memcpy(priv->domain, name, p - name);
priv->domain[p - name] = '\0';
priv->map = p + 1;
}
/* if stat required, just zero it out, there is nothing to put there */
if (statp) {
(void) bzero((char *)statp, sizeof(*statp));
}
if (priv->domain) {
domain = priv->domain;
} else {
if (default_yp_domain == NULL &&
(err = yp_get_default_domain(&default_yp_domain)))
{
/* this should only fail if the domainname is not set, right? */
*error = yperr_string(err);
return FILE_FAIL;
}
domain = default_yp_domain;
}
#ifdef notyet
save_time = alarm(0);
/* verify that we can access the database */
if (setjmp(alarm_jmp)) {
(void) signal(SIGALRM, save_sigalrm);
(void) alarm(save_time);
*error = "YP timeout";
return FILE_AGAIN;
} else {
/* arrange to timeout if the operation blocks */
save_sigalrm = (void (*)())signal(SIGALRM, yp_sigalrm);
(void) alarm(YP_TIMEOUT);
#endif
/* potentially blocking operation */
err = yp_order(domain, priv->map, &order);
#ifdef notyet
/* restore previous alarm setting */
(void) signal(SIGALRM, save_sigalrm);
(void) alarm(save_time);
#endif
if (err) {
/* analyze the reason for the failure */
*error = yperr_string(err);
switch (err) {
case YPERR_RPC: /* cases where failure is temporary */
case YPERR_YPERR:
case YPERR_RESRC:
case YPERR_PMAP:
case YPERR_YPBIND:
case YPERR_YPSERV:
return FILE_AGAIN;
case YPERR_MAP: /* no such map */
case YPERR_DOMAIN: /* no such domain */
return FILE_NOMATCH;
}
return FILE_FAIL;
}
#ifdef notyet
}
#endif
priv->proto = proto;
*db = (char *)priv;
return FILE_SUCCEED;
}
/* yp_close, aliasyp_close - free up data allocated for to a YP database */
static void
aliasyp_close(db)
struct yp_db *db;
{
yp_close(db);
}
/*ARGSUSED*/
static void
yp_close(db)
struct yp_db *db;
{
if (db->domain) {
xfree(db->domain);
}
xfree((char *)db);
return;
}
/* yp_lookup, aliasyp_lookup - call on the YP routines to find that data */
static int
yp_lookup(db, key, value, error)
register struct yp_db *db; /* open YP database */
char *key; /* search key */
char **value; /* return value here */
char **error; /* return error message here */
{
return common_yp_lookup(db, key, value, error, FALSE);
}
static int
aliasyp_lookup(db, key, value, error)
register struct yp_db *db; /* open YP database */
char *key; /* search key */
char **value; /* return value here */
char **error; /* return error message here */
{
return common_yp_lookup(db, key, value, error, TRUE);
}
/*ARGSUSED*/
static int
common_yp_lookup(db, key, value, error, aliasflag)
register struct yp_db *db; /* open YP database */
char *key; /* search key */
char **value; /* return value here */
char **error; /* return error message here */
int aliasflag; /* TRUE for Sun mail.aliases format */
{
int keylen; /* length of key */
static char *temp_key = NULL; /* area for lower-case conversion */
static int temp_size; /* size of temp area */
register char *p;
char *matchval; /* matched data */
int matchlen; /* length of matched data */
int err; /* yp error */
char *domain;
#ifdef notyet
int save_time; /* saved value from alarm() */
void (*save_sigalrm)(); /* previous SIGALRM handler */
#endif
/*
* convert the key to lower case, as fetch() is case-sensitive
* for efficiency, keep around the malloc'd region used to store
* the down-cased key.
*/
keylen = strlen(key);
if (temp_key == NULL) {
temp_size = keylen + 1;
temp_key = xmalloc(temp_size);
} else if (temp_size <= keylen) {
temp_size = keylen + 1;
temp_key = xrealloc(temp_key, temp_size);
}
for (p = temp_key; *key; p++, key++) {
*p = lowercase(*key);
}
*p = '\0';
if (db->domain) {
domain = db->domain;
} else {
domain = default_yp_domain;
}
if (aliasflag) {
keylen++;
}
#ifdef notyet
save_time = alarm(0);
if (setjmp(alarm_jmp)) {
(void) signal(SIGALRM, save_sigalrm);
(void) alarm(save_time);
*error = "YP timeout";
return FILE_AGAIN;
} else {
/* arrange to timeout if the operation blocks */
save_sigalrm = (void (*)())signal(SIGALRM, yp_sigalrm);
(void) alarm(YP_TIMEOUT);
#endif
/* potentially blocking operation */
err = yp_match(domain, db->map, temp_key, keylen,
&matchval, &matchlen);
#ifdef notyet
/* restore previous alarm setting */
(void) signal(SIGALRM, save_sigalrm);
(void) alarm(save_time);
#endif
if (err) {
/* analyze the reason for the failure */
*error = yperr_string(err);
switch (err) {
case YPERR_RPC: /* cases where failure is temporary */
case YPERR_DOMAIN:
case YPERR_YPERR:
case YPERR_RESRC:
case YPERR_PMAP:
case YPERR_YPBIND:
case YPERR_YPSERV:
return FILE_AGAIN;
case YPERR_KEY: /* key not in database */
return DB_NOMATCH;
}
return FILE_FAIL;
}
#ifdef notyet
}
#endif
matchval[matchlen] = '\0'; /* we don't want the extra newline */
*value = matchval;
return DB_SUCCEED;
}
#ifdef notyet
static void
yp_sigalrm()
{
longjmp(alarm_jmp, 1);
}
#endif
#endif /* HAVE_YP */
#ifdef STANDALONE
int debug = 0;
FILE *errfile = stderr;
void
main(argc, argv)
int argc;
char **argv;
{
char *program = (--argc, *argv++);
char *proto;
char *name;
char *db;
char *error;
int interval = 3;
int retries = 0;
int success;
for (;;) {
if (*argv && EQ(*argv, "-r")) {
argv++;
retries = atoi(*argv++);
argc -= 2;
continue;
}
if (*argv && EQ(*argv, "-i")) {
argv++;
interval = atoi(*argv++);
argc -= 2;
continue;
}
break;
}
if (argc < 3) {
fprintf(stderr,
"Usage: %s [-r #retries] [-i interval] proto name key ...\n",
program);
exit(EX_USAGE);
}
proto = *argv++;
name = *argv++;
success = open_database(name, proto, retries, interval,
(struct stat *)NULL, &db, &error);
switch (success) {
case DB_AGAIN:
fprintf(stderr, "%s: try again later: %s\n", program, error);
exit(EX_TEMPFAIL);
case DB_FAIL:
fprintf(stderr, "%s: open failed: %s\n", program, error);
exit(EX_UNAVAILABLE);
}
while (*argv) {
char *value;
switch (lookup_database(db, *argv, &value, &error)) {
case DB_AGAIN:
fprintf(stderr, "%s: %s: try again later: %s\n",
program, *argv, error);
break;
case DB_FAIL:
fprintf(stderr, "%s: %s: failed: %s\n", program, *argv, error);
break;
case DB_NOMATCH:
fprintf(stderr, "%s: %s: no match\n", program, *argv);
break;
case DB_SUCCEED:
printf("%s --> %s", *argv, value);
break;
}
argv++;
}
close_database(db);
exit(EX_OK);
}
char *
xmalloc(size)
int size;
{
char *malloc();
return malloc(size);
}
char *
xrealloc(region, size)
char *region;
int size;
{
char *realloc();
return realloc(region, size);
}
void
xfree(region)
char *region;
{
(void) free(region);
}
#endif /* STANDALONE */