Sync usage with man page.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / postalias / postalias.c
blob5bd9a00ea5c9aacf1ee5e268baca42d1accf994b
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* postalias 1
6 /* SUMMARY
7 /* Postfix alias database maintenance
8 /* SYNOPSIS
9 /* .fi
10 /* \fBpostalias\fR [\fB-Nfinoprsvw\fR] [\fB-c \fIconfig_dir\fR]
11 /* [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
12 /* [\fIfile_type\fR:]\fIfile_name\fR ...
13 /* DESCRIPTION
14 /* The \fBpostalias\fR(1) command creates or queries one or more Postfix
15 /* alias databases, or updates an existing one. The input and output
16 /* file formats are expected to be compatible with Sendmail version 8,
17 /* and are expected to be suitable for the use as NIS alias maps.
19 /* If the result files do not exist they will be created with the
20 /* same group and other read permissions as their source file.
22 /* While a database update is in progress, signal delivery is
23 /* postponed, and an exclusive, advisory, lock is placed on the
24 /* entire database, in order to avoid surprises in spectator
25 /* processes.
27 /* The format of Postfix alias input files is described in
28 /* \fBaliases\fR(5).
30 /* By default the lookup key is mapped to lowercase to make
31 /* the lookups case insensitive; as of Postfix 2.3 this case
32 /* folding happens only with tables whose lookup keys are
33 /* fixed-case strings such as btree:, dbm: or hash:. With
34 /* earlier versions, the lookup key is folded even with tables
35 /* where a lookup field can match both upper and lower case
36 /* text, such as regexp: and pcre:. This resulted in loss of
37 /* information with $\fInumber\fR substitutions.
39 /* Options:
40 /* .IP "\fB-c \fIconfig_dir\fR"
41 /* Read the \fBmain.cf\fR configuration file in the named directory
42 /* instead of the default configuration directory.
43 /* .IP "\fB-d \fIkey\fR"
44 /* Search the specified maps for \fIkey\fR and remove one entry per map.
45 /* The exit status is zero when the requested information was found.
47 /* If a key value of \fB-\fR is specified, the program reads key
48 /* values from the standard input stream. The exit status is zero
49 /* when at least one of the requested keys was found.
50 /* .IP \fB-f\fR
51 /* Do not fold the lookup key to lower case while creating or querying
52 /* a table.
54 /* With Postfix version 2.3 and later, this option has no
55 /* effect for regular expression tables. There, case folding
56 /* is controlled by appending a flag to a pattern.
57 /* .IP \fB-i\fR
58 /* Incremental mode. Read entries from standard input and do not
59 /* truncate an existing database. By default, \fBpostalias\fR(1) creates
60 /* a new database from the entries in \fIfile_name\fR.
61 /* .IP \fB-N\fR
62 /* Include the terminating null character that terminates lookup keys
63 /* and values. By default, \fBpostalias\fR(1) does whatever
64 /* is the default for
65 /* the host operating system.
66 /* .IP \fB-n\fR
67 /* Don't include the terminating null character that terminates lookup
68 /* keys and values. By default, \fBpostalias\fR(1) does whatever
69 /* is the default for
70 /* the host operating system.
71 /* .IP \fB-o\fR
72 /* Do not release root privileges when processing a non-root
73 /* input file. By default, \fBpostalias\fR(1) drops root privileges
74 /* and runs as the source file owner instead.
75 /* .IP \fB-p\fR
76 /* Do not inherit the file access permissions from the input file
77 /* when creating a new file. Instead, create a new file with default
78 /* access permissions (mode 0644).
79 /* .IP "\fB-q \fIkey\fR"
80 /* Search the specified maps for \fIkey\fR and write the first value
81 /* found to the standard output stream. The exit status is zero
82 /* when the requested information was found.
84 /* If a key value of \fB-\fR is specified, the program reads key
85 /* values from the standard input stream and writes one line of
86 /* \fIkey: value\fR output for each key that was found. The exit
87 /* status is zero when at least one of the requested keys was found.
88 /* .IP \fB-r\fR
89 /* When updating a table, do not complain about attempts to update
90 /* existing entries, and make those updates anyway.
91 /* .IP \fB-s\fR
92 /* Retrieve all database elements, and write one line of
93 /* \fIkey: value\fR output for each element. The elements are
94 /* printed in database order, which is not necessarily the same
95 /* as the original input order.
96 /* This feature is available in Postfix version 2.2 and later,
97 /* and is not available for all database types.
98 /* .IP \fB-v\fR
99 /* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
100 /* options make the software increasingly verbose.
101 /* .IP \fB-w\fR
102 /* When updating a table, do not complain about attempts to update
103 /* existing entries, and ignore those attempts.
104 /* .PP
105 /* Arguments:
106 /* .IP \fIfile_type\fR
107 /* The database type. To find out what types are supported, use
108 /* the "\fBpostconf -m\fR" command.
110 /* The \fBpostalias\fR(1) command can query any supported file type,
111 /* but it can create only the following file types:
112 /* .RS
113 /* .IP \fBbtree\fR
114 /* The output is a btree file, named \fIfile_name\fB.db\fR.
115 /* This is available on systems with support for \fBdb\fR databases.
116 /* .IP \fBcdb\fR
117 /* The output is one file named \fIfile_name\fB.cdb\fR.
118 /* This is available on systems with support for \fBcdb\fR databases.
119 /* .IP \fBdbm\fR
120 /* The output consists of two files, named \fIfile_name\fB.pag\fR and
121 /* \fIfile_name\fB.dir\fR.
122 /* This is available on systems with support for \fBdbm\fR databases.
123 /* .IP \fBhash\fR
124 /* The output is a hashed file, named \fIfile_name\fB.db\fR.
125 /* This is available on systems with support for \fBdb\fR databases.
126 /* .IP \fBsdbm\fR
127 /* The output consists of two files, named \fIfile_name\fB.pag\fR and
128 /* \fIfile_name\fB.dir\fR.
129 /* This is available on systems with support for \fBsdbm\fR databases.
130 /* .PP
131 /* When no \fIfile_type\fR is specified, the software uses the database
132 /* type specified via the \fBdefault_database_type\fR configuration
133 /* parameter.
134 /* The default value for this parameter depends on the host environment.
135 /* .RE
136 /* .IP \fIfile_name\fR
137 /* The name of the alias database source file when creating a database.
138 /* DIAGNOSTICS
139 /* Problems are logged to the standard error stream and to
140 /* \fBsyslogd\fR(8). No output means that
141 /* no problems were detected. Duplicate entries are skipped and are
142 /* flagged with a warning.
144 /* \fBpostalias\fR(1) terminates with zero exit status in case of success
145 /* (including successful "\fBpostalias -q\fR" lookup) and terminates
146 /* with non-zero exit status in case of failure.
147 /* ENVIRONMENT
148 /* .ad
149 /* .fi
150 /* .IP \fBMAIL_CONFIG\fR
151 /* Directory with Postfix configuration files.
152 /* .IP \fBMAIL_VERBOSE\fR
153 /* Enable verbose logging for debugging purposes.
154 /* CONFIGURATION PARAMETERS
155 /* .ad
156 /* .fi
157 /* The following \fBmain.cf\fR parameters are especially relevant to
158 /* this program.
160 /* The text below provides only a parameter summary. See
161 /* \fBpostconf\fR(5) for more details including examples.
162 /* .IP "\fBalias_database (see 'postconf -d' output)\fR"
163 /* The alias databases for \fBlocal\fR(8) delivery that are updated with
164 /* "\fBnewaliases\fR" or with "\fBsendmail -bi\fR".
165 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
166 /* The default location of the Postfix main.cf and master.cf
167 /* configuration files.
168 /* .IP "\fBberkeley_db_create_buffer_size (16777216)\fR"
169 /* The per-table I/O buffer size for programs that create Berkeley DB
170 /* hash or btree tables.
171 /* .IP "\fBberkeley_db_read_buffer_size (131072)\fR"
172 /* The per-table I/O buffer size for programs that read Berkeley DB
173 /* hash or btree tables.
174 /* .IP "\fBdefault_database_type (see 'postconf -d' output)\fR"
175 /* The default database type for use in \fBnewaliases\fR(1), \fBpostalias\fR(1)
176 /* and \fBpostmap\fR(1) commands.
177 /* .IP "\fBsyslog_facility (mail)\fR"
178 /* The syslog facility of Postfix logging.
179 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
180 /* The mail system name that is prepended to the process name in syslog
181 /* records, so that "smtpd" becomes, for example, "postfix/smtpd".
182 /* STANDARDS
183 /* RFC 822 (ARPA Internet Text Messages)
184 /* SEE ALSO
185 /* aliases(5), format of alias database input file.
186 /* local(8), Postfix local delivery agent.
187 /* postconf(1), supported database types
188 /* postconf(5), configuration parameters
189 /* postmap(1), create/update/query lookup tables
190 /* newaliases(1), Sendmail compatibility interface.
191 /* syslogd(8), system logging
192 /* README FILES
193 /* .ad
194 /* .fi
195 /* Use "\fBpostconf readme_directory\fR" or
196 /* "\fBpostconf html_directory\fR" to locate this information.
197 /* .na
198 /* .nf
199 /* DATABASE_README, Postfix lookup table overview
200 /* LICENSE
201 /* .ad
202 /* .fi
203 /* The Secure Mailer license must be distributed with this software.
204 /* AUTHOR(S)
205 /* Wietse Venema
206 /* IBM T.J. Watson Research
207 /* P.O. Box 704
208 /* Yorktown Heights, NY 10598, USA
209 /*--*/
211 /* System library. */
213 #include <sys_defs.h>
214 #include <sys/stat.h>
215 #include <stdlib.h>
216 #include <unistd.h>
217 #include <fcntl.h>
218 #include <ctype.h>
219 #include <string.h>
221 /* Utility library. */
223 #include <msg.h>
224 #include <mymalloc.h>
225 #include <vstring.h>
226 #include <vstream.h>
227 #include <msg_vstream.h>
228 #include <msg_syslog.h>
229 #include <readlline.h>
230 #include <stringops.h>
231 #include <split_at.h>
232 #include <vstring_vstream.h>
233 #include <set_eugid.h>
235 /* Global library. */
237 #include <tok822.h>
238 #include <mail_conf.h>
239 #include <mail_dict.h>
240 #include <mail_params.h>
241 #include <mail_version.h>
242 #include <mkmap.h>
243 #include <mail_task.h>
244 #include <dict_proxy.h>
246 /* Application-specific. */
248 #define STR vstring_str
250 #define POSTALIAS_FLAG_AS_OWNER (1<<0) /* open dest as owner of source */
251 #define POSTALIAS_FLAG_SAVE_PERM (1<<1) /* copy access permission
252 * from source */
254 /* postalias - create or update alias database */
256 static void postalias(char *map_type, char *path_name, int postalias_flags,
257 int open_flags, int dict_flags)
259 VSTREAM *source_fp;
260 VSTRING *line_buffer;
261 MKMAP *mkmap;
262 int lineno;
263 VSTRING *key_buffer;
264 VSTRING *value_buffer;
265 TOK822 *tok_list;
266 TOK822 *key_list;
267 TOK822 *colon;
268 TOK822 *value_list;
269 struct stat st;
270 mode_t saved_mask;
273 * Initialize.
275 line_buffer = vstring_alloc(100);
276 key_buffer = vstring_alloc(100);
277 value_buffer = vstring_alloc(100);
278 if ((open_flags & O_TRUNC) == 0) {
279 source_fp = VSTREAM_IN;
280 vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
281 } else if (strcmp(map_type, DICT_TYPE_PROXY) == 0) {
282 msg_fatal("can't create maps via the proxy service");
283 } else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) {
284 msg_fatal("open %s: %m", path_name);
286 if (fstat(vstream_fileno(source_fp), &st) < 0)
287 msg_fatal("fstat %s: %m", path_name);
290 * Turn off group/other read permissions as indicated in the source file.
292 if ((postalias_flags & POSTALIAS_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
293 saved_mask = umask(022 | (~st.st_mode & 077));
296 * If running as root, run as the owner of the source file, so that the
297 * result shows proper ownership, and so that a bug in postalias does not
298 * allow privilege escalation.
300 if ((postalias_flags & POSTALIAS_FLAG_AS_OWNER) && getuid() == 0
301 && (st.st_uid != geteuid() || st.st_gid != getegid()))
302 set_eugid(st.st_uid, st.st_gid);
306 * Open the database, create it when it does not exist, truncate it when
307 * it does exist, and lock out any spectators.
309 mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags);
312 * And restore the umask, in case it matters.
314 if ((postalias_flags & POSTALIAS_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
315 umask(saved_mask);
318 * Add records to the database.
320 lineno = 0;
321 while (readlline(line_buffer, source_fp, &lineno)) {
324 * Tokenize the input, so that we do the right thing when a quoted
325 * localpart contains special characters such as "@", ":" and so on.
327 if ((tok_list = tok822_scan(STR(line_buffer), (TOK822 **) 0)) == 0)
328 continue;
331 * Enforce the key:value format. Disallow missing keys, multi-address
332 * keys, or missing values. In order to specify an empty string or
333 * value, enclose it in double quotes.
335 if ((colon = tok822_find_type(tok_list, ':')) == 0
336 || colon->prev == 0 || colon->next == 0
337 || tok822_rfind_type(colon, ',')) {
338 msg_warn("%s, line %d: need name:value pair",
339 VSTREAM_PATH(source_fp), lineno);
340 tok822_free_tree(tok_list);
341 continue;
345 * Key must be local. XXX We should use the Postfix rewriting and
346 * resolving services to handle all address forms correctly. However,
347 * we can't count on the mail system being up when the alias database
348 * is being built, so we're guessing a bit.
350 if (tok822_rfind_type(colon, '@') || tok822_rfind_type(colon, '%')) {
351 msg_warn("%s, line %d: name must be local",
352 VSTREAM_PATH(source_fp), lineno);
353 tok822_free_tree(tok_list);
354 continue;
358 * Split the input into key and value parts, and convert from token
359 * representation back to string representation. Convert the key to
360 * internal (unquoted) form, because the resolver produces addresses
361 * in internal form. Convert the value to external (quoted) form,
362 * because it will have to be re-parsed upon lookup. Discard the
363 * token representation when done.
365 key_list = tok_list;
366 tok_list = 0;
367 value_list = tok822_cut_after(colon);
368 tok822_unlink(colon);
369 tok822_free(colon);
371 tok822_internalize(key_buffer, key_list, TOK822_STR_DEFL);
372 tok822_free_tree(key_list);
374 tok822_externalize(value_buffer, value_list, TOK822_STR_DEFL);
375 tok822_free_tree(value_list);
378 * Store the value under a case-insensitive key.
380 mkmap_append(mkmap, STR(key_buffer), STR(value_buffer));
384 * Update or append sendmail and NIS signatures.
386 if ((open_flags & O_TRUNC) == 0)
387 mkmap->dict->flags |= DICT_FLAG_DUP_REPLACE;
390 * Sendmail compatibility: add the @:@ signature to indicate that the
391 * database is complete. This might be needed by NIS clients running
392 * sendmail.
394 mkmap_append(mkmap, "@", "@");
397 * NIS compatibility: add time and master info. Unlike other information,
398 * this information MUST be written without a trailing null appended to
399 * key or value.
401 mkmap->dict->flags &= ~DICT_FLAG_TRY1NULL;
402 mkmap->dict->flags |= DICT_FLAG_TRY0NULL;
403 vstring_sprintf(value_buffer, "%010ld", (long) time((time_t *) 0));
404 #if (defined(HAS_NIS) || defined(HAS_NISPLUS))
405 mkmap->dict->flags &= ~DICT_FLAG_FOLD_FIX;
406 mkmap_append(mkmap, "YP_LAST_MODIFIED", STR(value_buffer));
407 mkmap_append(mkmap, "YP_MASTER_NAME", var_myhostname);
408 #endif
411 * Close the alias database, and release the lock.
413 mkmap_close(mkmap);
416 * Cleanup. We're about to terminate, but it is a good sanity check.
418 vstring_free(value_buffer);
419 vstring_free(key_buffer);
420 vstring_free(line_buffer);
421 if (source_fp != VSTREAM_IN)
422 vstream_fclose(source_fp);
425 /* postalias_queries - apply multiple requests from stdin */
427 static int postalias_queries(VSTREAM *in, char **maps, const int map_count,
428 const int dict_flags)
430 int found = 0;
431 VSTRING *keybuf = vstring_alloc(100);
432 DICT **dicts;
433 const char *map_name;
434 const char *value;
435 int n;
438 * Sanity check.
440 if (map_count <= 0)
441 msg_panic("postalias_queries: bad map count");
444 * Prepare to open maps lazily.
446 dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count);
447 for (n = 0; n < map_count; n++)
448 dicts[n] = 0;
451 * Perform all queries. Open maps on the fly, to avoid opening unecessary
452 * maps.
454 while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) {
455 for (n = 0; n < map_count; n++) {
456 if (dicts[n] == 0)
457 dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ?
458 dict_open3(maps[n], map_name, O_RDONLY, dict_flags) :
459 dict_open3(var_db_type, maps[n], O_RDONLY, dict_flags));
460 if ((value = dict_get(dicts[n], STR(keybuf))) != 0) {
461 if (*value == 0) {
462 msg_warn("table %s:%s: key %s: empty string result is not allowed",
463 dicts[n]->type, dicts[n]->name, STR(keybuf));
464 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
465 dicts[n]->type, dicts[n]->name);
467 vstream_printf("%s: %s\n", STR(keybuf), value);
468 found = 1;
469 break;
473 if (found)
474 vstream_fflush(VSTREAM_OUT);
477 * Cleanup.
479 for (n = 0; n < map_count; n++)
480 if (dicts[n])
481 dict_close(dicts[n]);
482 myfree((char *) dicts);
483 vstring_free(keybuf);
485 return (found);
488 /* postalias_query - query a map and print the result to stdout */
490 static int postalias_query(const char *map_type, const char *map_name,
491 const char *key, int dict_flags)
493 DICT *dict;
494 const char *value;
496 dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
497 if ((value = dict_get(dict, key)) != 0) {
498 if (*value == 0) {
499 msg_warn("table %s:%s: key %s: empty string result is not allowed",
500 map_type, map_name, key);
501 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
502 map_type, map_name);
504 vstream_printf("%s\n", value);
506 vstream_fflush(VSTREAM_OUT);
507 dict_close(dict);
508 return (value != 0);
511 /* postalias_deletes - apply multiple requests from stdin */
513 static int postalias_deletes(VSTREAM *in, char **maps, const int map_count,
514 int dict_flags)
516 int found = 0;
517 VSTRING *keybuf = vstring_alloc(100);
518 DICT **dicts;
519 const char *map_name;
520 int n;
521 int open_flags;
524 * Sanity check.
526 if (map_count <= 0)
527 msg_panic("postalias_deletes: bad map count");
530 * Open maps ahead of time.
532 dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count);
533 for (n = 0; n < map_count; n++) {
534 map_name = split_at(maps[n], ':');
535 if (map_name && strcmp(maps[n], DICT_TYPE_PROXY) == 0)
536 open_flags = O_RDWR | O_CREAT; /* XXX */
537 else
538 open_flags = O_RDWR;
539 dicts[n] = (map_name != 0 ?
540 dict_open3(maps[n], map_name, open_flags, dict_flags) :
541 dict_open3(var_db_type, maps[n], open_flags, dict_flags));
545 * Perform all requests.
547 while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF)
548 for (n = 0; n < map_count; n++)
549 found |= (dict_del(dicts[n], STR(keybuf)) == 0);
552 * Cleanup.
554 for (n = 0; n < map_count; n++)
555 if (dicts[n])
556 dict_close(dicts[n]);
557 myfree((char *) dicts);
558 vstring_free(keybuf);
560 return (found);
563 /* postalias_delete - delete a key value pair from a map */
565 static int postalias_delete(const char *map_type, const char *map_name,
566 const char *key, int dict_flags)
568 DICT *dict;
569 int status;
570 int open_flags;
572 if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
573 open_flags = O_RDWR | O_CREAT; /* XXX */
574 else
575 open_flags = O_RDWR;
576 dict = dict_open3(map_type, map_name, open_flags, dict_flags);
577 status = dict_del(dict, key);
578 dict_close(dict);
579 return (status == 0);
582 /* postalias_seq - print all map entries to stdout */
584 static void postalias_seq(const char *map_type, const char *map_name,
585 int dict_flags)
587 DICT *dict;
588 const char *key;
589 const char *value;
590 int func;
592 if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
593 msg_fatal("can't sequence maps via the proxy service");
594 dict = dict_open3(map_type, map_name, O_RDONLY, dict_flags);
595 for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
596 if (dict_seq(dict, func, &key, &value) != 0)
597 break;
598 if (*key == 0) {
599 msg_warn("table %s:%s: empty lookup key value is not allowed",
600 map_type, map_name);
601 } else if (*value == 0) {
602 msg_warn("table %s:%s: key %s: empty string result is not allowed",
603 map_type, map_name, key);
604 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
605 map_type, map_name);
607 vstream_printf("%s: %s\n", key, value);
609 vstream_fflush(VSTREAM_OUT);
610 dict_close(dict);
613 /* usage - explain */
615 static NORETURN usage(char *myname)
617 msg_fatal("usage: %s [-Nfinoprsvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
618 myname);
621 MAIL_VERSION_STAMP_DECLARE;
623 int main(int argc, char **argv)
625 char *path_name;
626 int ch;
627 int fd;
628 char *slash;
629 struct stat st;
630 int postalias_flags = POSTALIAS_FLAG_AS_OWNER | POSTALIAS_FLAG_SAVE_PERM;
631 int open_flags = O_RDWR | O_CREAT | O_TRUNC;
632 int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX;
633 char *query = 0;
634 char *delkey = 0;
635 int sequence = 0;
636 int found;
639 * Fingerprint executables and core dumps.
641 MAIL_VERSION_STAMP_ALLOCATE;
644 * Be consistent with file permissions.
646 umask(022);
649 * To minimize confusion, make sure that the standard file descriptors
650 * are open before opening anything else. XXX Work around for 44BSD where
651 * fstat can return EBADF on an open file descriptor.
653 for (fd = 0; fd < 3; fd++)
654 if (fstat(fd, &st) == -1
655 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
656 msg_fatal("open /dev/null: %m");
659 * Process environment options as early as we can. We are not set-uid,
660 * and we are supposed to be running in a controlled environment.
662 if (getenv(CONF_ENV_VERB))
663 msg_verbose = 1;
666 * Initialize. Set up logging, read the global configuration file and
667 * extract configuration information.
669 if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
670 argv[0] = slash + 1;
671 msg_vstream_init(argv[0], VSTREAM_ERR);
672 msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
675 * Parse JCL.
677 while ((ch = GETOPT(argc, argv, "Nc:d:finopq:rsvw")) > 0) {
678 switch (ch) {
679 default:
680 usage(argv[0]);
681 break;
682 case 'N':
683 dict_flags |= DICT_FLAG_TRY1NULL;
684 dict_flags &= ~DICT_FLAG_TRY0NULL;
685 break;
686 case 'c':
687 if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
688 msg_fatal("out of memory");
689 break;
690 case 'd':
691 if (sequence || query || delkey)
692 msg_fatal("specify only one of -s -q or -d");
693 delkey = optarg;
694 break;
695 case 'f':
696 dict_flags &= ~DICT_FLAG_FOLD_FIX;
697 break;
698 case 'i':
699 open_flags &= ~O_TRUNC;
700 break;
701 case 'n':
702 dict_flags |= DICT_FLAG_TRY0NULL;
703 dict_flags &= ~DICT_FLAG_TRY1NULL;
704 break;
705 case 'o':
706 postalias_flags &= ~POSTALIAS_FLAG_AS_OWNER;
707 break;
708 case 'p':
709 postalias_flags &= ~POSTALIAS_FLAG_SAVE_PERM;
710 break;
711 case 'q':
712 if (sequence || query || delkey)
713 msg_fatal("specify only one of -s -q or -d");
714 query = optarg;
715 break;
716 case 'r':
717 dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE);
718 dict_flags |= DICT_FLAG_DUP_REPLACE;
719 break;
720 case 's':
721 if (query || delkey)
722 msg_fatal("specify only one of -s or -q or -d");
723 sequence = 1;
724 break;
725 case 'v':
726 msg_verbose++;
727 break;
728 case 'w':
729 dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_REPLACE);
730 dict_flags |= DICT_FLAG_DUP_IGNORE;
731 break;
734 mail_conf_read();
735 if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
736 msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
737 mail_dict_init();
740 * Use the map type specified by the user, or fall back to a default
741 * database type.
743 if (delkey) { /* remove entry */
744 if (optind + 1 > argc)
745 usage(argv[0]);
746 if (strcmp(delkey, "-") == 0)
747 exit(postalias_deletes(VSTREAM_IN, argv + optind, argc - optind,
748 dict_flags | DICT_FLAG_LOCK) == 0);
749 found = 0;
750 while (optind < argc) {
751 if ((path_name = split_at(argv[optind], ':')) != 0) {
752 found |= postalias_delete(argv[optind], path_name, delkey,
753 dict_flags | DICT_FLAG_LOCK);
754 } else {
755 found |= postalias_delete(var_db_type, argv[optind], delkey,
756 dict_flags | DICT_FLAG_LOCK);
758 optind++;
760 exit(found ? 0 : 1);
761 } else if (query) { /* query map(s) */
762 if (optind + 1 > argc)
763 usage(argv[0]);
764 if (strcmp(query, "-") == 0)
765 exit(postalias_queries(VSTREAM_IN, argv + optind, argc - optind,
766 dict_flags | DICT_FLAG_LOCK) == 0);
767 while (optind < argc) {
768 if ((path_name = split_at(argv[optind], ':')) != 0) {
769 found = postalias_query(argv[optind], path_name, query,
770 dict_flags | DICT_FLAG_LOCK);
771 } else {
772 found = postalias_query(var_db_type, argv[optind], query,
773 dict_flags | DICT_FLAG_LOCK);
775 if (found)
776 exit(0);
777 optind++;
779 exit(1);
780 } else if (sequence) {
781 while (optind < argc) {
782 if ((path_name = split_at(argv[optind], ':')) != 0) {
783 postalias_seq(argv[optind], path_name,
784 dict_flags | DICT_FLAG_LOCK);
785 } else {
786 postalias_seq(var_db_type, argv[optind],
787 dict_flags | DICT_FLAG_LOCK);
789 exit(0);
791 exit(1);
792 } else { /* create/update map(s) */
793 if (optind + 1 > argc)
794 usage(argv[0]);
795 while (optind < argc) {
796 if ((path_name = split_at(argv[optind], ':')) != 0) {
797 postalias(argv[optind], path_name, postalias_flags,
798 open_flags, dict_flags);
799 } else {
800 postalias(var_db_type, argv[optind], postalias_flags,
801 open_flags, dict_flags);
803 optind++;
805 exit(0);