7 /* Postfix lookup table management
10 /* \fBpostmap\fR [\fB-Nbfhimnoprsvw\fR] [\fB-c \fIconfig_dir\fR]
11 /* [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
12 /* [\fIfile_type\fR:]\fIfile_name\fR ...
14 /* The \fBpostmap\fR(1) command creates or queries one or more Postfix
15 /* lookup tables, or updates an existing one. The input and output
16 /* file formats are expected to be compatible with:
19 /* \fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR
22 /* If the result files do not exist they will be created with the
23 /* same group and other read permissions as their source file.
25 /* While the table update is in progress, signal delivery is
26 /* postponed, and an exclusive, advisory, lock is placed on the
27 /* entire table, in order to avoid surprises in spectator
32 /* The format of a lookup table input file is as follows:
34 /* A table entry has the form
37 /* \fIkey\fR whitespace \fIvalue\fR
40 /* Empty lines and whitespace-only lines are ignored, as
41 /* are lines whose first non-whitespace character is a `#'.
43 /* A logical line starts with non-whitespace text. A line that
44 /* starts with whitespace continues a logical line.
46 /* The \fIkey\fR and \fIvalue\fR are processed as is, except that
47 /* surrounding white space is stripped off. Unlike with Postfix alias
48 /* databases, quotes cannot be used to protect lookup keys that contain
49 /* special characters such as `#' or whitespace.
51 /* By default the lookup key is mapped to lowercase to make
52 /* the lookups case insensitive; as of Postfix 2.3 this case
53 /* folding happens only with tables whose lookup keys are
54 /* fixed-case strings such as btree:, dbm: or hash:. With
55 /* earlier versions, the lookup key is folded even with tables
56 /* where a lookup field can match both upper and lower case
57 /* text, such as regexp: and pcre:. This resulted in loss of
58 /* information with $\fInumber\fR substitutions.
59 /* COMMAND-LINE ARGUMENTS
63 /* Enable message body query mode. When reading lookup keys
64 /* from standard input with "\fB-q -\fR", process the input
65 /* as if it is an email message in RFC 2822 format. Each line
66 /* of body content becomes one lookup key.
68 /* By default, the \fB-b\fR option starts generating lookup
69 /* keys at the first non-header line, and stops when the end
70 /* of the message is reached.
71 /* To simulate \fBbody_checks\fR(5) processing, enable MIME
72 /* parsing with \fB-m\fR. With this, the \fB-b\fR option
73 /* generates no body-style lookup keys for attachment MIME
74 /* headers and for attached message/* headers.
76 /* This feature is available in Postfix version 2.6 and later.
77 /* .IP "\fB-c \fIconfig_dir\fR"
78 /* Read the \fBmain.cf\fR configuration file in the named directory
79 /* instead of the default configuration directory.
80 /* .IP "\fB-d \fIkey\fR"
81 /* Search the specified maps for \fIkey\fR and remove one entry per map.
82 /* The exit status is zero 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. The exit status is zero
86 /* when at least one of the requested keys was found.
88 /* Do not fold the lookup key to lower case while creating or querying
91 /* With Postfix version 2.3 and later, this option has no
92 /* effect for regular expression tables. There, case folding
93 /* is controlled by appending a flag to a pattern.
95 /* Enable message header query mode. When reading lookup keys
96 /* from standard input with "\fB-q -\fR", process the input
97 /* as if it is an email message in RFC 2822 format. Each
98 /* logical header line becomes one lookup key. A multi-line
99 /* header becomes one lookup key with one or more embedded
100 /* newline characters.
102 /* By default, the \fB-h\fR option generates lookup keys until
103 /* the first non-header line is reached.
104 /* To simulate \fBheader_checks\fR(5) processing, enable MIME
105 /* parsing with \fB-m\fR. With this, the \fB-h\fR option also
106 /* generates header-style lookup keys for attachment MIME
107 /* headers and for attached message/* headers.
109 /* This feature is available in Postfix version 2.6 and later.
111 /* Incremental mode. Read entries from standard input and do not
112 /* truncate an existing database. By default, \fBpostmap\fR(1) creates
113 /* a new database from the entries in \fBfile_name\fR.
115 /* Enable MIME parsing with "\fB-b\fR" and "\fB-h\fR".
117 /* This feature is available in Postfix version 2.6 and later.
119 /* Include the terminating null character that terminates lookup keys
120 /* and values. By default, \fBpostmap\fR(1) does whatever is
122 /* the host operating system.
124 /* Don't include the terminating null character that terminates lookup
125 /* keys and values. By default, \fBpostmap\fR(1) does whatever
126 /* is the default for
127 /* the host operating system.
129 /* Do not release root privileges when processing a non-root
130 /* input file. By default, \fBpostmap\fR(1) drops root privileges
131 /* and runs as the source file owner instead.
133 /* Do not inherit the file access permissions from the input file
134 /* when creating a new file. Instead, create a new file with default
135 /* access permissions (mode 0644).
136 /* .IP "\fB-q \fIkey\fR"
137 /* Search the specified maps for \fIkey\fR and write the first value
138 /* found to the standard output stream. The exit status is zero
139 /* when the requested information was found.
141 /* If a key value of \fB-\fR is specified, the program reads key
142 /* values from the standard input stream and writes one line of
143 /* \fIkey value\fR output for each key that was found. The exit
144 /* status is zero when at least one of the requested keys was found.
146 /* When updating a table, do not complain about attempts to update
147 /* existing entries, and make those updates anyway.
149 /* Retrieve all database elements, and write one line of
150 /* \fIkey value\fR output for each element. The elements are
151 /* printed in database order, which is not necessarily the same
152 /* as the original input order.
154 /* This feature is available in Postfix version 2.2 and later,
155 /* and is not available for all database types.
157 /* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
158 /* options make the software increasingly verbose.
160 /* When updating a table, do not complain about attempts to update
161 /* existing entries, and ignore those attempts.
164 /* .IP \fIfile_type\fR
165 /* The database type. To find out what types are supported, use
166 /* the "\fBpostconf -m\fR" command.
168 /* The \fBpostmap\fR(1) command can query any supported file type,
169 /* but it can create only the following file types:
172 /* The output file is a btree file, named \fIfile_name\fB.db\fR.
173 /* This is available on systems with support for \fBdb\fR databases.
175 /* The output consists of one file, named \fIfile_name\fB.cdb\fR.
176 /* This is available on systems with support for \fBcdb\fR databases.
178 /* The output consists of two files, named \fIfile_name\fB.pag\fR and
179 /* \fIfile_name\fB.dir\fR.
180 /* This is available on systems with support for \fBdbm\fR databases.
182 /* The output file is a hashed file, named \fIfile_name\fB.db\fR.
183 /* This is available on systems with support for \fBdb\fR databases.
185 /* The output consists of two files, named \fIfile_name\fB.pag\fR and
186 /* \fIfile_name\fB.dir\fR.
187 /* This is available on systems with support for \fBsdbm\fR databases.
189 /* When no \fIfile_type\fR is specified, the software uses the database
190 /* type specified via the \fBdefault_database_type\fR configuration
193 /* .IP \fIfile_name\fR
194 /* The name of the lookup table source file when rebuilding a database.
196 /* Problems are logged to the standard error stream and to
198 /* No output means that no problems were detected. Duplicate entries are
199 /* skipped and are flagged with a warning.
201 /* \fBpostmap\fR(1) terminates with zero exit status in case of success
202 /* (including successful "\fBpostmap -q\fR" lookup) and terminates
203 /* with non-zero exit status in case of failure.
207 /* .IP \fBMAIL_CONFIG\fR
208 /* Directory with Postfix configuration files.
209 /* .IP \fBMAIL_VERBOSE\fR
210 /* Enable verbose logging for debugging purposes.
211 /* CONFIGURATION PARAMETERS
214 /* The following \fBmain.cf\fR parameters are especially relevant to
216 /* The text below provides only a parameter summary. See
217 /* \fBpostconf\fR(5) for more details including examples.
218 /* .IP "\fBberkeley_db_create_buffer_size (16777216)\fR"
219 /* The per-table I/O buffer size for programs that create Berkeley DB
220 /* hash or btree tables.
221 /* .IP "\fBberkeley_db_read_buffer_size (131072)\fR"
222 /* The per-table I/O buffer size for programs that read Berkeley DB
223 /* hash or btree tables.
224 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
225 /* The default location of the Postfix main.cf and master.cf
226 /* configuration files.
227 /* .IP "\fBdefault_database_type (see 'postconf -d' output)\fR"
228 /* The default database type for use in \fBnewaliases\fR(1), \fBpostalias\fR(1)
229 /* and \fBpostmap\fR(1) commands.
230 /* .IP "\fBsyslog_facility (mail)\fR"
231 /* The syslog facility of Postfix logging.
232 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
233 /* The mail system name that is prepended to the process name in syslog
234 /* records, so that "smtpd" becomes, for example, "postfix/smtpd".
236 /* postalias(1), create/update/query alias database
237 /* postconf(1), supported database types
238 /* postconf(5), configuration parameters
239 /* syslogd(8), system logging
243 /* Use "\fBpostconf readme_directory\fR" or
244 /* "\fBpostconf html_directory\fR" to locate this information.
247 /* DATABASE_README, Postfix lookup table overview
251 /* The Secure Mailer license must be distributed with this software.
254 /* IBM T.J. Watson Research
256 /* Yorktown Heights, NY 10598, USA
259 /* System library. */
261 #include <sys_defs.h>
262 #include <sys/stat.h>
269 /* Utility library. */
272 #include <mymalloc.h>
275 #include <msg_vstream.h>
276 #include <msg_syslog.h>
277 #include <readlline.h>
278 #include <stringops.h>
279 #include <split_at.h>
280 #include <vstring_vstream.h>
281 #include <set_eugid.h>
283 /* Global library. */
285 #include <mail_conf.h>
286 #include <mail_dict.h>
287 #include <mail_params.h>
288 #include <mail_version.h>
290 #include <mail_task.h>
291 #include <dict_proxy.h>
292 #include <mime_state.h>
293 #include <rec_type.h>
295 /* Application-specific. */
297 #define STR vstring_str
298 #define LEN VSTRING_LEN
300 #define POSTMAP_FLAG_AS_OWNER (1<<0) /* open dest as owner of source */
301 #define POSTMAP_FLAG_SAVE_PERM (1<<1) /* copy access permission from source */
302 #define POSTMAP_FLAG_HEADER_KEY (1<<2) /* apply to header text */
303 #define POSTMAP_FLAG_BODY_KEY (1<<3) /* apply to body text */
304 #define POSTMAP_FLAG_MIME_KEY (1<<4) /* enable MIME parsing */
306 #define POSTMAP_FLAG_HB_KEY (POSTMAP_FLAG_HEADER_KEY | POSTMAP_FLAG_BODY_KEY)
307 #define POSTMAP_FLAG_FULL_KEY (POSTMAP_FLAG_BODY_KEY | POSTMAP_FLAG_MIME_KEY)
308 #define POSTMAP_FLAG_ANY_KEY (POSTMAP_FLAG_HB_KEY | POSTMAP_FLAG_MIME_KEY)
311 * MIME Engine call-back state for generating lookup keys from an email
312 * message read from standard input.
315 DICT
**dicts
; /* map handles */
316 char **maps
; /* map names */
317 int map_count
; /* yes, indeed */
318 int dict_flags
; /* query flags */
319 int header_done
; /* past primary header */
320 int found
; /* result */
323 /* postmap - create or update mapping database */
325 static void postmap(char *map_type
, char *path_name
, int postmap_flags
,
326 int open_flags
, int dict_flags
)
329 VSTRING
*line_buffer
;
340 line_buffer
= vstring_alloc(100);
341 if ((open_flags
& O_TRUNC
) == 0) {
342 source_fp
= VSTREAM_IN
;
343 vstream_control(source_fp
, VSTREAM_CTL_PATH
, "stdin", VSTREAM_CTL_END
);
344 } else if (strcmp(map_type
, DICT_TYPE_PROXY
) == 0) {
345 msg_fatal("can't create maps via the proxy service");
346 } else if ((source_fp
= vstream_fopen(path_name
, O_RDONLY
, 0)) == 0) {
347 msg_fatal("open %s: %m", path_name
);
349 if (fstat(vstream_fileno(source_fp
), &st
) < 0)
350 msg_fatal("fstat %s: %m", path_name
);
353 * Turn off group/other read permissions as indicated in the source file.
355 if ((postmap_flags
& POSTMAP_FLAG_SAVE_PERM
) && S_ISREG(st
.st_mode
))
356 saved_mask
= umask(022 | (~st
.st_mode
& 077));
359 * If running as root, run as the owner of the source file, so that the
360 * result shows proper ownership, and so that a bug in postmap does not
361 * allow privilege escalation.
363 if ((postmap_flags
& POSTMAP_FLAG_AS_OWNER
) && getuid() == 0
364 && (st
.st_uid
!= geteuid() || st
.st_gid
!= getegid()))
365 set_eugid(st
.st_uid
, st
.st_gid
);
368 * Open the database, optionally create it when it does not exist,
369 * optionally truncate it when it does exist, and lock out any
372 mkmap
= mkmap_open(map_type
, path_name
, open_flags
, dict_flags
);
375 * And restore the umask, in case it matters.
377 if ((postmap_flags
& POSTMAP_FLAG_SAVE_PERM
) && S_ISREG(st
.st_mode
))
381 * Add records to the database.
384 while (readlline(line_buffer
, source_fp
, &lineno
)) {
387 * Split on the first whitespace character, then trim leading and
388 * trailing whitespace from key and value.
390 key
= STR(line_buffer
);
391 value
= key
+ strcspn(key
, " \t\r\n");
394 while (ISSPACE(*value
))
396 trimblanks(key
, 0)[0] = 0;
397 trimblanks(value
, 0)[0] = 0;
400 * Enforce the "key whitespace value" format. Disallow missing keys
403 if (*key
== 0 || *value
== 0) {
404 msg_warn("%s, line %d: expected format: key whitespace value",
405 VSTREAM_PATH(source_fp
), lineno
);
408 if (key
[strlen(key
) - 1] == ':')
409 msg_warn("%s, line %d: record is in \"key: value\" format; is this an alias file?",
410 VSTREAM_PATH(source_fp
), lineno
);
413 * Store the value under a case-insensitive key.
415 mkmap_append(mkmap
, key
, value
);
419 * Close the mapping database, and release the lock.
424 * Cleanup. We're about to terminate, but it is a good sanity check.
426 vstring_free(line_buffer
);
427 if (source_fp
!= VSTREAM_IN
)
428 vstream_fclose(source_fp
);
431 /* postmap_body - MIME engine body call-back routine */
433 static void postmap_body(void *ptr
, int unused_rec_type
,
438 POSTMAP_KEY_STATE
*state
= (POSTMAP_KEY_STATE
*) ptr
;
439 DICT
**dicts
= state
->dicts
;
440 char **maps
= state
->maps
;
441 int map_count
= state
->map_count
;
442 int dict_flags
= state
->dict_flags
;
443 const char *map_name
;
447 for (n
= 0; n
< map_count
; n
++) {
449 dicts
[n
] = ((map_name
= split_at(maps
[n
], ':')) != 0 ?
450 dict_open3(maps
[n
], map_name
, O_RDONLY
, dict_flags
) :
451 dict_open3(var_db_type
, maps
[n
], O_RDONLY
, dict_flags
));
452 if ((value
= dict_get(dicts
[n
], keybuf
)) != 0) {
454 msg_warn("table %s:%s: key %s: empty string result is not allowed",
455 dicts
[n
]->type
, dicts
[n
]->name
, keybuf
);
456 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
457 dicts
[n
]->type
, dicts
[n
]->name
);
459 vstream_printf("%s %s\n", keybuf
, value
);
466 /* postmap_header - MIME engine header call-back routine */
468 static void postmap_header(void *ptr
, int unused_header_class
,
469 const HEADER_OPTS
*unused_header_info
,
475 * Don't re-invent an already working wheel.
477 postmap_body(ptr
, 0, STR(header_buf
), LEN(header_buf
), offset
);
480 /* postmap_head_end - MIME engine end-of-header call-back routine */
482 static void postmap_head_end(void *ptr
)
484 POSTMAP_KEY_STATE
*state
= (POSTMAP_KEY_STATE
*) ptr
;
487 * Don't process the message body when we only examine primary headers.
489 state
->header_done
= 1;
492 /* postmap_queries - apply multiple requests from stdin */
494 static int postmap_queries(VSTREAM
*in
, char **maps
, const int map_count
,
495 const int postmap_flags
,
496 const int dict_flags
)
499 VSTRING
*keybuf
= vstring_alloc(100);
501 const char *map_name
;
509 msg_panic("postmap_queries: bad map count");
512 * Prepare to open maps lazily.
514 dicts
= (DICT
**) mymalloc(sizeof(*dicts
) * map_count
);
515 for (n
= 0; n
< map_count
; n
++)
519 * Perform all queries. Open maps on the fly, to avoid opening unecessary
522 if ((postmap_flags
& POSTMAP_FLAG_HB_KEY
) == 0) {
523 while (vstring_get_nonl(keybuf
, in
) != VSTREAM_EOF
) {
524 for (n
= 0; n
< map_count
; n
++) {
526 dicts
[n
] = ((map_name
= split_at(maps
[n
], ':')) != 0 ?
527 dict_open3(maps
[n
], map_name
, O_RDONLY
, dict_flags
) :
528 dict_open3(var_db_type
, maps
[n
], O_RDONLY
, dict_flags
));
529 if ((value
= dict_get(dicts
[n
], STR(keybuf
))) != 0) {
531 msg_warn("table %s:%s: key %s: empty string result is not allowed",
532 dicts
[n
]->type
, dicts
[n
]->name
, STR(keybuf
));
533 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
534 dicts
[n
]->type
, dicts
[n
]->name
);
536 vstream_printf("%s %s\n", STR(keybuf
), value
);
543 POSTMAP_KEY_STATE key_state
;
544 MIME_STATE
*mime_state
;
548 * Bundle up the request and instantiate a MIME parsing engine.
550 key_state
.dicts
= dicts
;
551 key_state
.maps
= maps
;
552 key_state
.map_count
= map_count
;
553 key_state
.dict_flags
= dict_flags
;
554 key_state
.header_done
= 0;
557 mime_state_alloc((postmap_flags
& POSTMAP_FLAG_MIME_KEY
) ?
558 0 : MIME_OPT_DISABLE_MIME
,
559 (postmap_flags
& POSTMAP_FLAG_HEADER_KEY
) ?
560 postmap_header
: (MIME_STATE_HEAD_OUT
) 0,
561 (postmap_flags
& POSTMAP_FLAG_FULL_KEY
) ?
562 (MIME_STATE_ANY_END
) 0 : postmap_head_end
,
563 (postmap_flags
& POSTMAP_FLAG_BODY_KEY
) ?
564 postmap_body
: (MIME_STATE_BODY_OUT
) 0,
565 (MIME_STATE_ANY_END
) 0,
566 (MIME_STATE_ERR_PRINT
) 0,
567 (void *) &key_state
);
570 * Process the input message.
572 while (vstring_get_nonl(keybuf
, in
) != VSTREAM_EOF
573 && key_state
.header_done
== 0 && mime_errs
== 0)
574 mime_errs
= mime_state_update(mime_state
, REC_TYPE_NORM
,
575 STR(keybuf
), LEN(keybuf
));
578 * Flush the MIME engine output buffer and tidy up loose ends.
581 mime_errs
= mime_state_update(mime_state
, REC_TYPE_END
, "", 0);
583 msg_fatal("message format error: %s",
584 mime_state_detail(mime_errs
)->text
);
585 mime_state_free(mime_state
);
586 found
= key_state
.found
;
589 vstream_fflush(VSTREAM_OUT
);
594 for (n
= 0; n
< map_count
; n
++)
596 dict_close(dicts
[n
]);
597 myfree((char *) dicts
);
598 vstring_free(keybuf
);
603 /* postmap_query - query a map and print the result to stdout */
605 static int postmap_query(const char *map_type
, const char *map_name
,
606 const char *key
, int dict_flags
)
611 dict
= dict_open3(map_type
, map_name
, O_RDONLY
, dict_flags
);
612 if ((value
= dict_get(dict
, key
)) != 0) {
614 msg_warn("table %s:%s: key %s: empty string result is not allowed",
615 map_type
, map_name
, key
);
616 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
619 vstream_printf("%s\n", value
);
621 vstream_fflush(VSTREAM_OUT
);
626 /* postmap_deletes - apply multiple requests from stdin */
628 static int postmap_deletes(VSTREAM
*in
, char **maps
, const int map_count
,
632 VSTRING
*keybuf
= vstring_alloc(100);
634 const char *map_name
;
642 msg_panic("postmap_deletes: bad map count");
645 * Open maps ahead of time.
647 dicts
= (DICT
**) mymalloc(sizeof(*dicts
) * map_count
);
648 for (n
= 0; n
< map_count
; n
++) {
649 map_name
= split_at(maps
[n
], ':');
650 if (map_name
&& strcmp(maps
[n
], DICT_TYPE_PROXY
) == 0)
651 open_flags
= O_RDWR
| O_CREAT
; /* XXX */
654 dicts
[n
] = (map_name
!= 0 ?
655 dict_open3(maps
[n
], map_name
, open_flags
, dict_flags
) :
656 dict_open3(var_db_type
, maps
[n
], open_flags
, dict_flags
));
660 * Perform all requests.
662 while (vstring_get_nonl(keybuf
, in
) != VSTREAM_EOF
)
663 for (n
= 0; n
< map_count
; n
++)
664 found
|= (dict_del(dicts
[n
], STR(keybuf
)) == 0);
669 for (n
= 0; n
< map_count
; n
++)
671 dict_close(dicts
[n
]);
672 myfree((char *) dicts
);
673 vstring_free(keybuf
);
678 /* postmap_delete - delete a (key, value) pair from a map */
680 static int postmap_delete(const char *map_type
, const char *map_name
,
681 const char *key
, int dict_flags
)
687 if (strcmp(map_type
, DICT_TYPE_PROXY
) == 0)
688 open_flags
= O_RDWR
| O_CREAT
; /* XXX */
691 dict
= dict_open3(map_type
, map_name
, open_flags
, dict_flags
);
692 status
= dict_del(dict
, key
);
694 return (status
== 0);
697 /* postmap_seq - print all map entries to stdout */
699 static void postmap_seq(const char *map_type
, const char *map_name
,
707 if (strcmp(map_type
, DICT_TYPE_PROXY
) == 0)
708 msg_fatal("can't sequence maps via the proxy service");
709 dict
= dict_open3(map_type
, map_name
, O_RDONLY
, dict_flags
);
710 for (func
= DICT_SEQ_FUN_FIRST
; /* void */ ; func
= DICT_SEQ_FUN_NEXT
) {
711 if (dict_seq(dict
, func
, &key
, &value
) != 0)
714 msg_warn("table %s:%s: empty lookup key value is not allowed",
716 } else if (*value
== 0) {
717 msg_warn("table %s:%s: key %s: empty string result is not allowed",
718 map_type
, map_name
, key
);
719 msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
722 vstream_printf("%s %s\n", key
, value
);
724 vstream_fflush(VSTREAM_OUT
);
728 /* usage - explain */
730 static NORETURN
usage(char *myname
)
732 msg_fatal("usage: %s [-Nfinoprsvw] [-c config_dir] [-d key] [-q key] [map_type:]file...",
736 MAIL_VERSION_STAMP_DECLARE
;
738 int main(int argc
, char **argv
)
745 int postmap_flags
= POSTMAP_FLAG_AS_OWNER
| POSTMAP_FLAG_SAVE_PERM
;
746 int open_flags
= O_RDWR
| O_CREAT
| O_TRUNC
;
747 int dict_flags
= DICT_FLAG_DUP_WARN
| DICT_FLAG_FOLD_FIX
;
754 * Fingerprint executables and core dumps.
756 MAIL_VERSION_STAMP_ALLOCATE
;
759 * Be consistent with file permissions.
764 * To minimize confusion, make sure that the standard file descriptors
765 * are open before opening anything else. XXX Work around for 44BSD where
766 * fstat can return EBADF on an open file descriptor.
768 for (fd
= 0; fd
< 3; fd
++)
769 if (fstat(fd
, &st
) == -1
770 && (close(fd
), open("/dev/null", O_RDWR
, 0)) != fd
)
771 msg_fatal("open /dev/null: %m");
774 * Process environment options as early as we can. We are not set-uid,
775 * and we are supposed to be running in a controlled environment.
777 if (getenv(CONF_ENV_VERB
))
781 * Initialize. Set up logging, read the global configuration file and
782 * extract configuration information.
784 if ((slash
= strrchr(argv
[0], '/')) != 0 && slash
[1])
786 msg_vstream_init(argv
[0], VSTREAM_ERR
);
787 msg_syslog_init(mail_task(argv
[0]), LOG_PID
, LOG_FACILITY
);
792 while ((ch
= GETOPT(argc
, argv
, "Nbc:d:fhimnopq:rsvw")) > 0) {
798 dict_flags
|= DICT_FLAG_TRY1NULL
;
799 dict_flags
&= ~DICT_FLAG_TRY0NULL
;
802 postmap_flags
|= POSTMAP_FLAG_BODY_KEY
;
805 if (setenv(CONF_ENV_PATH
, optarg
, 1) < 0)
806 msg_fatal("out of memory");
809 if (sequence
|| query
|| delkey
)
810 msg_fatal("specify only one of -s -q or -d");
814 dict_flags
&= ~DICT_FLAG_FOLD_FIX
;
817 postmap_flags
|= POSTMAP_FLAG_HEADER_KEY
;
820 open_flags
&= ~O_TRUNC
;
823 postmap_flags
|= POSTMAP_FLAG_MIME_KEY
;
826 dict_flags
|= DICT_FLAG_TRY0NULL
;
827 dict_flags
&= ~DICT_FLAG_TRY1NULL
;
830 postmap_flags
&= ~POSTMAP_FLAG_AS_OWNER
;
833 postmap_flags
&= ~POSTMAP_FLAG_SAVE_PERM
;
836 if (sequence
|| query
|| delkey
)
837 msg_fatal("specify only one of -s -q or -d");
841 dict_flags
&= ~(DICT_FLAG_DUP_WARN
| DICT_FLAG_DUP_IGNORE
);
842 dict_flags
|= DICT_FLAG_DUP_REPLACE
;
846 msg_fatal("specify only one of -s or -q or -d");
853 dict_flags
&= ~(DICT_FLAG_DUP_WARN
| DICT_FLAG_DUP_REPLACE
);
854 dict_flags
|= DICT_FLAG_DUP_IGNORE
;
859 if (strcmp(var_syslog_name
, DEF_SYSLOG_NAME
) != 0)
860 msg_syslog_init(mail_task(argv
[0]), LOG_PID
, LOG_FACILITY
);
862 if ((query
== 0 || strcmp(query
, "-") != 0)
863 && (postmap_flags
& POSTMAP_FLAG_ANY_KEY
))
864 msg_fatal("specify -b -h or -m only with \"-q -\"");
867 * Use the map type specified by the user, or fall back to a default
870 if (delkey
) { /* remove entry */
871 if (optind
+ 1 > argc
)
873 if (strcmp(delkey
, "-") == 0)
874 exit(postmap_deletes(VSTREAM_IN
, argv
+ optind
, argc
- optind
,
875 dict_flags
| DICT_FLAG_LOCK
) == 0);
877 while (optind
< argc
) {
878 if ((path_name
= split_at(argv
[optind
], ':')) != 0) {
879 found
|= postmap_delete(argv
[optind
], path_name
, delkey
,
880 dict_flags
| DICT_FLAG_LOCK
);
882 found
|= postmap_delete(var_db_type
, argv
[optind
], delkey
,
883 dict_flags
| DICT_FLAG_LOCK
);
888 } else if (query
) { /* query map(s) */
889 if (optind
+ 1 > argc
)
891 if (strcmp(query
, "-") == 0)
892 exit(postmap_queries(VSTREAM_IN
, argv
+ optind
, argc
- optind
,
893 postmap_flags
, dict_flags
| DICT_FLAG_LOCK
) == 0);
894 while (optind
< argc
) {
895 if ((path_name
= split_at(argv
[optind
], ':')) != 0) {
896 found
= postmap_query(argv
[optind
], path_name
, query
,
897 dict_flags
| DICT_FLAG_LOCK
);
899 found
= postmap_query(var_db_type
, argv
[optind
], query
,
900 dict_flags
| DICT_FLAG_LOCK
);
907 } else if (sequence
) {
908 while (optind
< argc
) {
909 if ((path_name
= split_at(argv
[optind
], ':')) != 0) {
910 postmap_seq(argv
[optind
], path_name
,
911 dict_flags
| DICT_FLAG_LOCK
);
913 postmap_seq(var_db_type
, argv
[optind
],
914 dict_flags
| DICT_FLAG_LOCK
);
919 } else { /* create/update map(s) */
920 if (optind
+ 1 > argc
)
922 while (optind
< argc
) {
923 if ((path_name
= split_at(argv
[optind
], ':')) != 0) {
924 postmap(argv
[optind
], path_name
, postmap_flags
,
925 open_flags
, dict_flags
);
927 postmap(var_db_type
, argv
[optind
], postmap_flags
,
928 open_flags
, dict_flags
);