Postfix3.3.1
dict.c
[詳解]
1 /*++
2 /* NAME
3 /* dict 3
4 /* SUMMARY
5 /* dictionary manager
6 /* SYNOPSIS
7 /* #include <dict.h>
8 /*
9 /* void dict_register(dict_name, dict_info)
10 /* const char *dict_name;
11 /* DICT *dict_info;
12 /*
13 /* DICT *dict_handle(dict_name)
14 /* const char *dict_name;
15 /*
16 /* void dict_unregister(dict_name)
17 /* const char *dict_name;
18 /*
19 /* int dict_update(dict_name, member, value)
20 /* const char *dict_name;
21 /* const char *member;
22 /* const char *value;
23 /*
24 /* const char *dict_lookup(dict_name, member)
25 /* const char *dict_name;
26 /* const char *member;
27 /*
28 /* int dict_delete(dict_name, member)
29 /* const char *dict_name;
30 /* const char *member;
31 /*
32 /* int dict_sequence(dict_name, func, member, value)
33 /* const char *dict_name;
34 /* int func;
35 /* const char **member;
36 /* const char **value;
37 /*
38 /* const char *dict_eval(dict_name, string, int recursive)
39 /* const char *dict_name;
40 /* const char *string;
41 /* int recursive;
42 /*
43 /* int dict_walk(action, context)
44 /* void (*action)(dict_name, dict_handle, context)
45 /* void *context;
46 /*
47 /* int dict_error(dict_name)
48 /* const char *dict_name;
49 /*
50 /* const char *dict_changed_name()
51 /*
52 /* void DICT_OWNER_AGGREGATE_INIT(aggregate)
53 /* DICT_OWNER aggregate;
54 /*
55 /* void DICT_OWNER_AGGREGATE_UPDATE(aggregate, source)
56 /* DICT_OWNER aggregate;
57 /* DICT_OWNER source;
58 /* AUXILIARY FUNCTIONS
59 /* int dict_load_file_xt(dict_name, path)
60 /* const char *dict_name;
61 /* const char *path;
62 /*
63 /* void dict_load_fp(dict_name, fp)
64 /* const char *dict_name;
65 /* VSTREAM *fp;
66 /*
67 /* const char *dict_flags_str(dict_flags)
68 /* int dict_flags;
69 /*
70 /* int dict_flags_mask(names)
71 /* const char *names;
72 /* DESCRIPTION
73 /* This module maintains a collection of name-value dictionaries.
74 /* Each dictionary has its own name and has its own methods to read
75 /* or update members. Examples of dictionaries that can be accessed
76 /* in this manner are the global UNIX-style process environment,
77 /* hash tables, NIS maps, DBM files, and so on. Dictionary values
78 /* are not limited to strings but can be arbitrary objects as long
79 /* as they can be represented by character pointers.
80 /* FEATURES
81 /* .fi
82 /* .ad
83 /* Notable features of this module are:
84 /* .IP "macro expansion (string-valued dictionaries only)"
85 /* Macros of the form $\fIname\fR can be expanded to the current
86 /* value of \fIname\fR. The forms $(\fIname\fR) and ${\fIname\fR} are
87 /* also supported.
88 /* .IP "unknown names"
89 /* An update request for an unknown dictionary name will trigger
90 /* the instantiation of an in-memory dictionary with that name.
91 /* A lookup request (including delete and sequence) for an
92 /* unknown dictionary will result in a "not found" and "no
93 /* error" result.
94 /* .PP
95 /* dict_register() adds a new dictionary, including access methods,
96 /* to the list of known dictionaries, or increments the reference
97 /* count for an existing (name, dictionary) pair. Otherwise, it is
98 /* an error to pass an existing name (this would cause a memory leak).
99 /*
100 /* dict_handle() returns the generic dictionary handle of the
101 /* named dictionary, or a null pointer when the named dictionary
102 /* is not found.
103 /*
104 /* dict_unregister() decrements the reference count of the named
105 /* dictionary. When the reference count reaches zero, dict_unregister()
106 /* breaks the (name, dictionary) association and executes the
107 /* dictionary's optional \fIremove\fR method.
108 /*
109 /* dict_update() updates the value of the named dictionary member.
110 /* The dictionary member and the named dictionary are instantiated
111 /* on the fly. The result value is zero (DICT_STAT_SUCCESS)
112 /* when the update was made.
113 /*
114 /* dict_lookup() returns the value of the named member (i.e. without
115 /* expanding macros in the member value). The \fIdict_name\fR argument
116 /* specifies the dictionary to search. The result is a null pointer
117 /* when no value is found, otherwise the result is owned by the
118 /* underlying dictionary method. Make a copy if the result is to be
119 /* modified, or if the result is to survive multiple dict_lookup() calls.
120 /*
121 /* dict_delete() removes the named member from the named dictionary.
122 /* The result value is zero (DICT_STAT_SUCCESS) when the member
123 /* was found.
124 /*
125 /* dict_sequence() steps through the named dictionary and returns
126 /* keys and values in some implementation-defined order. The func
127 /* argument is DICT_SEQ_FUN_FIRST to set the cursor to the first
128 /* entry or DICT_SEQ_FUN_NEXT to select the next entry. The result
129 /* is owned by the underlying dictionary method. Make a copy if the
130 /* result is to be modified, or if the result is to survive multiple
131 /* dict_sequence() calls. The result value is zero (DICT_STAT_SUCCESS)
132 /* when a member was found.
133 /*
134 /* dict_eval() expands macro references in the specified string.
135 /* The result is owned by the dictionary manager. Make a copy if the
136 /* result is to survive multiple dict_eval() calls. When the
137 /* \fIrecursive\fR argument is non-zero, macro references in macro
138 /* lookup results are expanded recursively.
139 /*
140 /* dict_walk() iterates over all registered dictionaries in some
141 /* arbitrary order, and invokes the specified action routine with
142 /* as arguments:
143 /* .IP "const char *dict_name"
144 /* Dictionary name.
145 /* .IP "DICT *dict_handle"
146 /* Generic dictionary handle.
147 /* .IP "char *context"
148 /* Application context from the caller.
149 /* .PP
150 /* dict_changed_name() returns non-zero when any dictionary needs to
151 /* be re-opened because it has changed or because it was unlinked.
152 /* A non-zero result is the name of a changed dictionary.
153 /*
154 /* dict_load_file_xt() reads name-value entries from the named file.
155 /* Lines that begin with whitespace are concatenated to the preceding
156 /* line (the newline is deleted).
157 /* Each entry is stored in the dictionary named by \fIdict_name\fR.
158 /* The result is zero if the file could not be opened.
159 /*
160 /* dict_load_fp() reads name-value entries from an open stream.
161 /* It has the same semantics as the dict_load_file_xt() function.
162 /*
163 /* dict_flags_str() returns a printable representation of the
164 /* specified dictionary flags. The result is overwritten upon
165 /* each call.
166 /*
167 /* dict_flags_mask() returns the bitmask for the specified
168 /* comma/space-separated dictionary flag names.
169 /* TRUST AND PROVENANCE
170 /* .ad
171 /* .fi
172 /* Each dictionary has an owner attribute that contains (status,
173 /* uid) information about the owner of a dictionary. The
174 /* status is one of the following:
175 /* .IP DICT_OWNER_TRUSTED
176 /* The dictionary is owned by a trusted user. The uid is zero,
177 /* and specifies a UNIX user ID.
178 /* .IP DICT_OWNER_UNTRUSTED
179 /* The dictionary is owned by an untrusted user. The uid is
180 /* non-zero, and specifies a UNIX user ID.
181 /* .IP DICT_OWNER_UNKNOWN
182 /* The dictionary is owned by an unspecified user. For example,
183 /* the origin is unauthenticated, or different parts of a
184 /* dictionary aggregate (see below) are owned by different
185 /* untrusted users. The uid is non-zero and does not specify
186 /* a UNIX user ID.
187 /* .PP
188 /* Note that dictionary ownership does not necessarily imply
189 /* ownership of lookup results. For example, a PCRE table may
190 /* be owned by the trusted root user, but the result of $number
191 /* expansion can contain data from an arbitrary remote SMTP
192 /* client. See dict_open(3) for how to disallow $number
193 /* expansions with security-sensitive operations.
194 /*
195 /* Two macros are available to help determine the provenance
196 /* and trustworthiness of a dictionary aggregate. The macros
197 /* are unsafe because they may evaluate arguments more than
198 /* once.
199 /*
200 /* DICT_OWNER_AGGREGATE_INIT() initialize aggregate owner
201 /* attributes to the highest trust level.
202 /*
203 /* DICT_OWNER_AGGREGATE_UPDATE() updates the aggregate owner
204 /* attributes with the attributes of the specified source, and
205 /* reduces the aggregate trust level as appropriate.
206 /* SEE ALSO
207 /* htable(3)
208 /* BUGS
209 /* DIAGNOSTICS
210 /* Fatal errors: out of memory, malformed macro name.
211 /*
212 /* The lookup routine returns non-null when the request is
213 /* satisfied. The update, delete and sequence routines return
214 /* zero (DICT_STAT_SUCCESS) when the request is satisfied.
215 /* The dict_error() function returns non-zero only when the
216 /* last operation was not satisfied due to a dictionary access
217 /* error. The result can have the following values:
218 /* .IP DICT_ERR_NONE(zero)
219 /* There was no dictionary access error. For example, the
220 /* request was satisfied, the requested information did not
221 /* exist in the dictionary, or the information already existed
222 /* when it should not exist (collision).
223 /* .IP DICT_ERR_RETRY(<0)
224 /* The dictionary was temporarily unavailable. This can happen
225 /* with network-based services.
226 /* .IP DICT_ERR_CONFIG(<0)
227 /* The dictionary was unavailable due to a configuration error.
228 /* .PP
229 /* Generally, a program is expected to test the function result
230 /* value for "success" first. If the operation was not successful,
231 /* a program is expected to test for a non-zero dict->error
232 /* status to distinguish between a data notfound/collision
233 /* condition or a dictionary access error.
234 /* LICENSE
235 /* .ad
236 /* .fi
237 /* The Secure Mailer license must be distributed with this software.
238 /* AUTHOR(S)
239 /* Wietse Venema
240 /* IBM T.J. Watson Research
241 /* P.O. Box 704
242 /* Yorktown Heights, NY 10598, USA
243 /*--*/
244 
245 /* System libraries. */
246 
247 #include "sys_defs.h"
248 #include <sys/stat.h>
249 #include <fcntl.h>
250 #include <ctype.h>
251 #include <string.h>
252 #include <time.h>
253 
254 /* Utility library. */
255 
256 #include "msg.h"
257 #include "htable.h"
258 #include "mymalloc.h"
259 #include "vstream.h"
260 #include "vstring.h"
261 #include "readlline.h"
262 #include "mac_expand.h"
263 #include "stringops.h"
264 #include "iostuff.h"
265 #include "name_mask.h"
266 #include "dict.h"
267 #include "dict_ht.h"
268 #include "warn_stat.h"
269 #include "line_number.h"
270 
271 static HTABLE *dict_table;
272 
273  /*
274  * Each (name, dictionary) instance has a reference count. The count is part
275  * of the name, not the dictionary. The same dictionary may be registered
276  * under multiple names. The structure below keeps track of instances and
277  * reference counts.
278  */
279 typedef struct {
281  int refcount;
282 } DICT_NODE;
283 
284 #define dict_node(dict) \
285  (dict_table ? (DICT_NODE *) htable_find(dict_table, dict) : 0)
286 
287 /* Find a dictionary handle by name for lookup purposes. */
288 
289 #define DICT_FIND_FOR_LOOKUP(dict, dict_name) do { \
290  DICT_NODE *node; \
291  if ((node = dict_node(dict_name)) != 0) \
292  dict = node->dict; \
293  else \
294  dict = 0; \
295 } while (0)
296 
297 /* Find a dictionary handle by name for update purposes. */
298 
299 #define DICT_FIND_FOR_UPDATE(dict, dict_name) do { \
300  DICT_NODE *node; \
301  if ((node = dict_node(dict_name)) == 0) { \
302  dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); \
303  dict_register(dict_name, dict); \
304  } else \
305  dict = node->dict; \
306 } while (0)
307 
308 #define STR(x) vstring_str(x)
309 
310 /* dict_register - make association with dictionary */
311 
312 void dict_register(const char *dict_name, DICT *dict_info)
313 {
314  const char *myname = "dict_register";
315  DICT_NODE *node;
316 
317  if (dict_table == 0)
318  dict_table = htable_create(0);
319  if ((node = dict_node(dict_name)) == 0) {
320  node = (DICT_NODE *) mymalloc(sizeof(*node));
321  node->dict = dict_info;
322  node->refcount = 0;
323  htable_enter(dict_table, dict_name, (void *) node);
324  } else if (dict_info != node->dict)
325  msg_fatal("%s: dictionary name exists: %s", myname, dict_name);
326  node->refcount++;
327  if (msg_verbose > 1)
328  msg_info("%s: %s %d", myname, dict_name, node->refcount);
329 }
330 
331 /* dict_handle - locate generic dictionary handle */
332 
333 DICT *dict_handle(const char *dict_name)
334 {
335  DICT_NODE *node;
336 
337  return ((node = dict_node(dict_name)) != 0 ? node->dict : 0);
338 }
339 
340 /* dict_node_free - dict_unregister() callback */
341 
342 static void dict_node_free(void *ptr)
343 {
344  DICT_NODE *node = (DICT_NODE *) ptr;
345  DICT *dict = node->dict;
346 
347  if (dict->close)
348  dict->close(dict);
349  myfree((void *) node);
350 }
351 
352 /* dict_unregister - break association with named dictionary */
353 
354 void dict_unregister(const char *dict_name)
355 {
356  const char *myname = "dict_unregister";
357  DICT_NODE *node;
358 
359  if ((node = dict_node(dict_name)) == 0)
360  msg_panic("non-existing dictionary: %s", dict_name);
361  if (msg_verbose > 1)
362  msg_info("%s: %s %d", myname, dict_name, node->refcount);
363  if (--(node->refcount) == 0)
364  htable_delete(dict_table, dict_name, dict_node_free);
365 }
366 
367 /* dict_update - replace or add dictionary entry */
368 
369 int dict_update(const char *dict_name, const char *member, const char *value)
370 {
371  const char *myname = "dict_update";
372  DICT *dict;
373 
374  DICT_FIND_FOR_UPDATE(dict, dict_name);
375  if (msg_verbose > 1)
376  msg_info("%s: %s = %s", myname, member, value);
377  return (dict->update(dict, member, value));
378 }
379 
380 /* dict_lookup - look up dictionary entry */
381 
382 const char *dict_lookup(const char *dict_name, const char *member)
383 {
384  const char *myname = "dict_lookup";
385  DICT *dict;
386  const char *ret;
387 
388  DICT_FIND_FOR_LOOKUP(dict, dict_name);
389  if (dict != 0) {
390  ret = dict->lookup(dict, member);
391  if (msg_verbose > 1)
392  msg_info("%s: %s = %s", myname, member, ret ? ret :
393  dict->error ? "(error)" : "(notfound)");
394  return (ret);
395  } else {
396  if (msg_verbose > 1)
397  msg_info("%s: %s = %s", myname, member, "(notfound)");
398  return (0);
399  }
400 }
401 
402 /* dict_delete - delete dictionary entry */
403 
404 int dict_delete(const char *dict_name, const char *member)
405 {
406  const char *myname = "dict_delete";
407  DICT *dict;
408 
409  DICT_FIND_FOR_LOOKUP(dict, dict_name);
410  if (msg_verbose > 1)
411  msg_info("%s: delete %s", myname, member);
412  return (dict ? dict->delete(dict, member) : DICT_STAT_FAIL);
413 }
414 
415 /* dict_sequence - traverse dictionary */
416 
417 int dict_sequence(const char *dict_name, const int func,
418  const char **member, const char **value)
419 {
420  const char *myname = "dict_sequence";
421  DICT *dict;
422 
423  DICT_FIND_FOR_LOOKUP(dict, dict_name);
424  if (msg_verbose > 1)
425  msg_info("%s: sequence func %d", myname, func);
426  return (dict ? dict->sequence(dict, func, member, value) : DICT_STAT_FAIL);
427 }
428 
429 /* dict_error - return last error */
430 
431 int dict_error(const char *dict_name)
432 {
433  DICT *dict;
434 
435  DICT_FIND_FOR_LOOKUP(dict, dict_name);
436  return (dict ? dict->error : DICT_ERR_NONE);
437 }
438 
439 /* dict_load_file_xt - read entries from text file */
440 
441 int dict_load_file_xt(const char *dict_name, const char *path)
442 {
443  VSTREAM *fp;
444  struct stat st;
445  time_t before;
446  time_t after;
447 
448  /*
449  * Read the file again if it is hot. This may result in reading a partial
450  * parameter name when a file changes in the middle of a read.
451  */
452  for (before = time((time_t *) 0); /* see below */ ; before = after) {
453  if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
454  return (0);
455  dict_load_fp(dict_name, fp);
456  if (fstat(vstream_fileno(fp), &st) < 0)
457  msg_fatal("fstat %s: %m", path);
458  if (vstream_ferror(fp) || vstream_fclose(fp))
459  msg_fatal("read %s: %m", path);
460  after = time((time_t *) 0);
461  if (st.st_mtime < before - 1 || st.st_mtime > after)
462  break;
463  if (msg_verbose > 1)
464  msg_info("pausing to let %s cool down", path);
465  doze(300000);
466  }
467  return (1);
468 }
469 
470 /* dict_load_fp - read entries from open stream */
471 
472 void dict_load_fp(const char *dict_name, VSTREAM *fp)
473 {
474  const char *myname = "dict_load_fp";
475  VSTRING *buf;
476  char *member;
477  char *val;
478  const char *old;
479  int last_line;
480  int lineno;
481  const char *err;
482  struct stat st;
483  DICT *dict;
484 
485  /*
486  * Instantiate the dictionary even if the file is empty.
487  */
488  DICT_FIND_FOR_UPDATE(dict, dict_name);
489  buf = vstring_alloc(100);
490  last_line = 0;
491 
492  if (fstat(vstream_fileno(fp), &st) < 0)
493  msg_fatal("fstat %s: %m", VSTREAM_PATH(fp));
494  while (readllines(buf, fp, &last_line, &lineno)) {
495  if ((err = split_nameval(STR(buf), &member, &val)) != 0)
496  msg_fatal("%s, line %d: %s: \"%s\"",
497  VSTREAM_PATH(fp),
498  lineno,
499  err, STR(buf));
500  if (msg_verbose > 1)
501  msg_info("%s: %s = %s", myname, member, val);
502  if ((old = dict->lookup(dict, member)) != 0
503  && strcmp(old, val) != 0)
504  msg_warn("%s, line %d: overriding earlier entry: %s=%s",
505  VSTREAM_PATH(fp), lineno, member, old);
506  if (dict->update(dict, member, val) != 0)
507  msg_fatal("%s, line %d: unable to update %s:%s",
508  VSTREAM_PATH(fp), lineno, dict->type, dict->name);
509  }
510  vstring_free(buf);
511  dict->owner.uid = st.st_uid;
512  dict->owner.status = (st.st_uid != 0);
513 }
514 
515 /* dict_eval_lookup - macro parser call-back routine */
516 
517 static const char *dict_eval_lookup(const char *key, int unused_type,
518  void *context)
519 {
520  char *dict_name = (char *) context;
521  const char *pp = 0;
522  DICT *dict;
523 
524  /*
525  * XXX how would one recover?
526  */
527  DICT_FIND_FOR_LOOKUP(dict, dict_name);
528  if (dict != 0
529  && (pp = dict->lookup(dict, key)) == 0 && dict->error != 0)
530  msg_fatal("dictionary %s: lookup %s: operation failed", dict_name, key);
531  return (pp);
532 }
533 
534 /* dict_eval - expand embedded dictionary references */
535 
536 const char *dict_eval(const char *dict_name, const char *value, int recursive)
537 {
538  const char *myname = "dict_eval";
539  static VSTRING *buf;
540  int status;
541 
542  /*
543  * Initialize.
544  */
545  if (buf == 0)
546  buf = vstring_alloc(10);
547 
548  /*
549  * Expand macros, possibly recursively.
550  */
551 #define DONT_FILTER (char *) 0
552 
553  status = mac_expand(buf, value,
555  DONT_FILTER, dict_eval_lookup, (void *) dict_name);
556  if (status & MAC_PARSE_ERROR)
557  msg_fatal("dictionary %s: macro processing error", dict_name);
558  if (msg_verbose > 1) {
559  if (strcmp(value, STR(buf)) != 0)
560  msg_info("%s: expand %s -> %s", myname, value, STR(buf));
561  else
562  msg_info("%s: const %s", myname, value);
563  }
564  return (STR(buf));
565 }
566 
567 /* dict_walk - iterate over all dictionaries in arbitrary order */
568 
569 void dict_walk(DICT_WALK_ACTION action, void *ptr)
570 {
571  HTABLE_INFO **ht_info_list;
572  HTABLE_INFO **ht;
573  HTABLE_INFO *h;
574 
575  ht_info_list = htable_list(dict_table);
576  for (ht = ht_info_list; (h = *ht) != 0; ht++)
577  action(h->key, (DICT *) h->value, ptr);
578  myfree((void *) ht_info_list);
579 }
580 
581 /* dict_changed_name - see if any dictionary has changed */
582 
583 const char *dict_changed_name(void)
584 {
585  const char *myname = "dict_changed_name";
586  struct stat st;
587  HTABLE_INFO **ht_info_list;
588  HTABLE_INFO **ht;
589  HTABLE_INFO *h;
590  const char *status;
591  DICT *dict;
592 
593  ht_info_list = htable_list(dict_table);
594  for (status = 0, ht = ht_info_list; status == 0 && (h = *ht) != 0; ht++) {
595  dict = ((DICT_NODE *) h->value)->dict;
596  if (dict->stat_fd < 0) /* not file-based */
597  continue;
598  if (dict->mtime == 0) /* not bloody likely */
599  msg_warn("%s: table %s: null time stamp", myname, h->key);
600  if (fstat(dict->stat_fd, &st) < 0)
601  msg_fatal("%s: fstat: %m", myname);
602  if (((dict->flags & DICT_FLAG_MULTI_WRITER) == 0
603  && st.st_mtime != dict->mtime)
604  || st.st_nlink == 0)
605  status = h->key;
606  }
607  myfree((void *) ht_info_list);
608  return (status);
609 }
610 
611 /* dict_changed - backwards compatibility */
612 
613 int dict_changed(void)
614 {
615  return (dict_changed_name() != 0);
616 }
617 
618  /*
619  * Mapping between flag names and flag values.
620  */
621 static const NAME_MASK dict_mask[] = {
622  "warn_dup", DICT_FLAG_DUP_WARN, /* if file, warn about dups */
623  "ignore_dup", DICT_FLAG_DUP_IGNORE, /* if file, ignore dups */
624  "try0null", DICT_FLAG_TRY0NULL, /* do not append 0 to key/value */
625  "try1null", DICT_FLAG_TRY1NULL, /* append 0 to key/value */
626  "fixed", DICT_FLAG_FIXED, /* fixed key map */
627  "pattern", DICT_FLAG_PATTERN, /* keys are patterns */
628  "lock", DICT_FLAG_LOCK, /* lock before access */
629  "replace", DICT_FLAG_DUP_REPLACE, /* if file, replace dups */
630  "sync_update", DICT_FLAG_SYNC_UPDATE, /* if file, sync updates */
631  "debug", DICT_FLAG_DEBUG, /* log access */
632  "no_regsub", DICT_FLAG_NO_REGSUB, /* disallow regexp substitution */
633  "no_proxy", DICT_FLAG_NO_PROXY, /* disallow proxy mapping */
634  "no_unauth", DICT_FLAG_NO_UNAUTH, /* disallow unauthenticated data */
635  "fold_fix", DICT_FLAG_FOLD_FIX, /* case-fold with fixed-case key map */
636  "fold_mul", DICT_FLAG_FOLD_MUL, /* case-fold with multi-case key map */
637  "open_lock", DICT_FLAG_OPEN_LOCK, /* permanent lock upon open */
638  "bulk_update", DICT_FLAG_BULK_UPDATE, /* bulk update if supported */
639  "multi_writer", DICT_FLAG_MULTI_WRITER, /* multi-writer safe */
640  "utf8_request", DICT_FLAG_UTF8_REQUEST, /* request UTF-8 activation */
641  "utf8_active", DICT_FLAG_UTF8_ACTIVE, /* UTF-8 is activated */
642  0,
643 };
644 
645 /* dict_flags_str - convert bitmask to symbolic flag names */
646 
647 const char *dict_flags_str(int dict_flags)
648 {
649  static VSTRING *buf = 0;
650 
651  if (buf == 0)
652  buf = vstring_alloc(1);
653 
654  return (str_name_mask_opt(buf, "dictionary flags", dict_mask, dict_flags,
656 }
657 
658 /* dict_flags_mask - convert symbolic flag names to bitmask */
659 
660 int dict_flags_mask(const char *names)
661 {
662  return (name_mask("dictionary flags", dict_mask, names));
663 }
int msg_verbose
Definition: msg.c:177
#define DICT_FLAG_DUP_IGNORE
Definition: dict.h:111
void * value
Definition: htable.h:18
void myfree(void *ptr)
Definition: mymalloc.c:207
int dict_error(const char *dict_name)
Definition: dict.c:431
time_t mtime
Definition: dict.h:91
int mac_expand(VSTRING *result, const char *pattern, int flags, const char *filter, MAC_EXP_LOOKUP_FN lookup, void *context)
Definition: mac_expand.c:593
#define dict_node(dict)
Definition: dict.c:284
void dict_register(const char *dict_name, DICT *dict_info)
Definition: dict.c:312
#define DICT_FLAG_NO_UNAUTH
Definition: dict.h:123
int dict_load_file_xt(const char *dict_name, const char *path)
Definition: dict.c:441
void(* close)(struct DICT *)
Definition: dict.h:87
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
int(* delete)(struct DICT *, const char *)
Definition: dict.h:84
#define stat(p, s)
Definition: warn_stat.h:18
#define DICT_FLAG_FIXED
Definition: dict.h:114
int flags
Definition: dict.h:81
int refcount
Definition: dict.c:281
#define DICT_STAT_FAIL
Definition: dict.h:185
int dict_changed(void)
Definition: dict.c:613
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
#define MAC_EXP_FLAG_RECURSE
Definition: mac_expand.h:24
#define DICT_FLAG_UTF8_REQUEST
Definition: dict.h:130
#define DICT_FLAG_MULTI_WRITER
Definition: dict.h:129
Definition: htable.h:25
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define DICT_FLAG_FOLD_FIX
Definition: dict.h:124
#define DICT_ERR_NONE
Definition: dict.h:177
void dict_unregister(const char *dict_name)
Definition: dict.c:354
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
Definition: vstream.c:1241
int dict_flags_mask(const char *names)
Definition: dict.c:660
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
Definition: dict.h:78
#define STR(x)
Definition: dict.c:308
const char * dict_lookup(const char *dict_name, const char *member)
Definition: dict.c:382
int(* update)(struct DICT *, const char *, const char *)
Definition: dict.h:83
HTABLE_INFO ** htable_list(HTABLE *table)
Definition: htable.c:330
const char * str_name_mask_opt(VSTRING *buf, const char *context, const NAME_MASK *table, int mask, int flags)
Definition: name_mask.c:265
int dict_sequence(const char *dict_name, const int func, const char **member, const char **value)
Definition: dict.c:417
#define MAC_EXP_FLAG_NONE
Definition: mac_expand.h:23
#define DONT_FILTER
int stat_fd
Definition: dict.h:90
#define DICT_FLAG_DUP_REPLACE
Definition: dict.h:117
const char * dict_changed_name(void)
Definition: dict.c:583
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define DICT_FLAG_TRY1NULL
Definition: dict.h:113
DICT * dict_handle(const char *dict_name)
Definition: dict.c:333
#define DICT_FLAG_LOCK
Definition: dict.h:116
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * key
Definition: htable.h:17
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define name_mask(tag, table, str)
Definition: name_mask.h:49
const char * dict_flags_str(int dict_flags)
Definition: dict.c:647
int error
Definition: dict.h:94
void doze(unsigned delay)
Definition: doze.c:44
const char *(* lookup)(struct DICT *, const char *)
Definition: dict.h:82
void dict_load_fp(const char *dict_name, VSTREAM *fp)
Definition: dict.c:472
#define DICT_FLAG_DUP_WARN
Definition: dict.h:110
void(* DICT_WALK_ACTION)(const char *, DICT *, void *)
Definition: dict.h:241
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int dict_update(const char *dict_name, const char *member, const char *value)
Definition: dict.c:369
VSTRING * readllines(VSTRING *buf, VSTREAM *fp, int *lineno, int *first_line)
Definition: readlline.c:82
#define DICT_FLAG_PATTERN
Definition: dict.h:115
#define DICT_FIND_FOR_UPDATE(dict, dict_name)
Definition: dict.c:299
DICT * dict
Definition: dict.c:280
const char * dict_eval(const char *dict_name, const char *value, int recursive)
Definition: dict.c:536
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define NAME_MASK_NUMBER
Definition: name_mask.h:32
#define DICT_FLAG_NO_REGSUB
Definition: dict.h:121
#define DICT_FLAG_FOLD_MUL
Definition: dict.h:125
#define vstream_fileno(vp)
Definition: vstream.h:115
void dict_walk(DICT_WALK_ACTION action, void *ptr)
Definition: dict.c:569
#define DICT_FLAG_DEBUG
Definition: dict.h:119
#define DICT_FLAG_SYNC_UPDATE
Definition: dict.h:118
int(* sequence)(struct DICT *, int, const char **, const char **)
Definition: dict.h:85
#define DICT_FIND_FOR_LOOKUP(dict, dict_name)
Definition: dict.c:289
#define NAME_MASK_PIPE
Definition: name_mask.h:31
void htable_delete(HTABLE *table, const char *key, void(*free_fn)(void *))
Definition: htable.c:257
#define vstream_ferror(vp)
Definition: vstream.h:120
#define DICT_FLAG_BULK_UPDATE
Definition: dict.h:128
#define DICT_FLAG_TRY0NULL
Definition: dict.h:112
#define DICT_FLAG_NO_PROXY
Definition: dict.h:122
int dict_delete(const char *dict_name, const char *member)
Definition: dict.c:404
#define DICT_FLAG_OPEN_LOCK
Definition: dict.h:127
#define DICT_FLAG_UTF8_ACTIVE
Definition: dict.h:131
#define fstat(f, s)
Definition: warn_stat.h:20
#define MAC_PARSE_ERROR
Definition: mac_parse.h:27
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199