Sync usage with man page.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / dict.c
blob42bf38bfd76401f1ea4765fbb5cb5dc288334887
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* dict 3
6 /* SUMMARY
7 /* dictionary manager
8 /* SYNOPSIS
9 /* #include <dict.h>
11 /* extern int dict_unknown_allowed;
12 /* extern int dict_errno;
14 /* void dict_register(dict_name, dict_info)
15 /* const char *dict_name;
16 /* DICT *dict_info;
18 /* DICT *dict_handle(dict_name)
19 /* const char *dict_name;
21 /* void dict_unregister(dict_name)
22 /* const char *dict_name;
24 /* void dict_update(dict_name, member, value)
25 /* const char *dict_name;
26 /* const char *member;
27 /* const char *value;
29 /* const char *dict_lookup(dict_name, member)
30 /* const char *dict_name;
31 /* const char *member;
33 /* int dict_delete(dict_name, member)
34 /* const char *dict_name;
35 /* const char *member;
37 /* int dict_sequence(dict_name, func, member, value)
38 /* const char *dict_name;
39 /* int func;
40 /* const char **member;
41 /* const char **value;
43 /* const char *dict_eval(dict_name, string, int recursive)
44 /* const char *dict_name;
45 /* const char *string;
46 /* int recursive;
48 /* int dict_walk(action, context)
49 /* void (*action)(dict_name, dict_handle, context)
50 /* char *context;
52 /* const char *dict_changed_name()
53 /* AUXILIARY FUNCTIONS
54 /* void dict_load_file(dict_name, path)
55 /* const char *dict_name;
56 /* const char *path;
58 /* void dict_load_fp(dict_name, fp)
59 /* const char *dict_name;
60 /* VSTREAM *fp;
62 /* const char *dict_flags_str(dict_flags)
63 /* int dict_flags;
64 /* DESCRIPTION
65 /* This module maintains a collection of name-value dictionaries.
66 /* Each dictionary has its own name and has its own methods to read
67 /* or update members. Examples of dictionaries that can be accessed
68 /* in this manner are the global UNIX-style process environment,
69 /* hash tables, NIS maps, DBM files, and so on. Dictionary values
70 /* are not limited to strings but can be arbitrary objects as long
71 /* as they can be represented by character pointers.
72 /* FEATURES
73 /* .fi
74 /* .ad
75 /* Notable features of this module are:
76 /* .IP "macro expansion (string-valued dictionaries only)"
77 /* Macros of the form $\fIname\fR can be expanded to the current
78 /* value of \fIname\fR. The forms $(\fIname\fR) and ${\fIname\fR} are
79 /* also supported.
80 /* .IP "unknown names"
81 /* References to unknown dictionary or dictionary member names either
82 /* default to an empty dictionary or null pointer value, or cause a
83 /* run-time error. The behavior is controlled by the global
84 /* \fIdict_unknown_allowed\fR boolean variable.
85 /* .PP
86 /* dict_register() adds a new dictionary, including access methods,
87 /* to the list of known dictionaries, or increments the reference
88 /* count for an existing (name, dictionary) pair. Otherwise, it is
89 /* an error to pass an existing name (this would cause a memory leak).
91 /* dict_handle() returns the generic dictionary handle of the
92 /* named dictionary, or a null pointer when the named dictionary
93 /* is not found.
95 /* dict_unregister() decrements the reference count of the named
96 /* dictionary. When the reference count reaches zero, dict_unregister()
97 /* breaks the (name, dictionary) association and executes the
98 /* dictionary's optional \fIremove\fR method.
100 /* dict_update() updates the value of the named dictionary member.
101 /* The dictionary member and the named dictionary are instantiated
102 /* on the fly.
104 /* dict_lookup() returns the value of the named member (i.e. without
105 /* expanding macros in the member value). The \fIdict_name\fR argument
106 /* specifies the dictionary to search. The result is a null pointer
107 /* when no value is found, otherwise the result is owned by the
108 /* underlying dictionary method. Make a copy if the result is to be
109 /* modified, or if the result is to survive multiple dict_lookup() calls.
111 /* dict_delete() removes the named member from the named dictionary.
112 /* The result is non-zero when the member does not exist.
114 /* dict_sequence() steps throuh the named dictionary and returns
115 /* keys and values in some implementation-defined order. The func
116 /* argument is DICT_SEQ_FUN_FIRST to set the cursor to the first
117 /* entry or DICT_SEQ_FUN_NEXT to select the next entry. The result
118 /* is owned by the underlying dictionary method. Make a copy if the
119 /* result is to be modified, or if the result is to survive multiple
120 /* dict_sequence() calls.
122 /* dict_eval() expands macro references in the specified string.
123 /* The result is owned by the dictionary manager. Make a copy if the
124 /* result is to survive multiple dict_eval() calls. When the
125 /* \fIrecursive\fR argument is non-zero, macro references in macro
126 /* lookup results are expanded recursively.
128 /* dict_walk() iterates over all registered dictionaries in some
129 /* arbitrary order, and invokes the specified action routine with
130 /* as arguments:
131 /* .IP "const char *dict_name"
132 /* Dictionary name.
133 /* .IP "DICT *dict_handle"
134 /* Generic dictionary handle.
135 /* .IP "char *context"
136 /* Application context from the caller.
137 /* .PP
138 /* dict_changed_name() returns non-zero when any dictionary needs to
139 /* be re-opened because it has changed or because it was unlinked.
140 /* A non-zero result is the name of a changed dictionary.
142 /* dict_load_file() reads name-value entries from the named file.
143 /* Lines that begin with whitespace are concatenated to the preceding
144 /* line (the newline is deleted).
145 /* Each entry is stored in the dictionary named by \fIdict_name\fR.
147 /* dict_load_fp() reads name-value entries from an open stream.
148 /* It has the same semantics as the dict_load_file() function.
150 /* dict_flags_str() returns a printable representation of the
151 /* specified dictionary flags. The result is overwritten upon
152 /* each call.
153 /* SEE ALSO
154 /* htable(3)
155 /* BUGS
156 /* DIAGNOSTICS
157 /* Fatal errors: out of memory, reference to unknown name,
158 /* malformed macro name.
160 /* The lookup routines may set the \fIdict_errno\fR variable when
161 /* they were unable to find the requested result. The lookup
162 /* routines must reset \fIdict_errno\fR before each lookup operation.
163 /* \fIdict_errno\fR can have the following values:
164 /* .IP DICT_ERR_RETRY
165 /* The dictionary was temporarily unavailable. This can happen
166 /* with network-based services.
167 /* LICENSE
168 /* .ad
169 /* .fi
170 /* The Secure Mailer license must be distributed with this software.
171 /* AUTHOR(S)
172 /* Wietse Venema
173 /* IBM T.J. Watson Research
174 /* P.O. Box 704
175 /* Yorktown Heights, NY 10598, USA
176 /*--*/
178 /* System libraries. */
180 #include "sys_defs.h"
181 #include <sys/stat.h>
182 #include <fcntl.h>
183 #include <ctype.h>
184 #include <string.h>
185 #include <time.h>
187 /* Utility library. */
189 #include "msg.h"
190 #include "htable.h"
191 #include "mymalloc.h"
192 #include "vstream.h"
193 #include "vstring.h"
194 #include "readlline.h"
195 #include "mac_expand.h"
196 #include "stringops.h"
197 #include "iostuff.h"
198 #include "name_mask.h"
199 #include "dict.h"
200 #include "dict_ht.h"
203 * By default, use a sane default for an unknown name.
205 int dict_unknown_allowed = 1;
206 int dict_errno = 0;
208 static HTABLE *dict_table;
211 * Each (name, dictionary) instance has a reference count. The count is part
212 * of the name, not the dictionary. The same dictionary may be registered
213 * under multiple names. The structure below keeps track of instances and
214 * reference counts.
216 typedef struct {
217 DICT *dict;
218 int refcount;
219 } DICT_NODE;
221 #define dict_node(dict) \
222 (dict_table ? (DICT_NODE *) htable_find(dict_table, dict) : 0)
224 #define STR(x) vstring_str(x)
226 /* dict_register - make association with dictionary */
228 void dict_register(const char *dict_name, DICT *dict_info)
230 const char *myname = "dict_register";
231 DICT_NODE *node;
233 if (dict_table == 0)
234 dict_table = htable_create(0);
235 if ((node = dict_node(dict_name)) == 0) {
236 node = (DICT_NODE *) mymalloc(sizeof(*node));
237 node->dict = dict_info;
238 node->refcount = 0;
239 htable_enter(dict_table, dict_name, (char *) node);
240 } else if (dict_info != node->dict)
241 msg_fatal("%s: dictionary name exists: %s", myname, dict_name);
242 node->refcount++;
243 if (msg_verbose > 1)
244 msg_info("%s: %s %d", myname, dict_name, node->refcount);
247 /* dict_handle - locate generic dictionary handle */
249 DICT *dict_handle(const char *dict_name)
251 DICT_NODE *node;
253 return ((node = dict_node(dict_name)) != 0 ? node->dict : 0);
256 /* dict_node_free - dict_unregister() callback */
258 static void dict_node_free(char *ptr)
260 DICT_NODE *node = (DICT_NODE *) ptr;
261 DICT *dict = node->dict;
263 if (dict->close)
264 dict->close(dict);
265 myfree((char *) node);
268 /* dict_unregister - break association with named dictionary */
270 void dict_unregister(const char *dict_name)
272 const char *myname = "dict_unregister";
273 DICT_NODE *node;
275 if ((node = dict_node(dict_name)) == 0)
276 msg_panic("non-existing dictionary: %s", dict_name);
277 if (msg_verbose > 1)
278 msg_info("%s: %s %d", myname, dict_name, node->refcount);
279 if (--(node->refcount) == 0)
280 htable_delete(dict_table, dict_name, dict_node_free);
283 /* dict_update - replace or add dictionary entry */
285 void dict_update(const char *dict_name, const char *member, const char *value)
287 const char *myname = "dict_update";
288 DICT_NODE *node;
289 DICT *dict;
291 if ((node = dict_node(dict_name)) == 0) {
292 if (dict_unknown_allowed == 0)
293 msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
294 dict = dict_ht_open(dict_name, htable_create(0), myfree);
295 dict_register(dict_name, dict);
296 } else
297 dict = node->dict;
298 if (msg_verbose > 1)
299 msg_info("%s: %s = %s", myname, member, value);
300 dict->update(dict, member, value);
303 /* dict_lookup - look up dictionary entry */
305 const char *dict_lookup(const char *dict_name, const char *member)
307 const char *myname = "dict_lookup";
308 DICT_NODE *node;
309 DICT *dict;
310 const char *ret = 0;
312 if ((node = dict_node(dict_name)) == 0) {
313 if (dict_unknown_allowed == 0)
314 msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
315 } else {
316 dict = node->dict;
317 ret = dict->lookup(dict, member);
318 if (ret == 0 && dict_unknown_allowed == 0)
319 msg_fatal("dictionary %s: unknown member: %s", dict_name, member);
321 if (msg_verbose > 1)
322 msg_info("%s: %s = %s", myname, member, ret ? ret : "(notfound)");
323 return (ret);
326 /* dict_delete - delete dictionary entry */
328 int dict_delete(const char *dict_name, const char *member)
330 const char *myname = "dict_delete";
331 DICT_NODE *node;
332 DICT *dict;
333 int result;
335 if ((node = dict_node(dict_name)) == 0) {
336 if (dict_unknown_allowed == 0)
337 msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
338 dict = dict_ht_open(dict_name, htable_create(0), myfree);
339 dict_register(dict_name, dict);
340 } else
341 dict = node->dict;
342 if (msg_verbose > 1)
343 msg_info("%s: delete %s", myname, member);
344 if ((result = dict->delete(dict, member)) != 0 && dict_unknown_allowed == 0)
345 msg_fatal("%s: dictionary %s: unknown member: %s",
346 myname, dict_name, member);
347 return (result);
350 /* dict_sequence - traverse dictionary */
352 int dict_sequence(const char *dict_name, const int func,
353 const char **member, const char **value)
355 const char *myname = "dict_sequence";
356 DICT_NODE *node;
357 DICT *dict;
359 if ((node = dict_node(dict_name)) == 0) {
360 if (dict_unknown_allowed == 0)
361 msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
362 dict = dict_ht_open(dict_name, htable_create(0), myfree);
363 dict_register(dict_name, dict);
364 } else
365 dict = node->dict;
366 if (msg_verbose > 1)
367 msg_info("%s: sequence func %d", myname, func);
368 return (dict->sequence(dict, func, member, value));
371 /* dict_load_file - read entries from text file */
373 void dict_load_file(const char *dict_name, const char *path)
375 VSTREAM *fp;
376 struct stat st;
377 time_t before;
378 time_t after;
381 * Read the file again if it is hot. This may result in reading a partial
382 * parameter name when a file changes in the middle of a read.
384 for (before = time((time_t *) 0); /* see below */ ; before = after) {
385 if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
386 msg_fatal("open %s: %m", path);
387 dict_load_fp(dict_name, fp);
388 if (fstat(vstream_fileno(fp), &st) < 0)
389 msg_fatal("fstat %s: %m", path);
390 if (vstream_ferror(fp) || vstream_fclose(fp))
391 msg_fatal("read %s: %m", path);
392 after = time((time_t *) 0);
393 if (st.st_mtime < before - 1 || st.st_mtime > after)
394 break;
395 if (msg_verbose)
396 msg_info("pausing to let %s cool down", path);
397 doze(300000);
401 /* dict_load_fp - read entries from open stream */
403 void dict_load_fp(const char *dict_name, VSTREAM *fp)
405 VSTRING *buf;
406 char *member;
407 char *val;
408 int lineno;
409 const char *err;
411 buf = vstring_alloc(100);
412 lineno = 0;
414 while (readlline(buf, fp, &lineno)) {
415 if ((err = split_nameval(STR(buf), &member, &val)) != 0)
416 msg_fatal("%s, line %d: %s: \"%s\"",
417 VSTREAM_PATH(fp), lineno, err, STR(buf));
418 dict_update(dict_name, member, val);
420 vstring_free(buf);
423 /* dict_eval_lookup - macro parser call-back routine */
425 static const char *dict_eval_lookup(const char *key, int unused_type,
426 char *dict_name)
428 const char *pp;
431 * XXX how would one recover?
433 if ((pp = dict_lookup(dict_name, key)) == 0 && dict_errno != 0)
434 msg_fatal("dictionary %s: lookup %s: temporary error", dict_name, key);
436 return (pp);
439 /* dict_eval - expand embedded dictionary references */
441 const char *dict_eval(const char *dict_name, const char *value, int recursive)
443 const char *myname = "dict_eval";
444 static VSTRING *buf;
445 int status;
448 * Initialize.
450 if (buf == 0)
451 buf = vstring_alloc(10);
454 * Expand macros, possibly recursively.
456 #define DONT_FILTER (char *) 0
458 status = mac_expand(buf, value,
459 recursive ? MAC_EXP_FLAG_RECURSE : MAC_EXP_FLAG_NONE,
460 DONT_FILTER, dict_eval_lookup, (char *) dict_name);
461 if (status & MAC_PARSE_ERROR)
462 msg_fatal("dictionary %s: macro processing error", dict_name);
463 if (msg_verbose) {
464 if (strcmp(value, STR(buf)) != 0)
465 msg_info("%s: expand %s -> %s", myname, value, STR(buf));
466 else
467 msg_info("%s: const %s", myname, value);
469 return (STR(buf));
472 /* dict_walk - iterate over all dictionaries in arbitrary order */
474 void dict_walk(DICT_WALK_ACTION action, char *ptr)
476 HTABLE_INFO **ht_info_list;
477 HTABLE_INFO **ht;
478 HTABLE_INFO *h;
480 ht_info_list = htable_list(dict_table);
481 for (ht = ht_info_list; (h = *ht) != 0; ht++)
482 action(h->key, (DICT *) h->value, ptr);
483 myfree((char *) ht_info_list);
486 /* dict_changed_name - see if any dictionary has changed */
488 const char *dict_changed_name(void)
490 const char *myname = "dict_changed_name";
491 struct stat st;
492 HTABLE_INFO **ht_info_list;
493 HTABLE_INFO **ht;
494 HTABLE_INFO *h;
495 const char *status;
496 DICT *dict;
498 ht_info_list = htable_list(dict_table);
499 for (status = 0, ht = ht_info_list; status == 0 && (h = *ht) != 0; ht++) {
500 dict = ((DICT_NODE *) h->value)->dict;
501 if (dict->stat_fd < 0) /* not file-based */
502 continue;
503 if (dict->mtime == 0) /* not bloody likely */
504 msg_warn("%s: table %s: null time stamp", myname, h->key);
505 if (fstat(dict->stat_fd, &st) < 0)
506 msg_fatal("%s: fstat: %m", myname);
507 if (st.st_mtime != dict->mtime || st.st_nlink == 0)
508 status = h->key;
510 myfree((char *) ht_info_list);
511 return (status);
514 /* dict_changed - backwards compatibility */
516 int dict_changed(void)
518 return (dict_changed_name() != 0);
522 * Mapping between flag names and flag values.
524 static const NAME_MASK dict_mask[] = {
525 "warn_dup", (1 << 0), /* if file, warn about dups */
526 "ignore_dup", (1 << 1), /* if file, ignore dups */
527 "try0null", (1 << 2), /* do not append 0 to key/value */
528 "try1null", (1 << 3), /* append 0 to key/value */
529 "fixed", (1 << 4), /* fixed key map */
530 "pattern", (1 << 5), /* keys are patterns */
531 "lock", (1 << 6), /* lock before access */
532 "replace", (1 << 7), /* if file, replace dups */
533 "sync_update", (1 << 8), /* if file, sync updates */
534 "debug", (1 << 9), /* log access */
535 "no_regsub", (1 << 11), /* disallow regexp substitution */
536 "no_proxy", (1 << 12), /* disallow proxy mapping */
537 "no_unauth", (1 << 13), /* disallow unauthenticated data */
538 "fold_fix", (1 << 14), /* case-fold with fixed-case key map */
539 "fold_mul", (1 << 15), /* case-fold with multi-case key map */
542 /* dict_flags_str - convert mask to string for debugging purposes */
544 const char *dict_flags_str(int dict_flags)
546 static VSTRING *buf = 0;
548 if (buf == 0)
549 buf = vstring_alloc(1);
551 return (str_name_mask_opt(buf, "dictionary flags", dict_mask, dict_flags,
552 NAME_MASK_RETURN | NAME_MASK_PIPE));