📄 map.c
字号:
/* * Copyright (c) 1992 Eric P. Allman. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)map.c 8.25 (Berkeley) 4/17/94";#endif /* not lint */#include "sendmail.h"#ifdef NDBM#include <ndbm.h>#endif#ifdef NEWDB#include <db.h>#endif#ifdef NIS#include <rpcsvc/ypclnt.h>#endif/*** MAP.C -- implementations for various map classes.**** Each map class implements a series of functions:**** bool map_parse(MAP *map, char *args)** Parse the arguments from the config file. Return TRUE** if they were ok, FALSE otherwise. Fill in map with the** values.**** char *map_lookup(MAP *map, char *key, char **args, int *pstat)** Look up the key in the given map. If found, do any** rewriting the map wants (including "args" if desired)** and return the value. Set *pstat to the appropriate status** on error and return NULL. Args will be NULL if called** from the alias routines, although this should probably** not be relied upon. It is suggested you call map_rewrite** to return the results -- it takes care of null termination** and uses a dynamically expanded buffer as needed.**** void map_store(MAP *map, char *key, char *value)** Store the key:value pair in the map.**** bool map_open(MAP *map, int mode)** Open the map for the indicated mode. Mode should** be either O_RDONLY or O_RDWR. Return TRUE if it** was opened successfully, FALSE otherwise. If the open** failed an the MF_OPTIONAL flag is not set, it should** also print an error. If the MF_ALIAS bit is set** and this map class understands the @:@ convention, it** should call aliaswait() before returning.**** void map_close(MAP *map)** Close the map.*/#define DBMMODE 0644extern bool aliaswait __P((MAP *, char *, int));/*** MAP_PARSEARGS -- parse config line arguments for database lookup**** This is a generic version of the map_parse method.**** Parameters:** map -- the map being initialized.** ap -- a pointer to the args on the config line.**** Returns:** TRUE -- if everything parsed OK.** FALSE -- otherwise.**** Side Effects:** null terminates the filename; stores it in map*/boolmap_parseargs(map, ap) MAP *map; char *ap;{ register char *p = ap; map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; for (;;) { while (isascii(*p) && isspace(*p)) p++; if (*p != '-') break; switch (*++p) { case 'N': map->map_mflags |= MF_INCLNULL; map->map_mflags &= ~MF_TRY0NULL; break; case 'O': map->map_mflags &= ~MF_TRY1NULL; break; case 'o': map->map_mflags |= MF_OPTIONAL; break; case 'f': map->map_mflags |= MF_NOFOLDCASE; break; case 'm': map->map_mflags |= MF_MATCHONLY; break; case 'a': map->map_app = ++p; break; } while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; if (*p != '\0') *p++ = '\0'; } if (map->map_app != NULL) map->map_app = newstr(map->map_app); if (*p != '\0') { map->map_file = p; while (*p != '\0' && !(isascii(*p) && isspace(*p))) p++; if (*p != '\0') *p++ = '\0'; map->map_file = newstr(map->map_file); } while (*p != '\0' && isascii(*p) && isspace(*p)) p++; if (*p != '\0') map->map_rebuild = newstr(p); if (map->map_file == NULL) { syserr("No file name for %s map %s", map->map_class->map_cname, map->map_mname); return FALSE; } return TRUE;}/*** MAP_REWRITE -- rewrite a database key, interpolating %n indications.**** It also adds the map_app string. It can be used as a utility** in the map_lookup method.**** Parameters:** map -- the map that causes this.** s -- the string to rewrite, NOT necessarily null terminated.** slen -- the length of s.** av -- arguments to interpolate into buf.**** Returns:** Pointer to rewritten result.**** Side Effects:** none.*/struct rwbuf{ int rwb_len; /* size of buffer */ char *rwb_buf; /* ptr to buffer */};struct rwbuf RwBufs[2]; /* buffers for rewriting output */char *map_rewrite(map, s, slen, av) register MAP *map; register char *s; int slen; char **av;{ register char *bp; register char c; char **avp; register char *ap; register struct rwbuf *rwb; int i; int len; if (tTd(39, 1)) { printf("map_rewrite(%.*s), av =", slen, s); if (av == NULL) printf(" (nullv)"); else { for (avp = av; *avp != NULL; avp++) printf("\n\t%s", *avp); } printf("\n"); } rwb = RwBufs; if (av == NULL) rwb++; /* count expected size of output (can safely overestimate) */ i = len = slen; if (av != NULL) { bp = s; for (i = slen; --i >= 0 && (c = *bp++) != 0; ) { if (c != '%') continue; if (--i < 0) break; c = *bp++; if (!(isascii(c) && isdigit(c))) continue; for (avp = av; --c >= '0' && *avp != NULL; avp++) continue; if (*avp == NULL) continue; len += strlen(*avp); } } if (map->map_app != NULL) len += strlen(map->map_app); if (rwb->rwb_len < ++len) { /* need to malloc additional space */ rwb->rwb_len = len; if (rwb->rwb_buf != NULL) free(rwb->rwb_buf); rwb->rwb_buf = xalloc(rwb->rwb_len); } bp = rwb->rwb_buf; if (av == NULL) { bcopy(s, bp, slen); bp += slen; } else { while (--slen >= 0 && (c = *s++) != '\0') { if (c != '%') { pushc: *bp++ = c; continue; } if (--slen < 0 || (c = *s++) == '\0') c = '%'; if (c == '%') goto pushc; if (!(isascii(c) && isdigit(c))) { *bp++ = '%'; goto pushc; } for (avp = av; --c >= '0' && *avp != NULL; avp++) continue; if (*avp == NULL) continue; /* transliterate argument into output string */ for (ap = *avp; (c = *ap++) != '\0'; ) *bp++ = c; } } if (map->map_app != NULL) strcpy(bp, map->map_app); else *bp = '\0'; if (tTd(39, 1)) printf("map_rewrite => %s\n", rwb->rwb_buf); return rwb->rwb_buf;}/*** INITMAPS -- initialize for aliasing**** Parameters:** rebuild -- if TRUE, this rebuilds the cached versions.** e -- current envelope.**** Returns:** none.**** Side Effects:** initializes aliases:** if NDBM: opens the database.** if ~NDBM: reads the aliases into the symbol table.*/initmaps(rebuild, e) bool rebuild; register ENVELOPE *e;{ extern void map_init();#ifdef XDEBUG checkfd012("entering initmaps");#endif CurEnv = e; if (rebuild) { stabapply(map_init, 1); stabapply(map_init, 2); } else { stabapply(map_init, 0); }#ifdef XDEBUG checkfd012("exiting initmaps");#endif}voidmap_init(s, rebuild) register STAB *s; int rebuild;{ register MAP *map; /* has to be a map */ if (s->s_type != ST_MAP) return; map = &s->s_map; if (!bitset(MF_VALID, map->map_mflags)) return; if (tTd(38, 2)) printf("map_init(%s:%s, %d)\n", map->map_class->map_cname == NULL ? "NULL" : map->map_class->map_cname, map->map_file == NULL ? "NULL" : map->map_file, rebuild); if (rebuild == (bitset(MF_ALIAS, map->map_mflags) && bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2)) { if (tTd(38, 3)) printf("\twrong pass\n"); return; } /* if already open, close it (for nested open) */ if (bitset(MF_OPEN, map->map_mflags)) { map->map_class->map_close(map); map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); } if (rebuild == 2) { rebuildaliases(map, FALSE); } else { if (map->map_class->map_open(map, O_RDONLY)) { if (tTd(38, 4)) printf("\t%s:%s: valid\n", map->map_class->map_cname == NULL ? "NULL" : map->map_class->map_cname, map->map_file == NULL ? "NULL" : map->map_file); map->map_mflags |= MF_OPEN; } else if (tTd(38, 4)) printf("\t%s:%s: invalid: %s\n", map->map_class->map_cname == NULL ? "NULL" : map->map_class->map_cname, map->map_file == NULL ? "NULL" : map->map_file, errstring(errno)); }}/*** NDBM modules*/#ifdef NDBM/*** DBM_MAP_OPEN -- DBM-style map open*/boolndbm_map_open(map, mode) MAP *map; int mode;{ register DBM *dbm; struct stat st; if (tTd(38, 2)) printf("ndbm_map_open(%s, %d)\n", map->map_file, mode); if (mode == O_RDWR) mode |= O_CREAT|O_TRUNC; /* open the database */ dbm = dbm_open(map->map_file, mode, DBMMODE); if (dbm == NULL) {#ifdef MAYBENEXTRELEASE if (aliaswait(map, ".pag", FALSE)) return TRUE;#endif if (!bitset(MF_OPTIONAL, map->map_mflags)) syserr("Cannot open DBM database %s", map->map_file); return FALSE; } map->map_db1 = (void *) dbm; if (mode == O_RDONLY) { if (bitset(MF_ALIAS, map->map_mflags) && !aliaswait(map, ".pag", TRUE)) return FALSE; } else { int fd; /* exclusive lock for duration of rebuild */ fd = dbm_dirfno((DBM *) map->map_db1); if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && lockfile(fd, map->map_file, ".dir", LOCK_EX)) map->map_mflags |= MF_LOCKED; } if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) map->map_mtime = st.st_mtime; return TRUE;}/*** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map*/char *ndbm_map_lookup(map, name, av, statp) MAP *map; char *name; char **av; int *statp;{ datum key, val; int fd; char keybuf[MAXNAME + 1]; if (tTd(38, 20)) printf("ndbm_map_lookup(%s)\n", name); key.dptr = name; key.dsize = strlen(name); if (!bitset(MF_NOFOLDCASE, map->map_mflags)) { if (key.dsize > sizeof keybuf - 1) key.dsize = sizeof keybuf - 1; bcopy(key.dptr, keybuf, key.dsize + 1); makelower(keybuf); key.dptr = keybuf; } fd = dbm_dirfno((DBM *) map->map_db1); if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); val.dptr = NULL; if (bitset(MF_TRY0NULL, map->map_mflags)) { val = dbm_fetch((DBM *) map->map_db1, key); if (val.dptr != NULL) map->map_mflags &= ~MF_TRY1NULL; } if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) { key.dsize++; val = dbm_fetch((DBM *) map->map_db1, key); if (val.dptr != NULL) map->map_mflags &= ~MF_TRY0NULL; } if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); if (val.dptr == NULL) return NULL; if (bitset(MF_MATCHONLY, map->map_mflags)) return map_rewrite(map, name, strlen(name), NULL); else return map_rewrite(map, val.dptr, val.dsize, av);}/*** DBM_MAP_STORE -- store a datum in the database*/voidndbm_map_store(map, lhs, rhs) register MAP *map; char *lhs; char *rhs;{ datum key; datum data; int stat; if (tTd(38, 12)) printf("ndbm_map_store(%s, %s)\n", lhs, rhs); key.dsize = strlen(lhs); key.dptr = lhs; data.dsize = strlen(rhs); data.dptr = rhs; if (bitset(MF_INCLNULL, map->map_mflags)) { key.dsize++; data.dsize++; } stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); if (stat > 0) { usrerr("050 Warning: duplicate alias name %s", lhs); stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); } if (stat != 0) syserr("readaliases: dbm put (%s)", lhs);}/*** NDBM_MAP_CLOSE -- close the database*/voidndbm_map_close(map) register MAP *map;{ if (tTd(38, 9)) printf("ndbm_map_close(%s, %x)\n", map->map_file, map->map_mflags); if (bitset(MF_WRITABLE, map->map_mflags)) {#ifdef NIS bool inclnull; char buf[200]; inclnull = bitset(MF_INCLNULL, map->map_mflags); map->map_mflags &= ~MF_INCLNULL; (void) sprintf(buf, "%010ld", curtime()); ndbm_map_store(map, "YP_LAST_MODIFIED", buf); (void) gethostname(buf, sizeof buf); ndbm_map_store(map, "YP_MASTER_NAME", buf); if (inclnull) map->map_mflags |= MF_INCLNULL;#endif /* write out the distinguished alias */ ndbm_map_store(map, "@", "@"); } dbm_close((DBM *) map->map_db1);}#endif/*** NEWDB (Hash and BTree) Modules*/#ifdef NEWDB/*** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.**** These do rather bizarre locking. If you can lock on open,** do that to avoid the condition of opening a database that** is being rebuilt. If you don't, we'll try to fake it, but** there will be a race condition. If opening for read-only,** we immediately release the lock to avoid freezing things up.** We really ought to hold the lock, but guarantee that we won't** be pokey about it. That's hard to do.*/boolbt_map_open(map, mode) MAP *map; int mode;{ DB *db; int i; int omode; int fd; struct stat st; char buf[MAXNAME]; if (tTd(38, 2)) printf("bt_map_open(%s, %d)\n", map->map_file, mode); omode = mode; if (omode == O_RDWR) { omode |= O_CREAT|O_TRUNC;#if defined(O_EXLOCK) && HASFLOCK omode |= O_EXLOCK;# if !OLD_NEWDB } else { omode |= O_SHLOCK;# endif#endif } (void) strcpy(buf, map->map_file); i = strlen(buf); if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) (void) strcat(buf, ".db"); db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); if (db == NULL) {#ifdef MAYBENEXTRELEASE if (aliaswait(map, ".db", FALSE)) return TRUE;#endif if (!bitset(MF_OPTIONAL, map->map_mflags)) syserr("Cannot open BTREE database %s", map->map_file); return FALSE; }#if !OLD_NEWDB && HASFLOCK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -