This is lookup.c in view mode; [Download] [Up]
/* @(#)src/lookup.c 1.2 24 Oct 1990 05:23:27 */ /* * 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 */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.