Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / postconf / postconf.c
blob5d7e1784c38938ee5aa0b3289111fb88e3b92fc7
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* postconf 1
6 /* SUMMARY
7 /* Postfix configuration utility
8 /* SYNOPSIS
9 /* .fi
10 /* \fBpostconf\fR [\fB-dhnv\fR] [\fB-c \fIconfig_dir\fR]
11 /* [\fIparameter ...\fR]
13 /* \fBpostconf\fR [\fB-aAmlv\fR] [\fB-c \fIconfig_dir\fR]
15 /* \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
16 /* [\fIparameter=value ...\fR]
18 /* \fBpostconf\fR [\fB-#v\fR] [\fB-c \fIconfig_dir\fR]
19 /* [\fIparameter ...\fR]
21 /* \fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
22 /* DESCRIPTION
23 /* The \fBpostconf\fR(1) command displays the actual values
24 /* of configuration parameters, changes configuration parameter
25 /* values, or displays other configuration information about
26 /* the Postfix mail system.
28 /* Options:
29 /* .IP \fB-a\fR
30 /* List the available SASL server plug-in types. The SASL
31 /* plug-in type is selected with the \fBsmtpd_sasl_type\fR
32 /* configuration parameter by specifying one of the names
33 /* listed below.
34 /* .RS
35 /* .IP \fBcyrus\fR
36 /* This server plug-in is available when Postfix is built with
37 /* Cyrus SASL support.
38 /* .IP \fBdovecot\fR
39 /* This server plug-in uses the Dovecot authentication server,
40 /* and is available when Postfix is built with any form of SASL
41 /* support.
42 /* .RE
43 /* .IP
44 /* This feature is available with Postfix 2.3 and later.
45 /* .IP \fB-A\fR
46 /* List the available SASL client plug-in types. The SASL
47 /* plug-in type is selected with the \fBsmtp_sasl_type\fR or
48 /* \fBlmtp_sasl_type\fR configuration parameters by specifying
49 /* one of the names listed below.
50 /* .RS
51 /* .IP \fBcyrus\fR
52 /* This client plug-in is available when Postfix is built with
53 /* Cyrus SASL support.
54 /* .RE
55 /* .IP
56 /* This feature is available with Postfix 2.3 and later.
57 /* .IP "\fB-b\fR [\fItemplate_file\fR]"
58 /* Display the message text that appears at the beginning of
59 /* delivery status notification (DSN) messages, with $\fBname\fR
60 /* expressions replaced by actual values. To override the
61 /* built-in message text, specify a template file at the end
62 /* of the command line, or specify a template file in main.cf
63 /* with the \fBbounce_template_file\fR parameter.
64 /* To force selection of the built-in message text templates,
65 /* specify an empty template file name (in shell language: "").
67 /* This feature is available with Postfix 2.3 and later.
68 /* .IP "\fB-c \fIconfig_dir\fR"
69 /* The \fBmain.cf\fR configuration file is in the named directory
70 /* instead of the default configuration directory.
71 /* .IP \fB-d\fR
72 /* Print default parameter settings instead of actual settings.
73 /* .IP \fB-e\fR
74 /* Edit the \fBmain.cf\fR configuration file. The file is copied
75 /* to a temporary file then renamed into place. Parameters and
76 /* values are specified on the command line. Use quotes in order
77 /* to protect shell metacharacters and whitespace.
78 /* .IP \fB-h\fR
79 /* Show parameter values only, not the ``name = '' label
80 /* that normally precedes the value.
81 /* .IP \fB-l\fR
82 /* List the names of all supported mailbox locking methods.
83 /* Postfix supports the following methods:
84 /* .RS
85 /* .IP \fBflock\fR
86 /* A kernel-based advisory locking method for local files only.
87 /* This locking method is available on systems with a BSD
88 /* compatible library.
89 /* .IP \fBfcntl\fR
90 /* A kernel-based advisory locking method for local and remote files.
91 /* .IP \fBdotlock\fR
92 /* An application-level locking method. An application locks a file
93 /* named \fIfilename\fR by creating a file named \fIfilename\fB.lock\fR.
94 /* The application is expected to remove its own lock file, as well as
95 /* stale lock files that were left behind after abnormal termination.
96 /* .RE
97 /* .IP \fB-m\fR
98 /* List the names of all supported lookup table types. In Postfix
99 /* configuration files,
100 /* lookup tables are specified as \fItype\fB:\fIname\fR, where
101 /* \fItype\fR is one of the types listed below. The table \fIname\fR
102 /* syntax depends on the lookup table type as described in the
103 /* DATABASE_README document.
104 /* .RS
105 /* .IP \fBbtree\fR
106 /* A sorted, balanced tree structure.
107 /* This is available on systems with support for Berkeley DB
108 /* databases.
109 /* .IP \fBcdb\fR
110 /* A read-optimized structure with no support for incremental updates.
111 /* This is available on systems with support for CDB databases.
112 /* .IP \fBcidr\fR
113 /* A table that associates values with Classless Inter-Domain Routing
114 /* (CIDR) patterns. This is described in \fBcidr_table\fR(5).
115 /* .IP \fBdbm\fR
116 /* An indexed file type based on hashing.
117 /* This is available on systems with support for DBM databases.
118 /* .IP \fBenviron\fR
119 /* The UNIX process environment array. The lookup key is the variable
120 /* name. Originally implemented for testing, someone may find this
121 /* useful someday.
122 /* .IP \fBhash\fR
123 /* An indexed file type based on hashing.
124 /* This is available on systems with support for Berkeley DB
125 /* databases.
126 /* .IP "\fBldap\fR (read-only)"
127 /* Perform lookups using the LDAP protocol. This is described
128 /* in \fBldap_table\fR(5).
129 /* .IP "\fBmysql\fR (read-only)"
130 /* Perform lookups using the MYSQL protocol. This is described
131 /* in \fBmysql_table\fR(5).
132 /* .IP "\fBpcre\fR (read-only)"
133 /* A lookup table based on Perl Compatible Regular Expressions. The
134 /* file format is described in \fBpcre_table\fR(5).
135 /* .IP "\fBpgsql\fR (read-only)"
136 /* Perform lookups using the PostgreSQL protocol. This is described
137 /* in \fBpgsql_table\fR(5).
138 /* .IP "\fBproxy\fR (read-only)"
139 /* A lookup table that is implemented via the Postfix
140 /* \fBproxymap\fR(8) service. The table name syntax is
141 /* \fItype\fB:\fIname\fR.
142 /* .IP "\fBregexp\fR (read-only)"
143 /* A lookup table based on regular expressions. The file format is
144 /* described in \fBregexp_table\fR(5).
145 /* .IP \fBsdbm\fR
146 /* An indexed file type based on hashing.
147 /* This is available on systems with support for SDBM databases.
148 /* .IP "\fBstatic\fR (read-only)"
149 /* A table that always returns its name as lookup result. For example,
150 /* \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
151 /* result.
152 /* .IP "\fBtcp\fR (read-only)"
153 /* Perform lookups using a simple request-reply protocol that is
154 /* described in \fBtcp_table\fR(5).
155 /* This feature is not included with the stable Postfix release.
156 /* .IP "\fBunix\fR (read-only)"
157 /* A limited way to query the UNIX authentication database. The
158 /* following tables are implemented:
159 /* .RS
160 /*. IP \fBunix:passwd.byname\fR
161 /* The table is the UNIX password database. The key is a login name.
162 /* The result is a password file entry in \fBpasswd\fR(5) format.
163 /* .IP \fBunix:group.byname\fR
164 /* The table is the UNIX group database. The key is a group name.
165 /* The result is a group file entry in \fBgroup\fR(5) format.
166 /* .RE
167 /* .RE
168 /* .IP
169 /* Other table types may exist depending on how Postfix was built.
170 /* .IP \fB-n\fR
171 /* Print parameter settings that are not left at their built-in
172 /* default value, because they are explicitly specified in main.cf.
173 /* .IP "\fB-t\fR [\fItemplate_file\fR]"
174 /* Display the templates for delivery status notification (DSN)
175 /* messages. To override the built-in templates, specify a
176 /* template file at the end of the command line, or specify a
177 /* template file in main.cf with the \fBbounce_template_file\fR
178 /* parameter. To force selection of the built-in templates,
179 /* specify an empty template file name (in shell language:
180 /* "").
182 /* This feature is available with Postfix 2.3 and later.
183 /* .IP \fB-v\fR
184 /* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
185 /* options make the software increasingly verbose.
186 /* .IP \fB-#\fR
187 /* Edit the \fBmain.cf\fR configuration file. The file is copied
188 /* to a temporary file then renamed into place. The parameters
189 /* specified on the command line are commented-out, so that they
190 /* revert to their default values. Specify a list of parameter
191 /* names, not name=value pairs. There is no \fBpostconf\fR command
192 /* to perform the reverse operation.
194 /* This feature is available with Postfix 2.6 and later.
195 /* DIAGNOSTICS
196 /* Problems are reported to the standard error stream.
197 /* ENVIRONMENT
198 /* .ad
199 /* .fi
200 /* .IP \fBMAIL_CONFIG\fR
201 /* Directory with Postfix configuration files.
202 /* CONFIGURATION PARAMETERS
203 /* .ad
204 /* .fi
205 /* The following \fBmain.cf\fR parameters are especially relevant to
206 /* this program.
208 /* The text below provides only a parameter summary. See
209 /* \fBpostconf\fR(5) for more details including examples.
210 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
211 /* The default location of the Postfix main.cf and master.cf
212 /* configuration files.
213 /* .IP "\fBbounce_template_file (empty)\fR"
214 /* Pathname of a configuration file with bounce message templates.
215 /* FILES
216 /* /etc/postfix/main.cf, Postfix configuration parameters
217 /* SEE ALSO
218 /* bounce(5), bounce template file format
219 /* postconf(5), configuration parameters
220 /* README FILES
221 /* .ad
222 /* .fi
223 /* Use "\fBpostconf readme_directory\fR" or
224 /* "\fBpostconf html_directory\fR" to locate this information.
225 /* .na
226 /* .nf
227 /* DATABASE_README, Postfix lookup table overview
228 /* LICENSE
229 /* .ad
230 /* .fi
231 /* The Secure Mailer license must be distributed with this software.
232 /* AUTHOR(S)
233 /* Wietse Venema
234 /* IBM T.J. Watson Research
235 /* P.O. Box 704
236 /* Yorktown Heights, NY 10598, USA
237 /*--*/
239 /* System library. */
241 #include <sys_defs.h>
242 #include <sys/stat.h>
243 #include <stdio.h> /* rename() */
244 #include <pwd.h>
245 #include <string.h>
246 #include <stdlib.h>
247 #include <unistd.h>
248 #include <ctype.h>
250 #ifdef USE_PATHS_H
251 #include <paths.h>
252 #endif
254 /* Utility library. */
256 #include <msg.h>
257 #include <vstream.h>
258 #include <msg_vstream.h>
259 #include <get_hostname.h>
260 #include <stringops.h>
261 #include <htable.h>
262 #include <dict.h>
263 #include <safe.h>
264 #include <mymalloc.h>
265 #include <argv.h>
266 #include <split_at.h>
267 #include <vstring_vstream.h>
268 #include <myflock.h>
269 #include <inet_proto.h>
270 #include <argv.h>
271 #include <edit_file.h>
273 /* Global library. */
275 #include <mynetworks.h>
276 #include <mail_conf.h>
277 #include <mail_dict.h>
278 #include <mail_proto.h>
279 #include <mail_version.h>
280 #include <mail_params.h>
281 #include <mail_addr.h>
282 #include <mbox_conf.h>
283 #include <mail_run.h>
285 /* XSASL library. */
287 #include <xsasl.h>
290 * What we're supposed to be doing.
292 #define SHOW_NONDEF (1<<0) /* show non-default settings */
293 #define SHOW_DEFS (1<<1) /* show default setting */
294 #define SHOW_NAME (1<<2) /* show parameter name */
295 #define SHOW_MAPS (1<<3) /* show map types */
296 #define EDIT_MAIN (1<<4) /* edit main.cf */
297 #define SHOW_LOCKS (1<<5) /* show mailbox lock methods */
298 #define SHOW_EVAL (1<<6) /* expand right-hand sides */
299 #define SHOW_SASL_SERV (1<<7) /* show server auth plugin types */
300 #define SHOW_SASL_CLNT (1<<8) /* show client auth plugin types */
301 #define COMMENT_OUT (1<<9) /* #-out selected main.cf entries */
304 * Lookup table for in-core parameter info.
306 HTABLE *param_table;
309 * Lookup table for external parameter info.
311 DICT *text_table;
314 * Declarations generated by scanning actual C source files.
316 #include "time_vars.h"
317 #include "bool_vars.h"
318 #include "int_vars.h"
319 #include "str_vars.h"
320 #include "raw_vars.h"
321 #include "nint_vars.h"
324 * Manually extracted.
326 #include "auto_vars.h"
327 #include "install_vars.h"
330 * Lookup tables generated by scanning actual C source files.
332 static const CONFIG_TIME_TABLE time_table[] = {
333 #include "time_table.h"
337 static const CONFIG_BOOL_TABLE bool_table[] = {
338 #include "bool_table.h"
342 static const CONFIG_INT_TABLE int_table[] = {
343 #include "int_table.h"
347 static const CONFIG_STR_TABLE str_table[] = {
348 #include "str_table.h"
349 #include "auto_table.h" /* XXX */
350 #include "install_table.h"
354 static const CONFIG_RAW_TABLE raw_table[] = {
355 #include "raw_table.h"
359 static const CONFIG_NINT_TABLE nint_table[] = {
360 #include "nint_table.h"
365 * Parameters with default values obtained via function calls.
367 char *var_myhostname;
368 char *var_mydomain;
369 char *var_mynetworks;
371 static const char *check_myhostname(void);
372 static const char *check_mydomainname(void);
373 static const char *check_mynetworks(void);
375 static const CONFIG_STR_FN_TABLE str_fn_table[] = {
376 VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0,
377 VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0,
380 static const CONFIG_STR_FN_TABLE str_fn_table_2[] = {
381 VAR_MYNETWORKS, check_mynetworks, &var_mynetworks, 1, 0,
386 * XXX Global so that call-backs can see it.
388 static int cmd_mode = SHOW_NAME;
390 /* check_myhostname - lookup hostname and validate */
392 static const char *check_myhostname(void)
394 static const char *name;
395 const char *dot;
396 const char *domain;
399 * Use cached result.
401 if (name)
402 return (name);
405 * If the local machine name is not in FQDN form, try to append the
406 * contents of $mydomain.
408 name = get_hostname();
409 if ((dot = strchr(name, '.')) == 0) {
410 if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0)
411 domain = DEF_MYDOMAIN;
412 name = concatenate(name, ".", domain, (char *) 0);
414 return (name);
417 /* get_myhostname - look up and store my hostname */
419 static void get_myhostname(void)
421 const char *name;
423 if ((name = mail_conf_lookup_eval(VAR_MYHOSTNAME)) == 0)
424 name = check_myhostname();
425 var_myhostname = mystrdup(name);
428 /* check_mydomainname - lookup domain name and validate */
430 static const char *check_mydomainname(void)
432 char *dot;
435 * Use the hostname when it is not a FQDN ("foo"), or when the hostname
436 * actually is a domain name ("foo.com").
438 if (var_myhostname == 0)
439 get_myhostname();
440 if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0)
441 return (DEF_MYDOMAIN);
442 return (dot + 1);
445 /* check_mynetworks - lookup network address list */
447 static const char *check_mynetworks(void)
449 INET_PROTO_INFO *proto_info;
450 const char *junk;
452 if (var_inet_interfaces == 0) {
453 if ((cmd_mode & SHOW_DEFS)
454 || (junk = mail_conf_lookup_eval(VAR_INET_INTERFACES)) == 0)
455 junk = DEF_INET_INTERFACES;
456 var_inet_interfaces = mystrdup(junk);
458 if (var_mynetworks_style == 0) {
459 if ((cmd_mode & SHOW_DEFS)
460 || (junk = mail_conf_lookup_eval(VAR_MYNETWORKS_STYLE)) == 0)
461 junk = DEF_MYNETWORKS_STYLE;
462 var_mynetworks_style = mystrdup(junk);
464 if (var_inet_protocols == 0) {
465 if ((cmd_mode & SHOW_DEFS)
466 || (junk = mail_conf_lookup_eval(VAR_INET_PROTOCOLS)) == 0)
467 junk = DEF_INET_PROTOCOLS;
468 var_inet_protocols = mystrdup(junk);
469 proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
471 return (mynetworks());
474 /* edit_parameters - edit parameter file */
476 static void edit_parameters(int cmd_mode, int argc, char **argv)
478 char *config_dir;
479 char *path;
480 EDIT_FILE *ep;
481 VSTREAM *src;
482 VSTREAM *dst;
483 VSTRING *buf = vstring_alloc(100);
484 VSTRING *key = vstring_alloc(10);
485 char *cp;
486 char *edit_key;
487 char *edit_val;
488 HTABLE *table;
489 struct cvalue {
490 char *value;
491 int found;
493 struct cvalue *cvalue;
494 HTABLE_INFO **ht_info;
495 HTABLE_INFO **ht;
496 int interesting;
497 const char *err;
500 * Store command-line parameters for quick lookup.
502 table = htable_create(argc);
503 while ((cp = *argv++) != 0) {
504 if (strchr(cp, '\n') != 0)
505 msg_fatal("-e or -# accepts no multi-line input");
506 while (ISSPACE(*cp))
507 cp++;
508 if (*cp == '#')
509 msg_fatal("-e or -# accepts no comment input");
510 if (cmd_mode & EDIT_MAIN) {
511 if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0)
512 msg_fatal("%s: \"%s\"", err, cp);
513 } else if (cmd_mode & COMMENT_OUT) {
514 if (*cp == 0)
515 msg_fatal("-# requires non-blank parameter names");
516 if (strchr(cp, '=') != 0)
517 msg_fatal("-# requires parameter names only");
518 edit_key = mystrdup(cp);
519 trimblanks(edit_key, 0);
520 edit_val = 0;
521 } else {
522 msg_panic("edit_parameters: unknown mode %d", cmd_mode);
524 cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
525 cvalue->value = edit_val;
526 cvalue->found = 0;
527 htable_enter(table, edit_key, (char *) cvalue);
531 * XXX Avoid code duplication by better code decomposition.
533 if (var_config_dir)
534 myfree(var_config_dir);
535 var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
536 config_dir : DEF_CONFIG_DIR); /* XXX */
537 set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
540 * Open a temp file for the result. This uses a deterministic name so we
541 * don't leave behind thrash with random names.
543 path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
544 if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
545 msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
546 dst = ep->tmp_fp;
549 * Open the original file for input.
551 if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
552 /* OK to delete, since we control the temp file name exclusively. */
553 (void) unlink(ep->tmp_path);
554 msg_fatal("open %s for reading: %m", path);
558 * Copy original file to temp file, while replacing parameters on the
559 * fly. Issue warnings for names found multiple times.
561 #define STR(x) vstring_str(x)
563 interesting = 0;
564 while (vstring_get(buf, src) != VSTREAM_EOF) {
565 for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
566 /* void */ ;
567 /* Copy comment, all-whitespace, or empty line. */
568 if (*cp == '#' || *cp == 0) {
569 vstream_fputs(STR(buf), dst);
571 /* Copy, skip or replace continued text. */
572 else if (cp > STR(buf)) {
573 if (interesting == 0)
574 vstream_fputs(STR(buf), dst);
575 else if (cmd_mode & COMMENT_OUT)
576 vstream_fprintf(dst, "#%s", STR(buf));
578 /* Copy or replace start of logical line. */
579 else {
580 vstring_strncpy(key, cp, strcspn(cp, " \t\r\n="));
581 cvalue = (struct cvalue *) htable_find(table, STR(key));
582 if ((interesting = !!cvalue) != 0) {
583 if (cvalue->found++ == 1)
584 msg_warn("%s: multiple entries for \"%s\"", path, STR(key));
585 if (cmd_mode & EDIT_MAIN)
586 vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
587 else if (cmd_mode & COMMENT_OUT)
588 vstream_fprintf(dst, "#%s", cp);
589 else
590 msg_panic("edit_parameters: unknown mode %d", cmd_mode);
591 } else {
592 vstream_fputs(STR(buf), dst);
598 * Generate new entries for parameters that were not found.
600 if (cmd_mode & EDIT_MAIN) {
601 for (ht_info = ht = htable_list(table); *ht; ht++) {
602 cvalue = (struct cvalue *) ht[0]->value;
603 if (cvalue->found == 0)
604 vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
606 myfree((char *) ht_info);
610 * When all is well, rename the temp file to the original one.
612 if (vstream_fclose(src))
613 msg_fatal("read %s: %m", path);
614 if (edit_file_close(ep) != 0)
615 msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);
618 * Cleanup.
620 myfree(path);
621 vstring_free(buf);
622 vstring_free(key);
623 htable_free(table, myfree);
626 /* read_parameters - read parameter info from file */
628 static void read_parameters(void)
630 char *config_dir;
631 char *path;
634 * A direct rip-off of mail_conf_read(). XXX Avoid code duplication by
635 * better code decomposition.
637 dict_unknown_allowed = 1;
638 if (var_config_dir)
639 myfree(var_config_dir);
640 var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
641 config_dir : DEF_CONFIG_DIR); /* XXX */
642 set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
643 path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
644 dict_load_file(CONFIG_DICT, path);
645 myfree(path);
648 /* set_parameters - set parameter values from default or explicit setting */
650 static void set_parameters(void)
654 * Populate the configuration parameter dictionary with default settings
655 * or with actual settings.
657 * Iterate over each entry in str_fn_table, str_fn_table_2, time_table,
658 * bool_table, int_table, str_table, and raw_table. Look up each
659 * parameter name in the configuration parameter dictionary. If the
660 * parameter is not set, take the default value, or take the value from
661 * main.cf, without doing $name expansions. This includes converting
662 * default values from numeric/boolean internal forms to external string
663 * form.
665 * Once the configuration parameter dictionary is populated, printing a
666 * parameter setting is a matter of querying the configuration parameter
667 * dictionary, optionally expanding of $name values, and printing the
668 * result.
672 /* hash_parameters - hash all parameter names so we can find and sort them */
674 static void hash_parameters(void)
676 const CONFIG_TIME_TABLE *ctt;
677 const CONFIG_BOOL_TABLE *cbt;
678 const CONFIG_INT_TABLE *cit;
679 const CONFIG_STR_TABLE *cst;
680 const CONFIG_STR_FN_TABLE *csft;
681 const CONFIG_RAW_TABLE *rst;
682 const CONFIG_NINT_TABLE *nst;
684 param_table = htable_create(100);
686 for (ctt = time_table; ctt->name; ctt++)
687 htable_enter(param_table, ctt->name, (char *) ctt);
688 for (cbt = bool_table; cbt->name; cbt++)
689 htable_enter(param_table, cbt->name, (char *) cbt);
690 for (cit = int_table; cit->name; cit++)
691 htable_enter(param_table, cit->name, (char *) cit);
692 for (cst = str_table; cst->name; cst++)
693 htable_enter(param_table, cst->name, (char *) cst);
694 for (csft = str_fn_table; csft->name; csft++)
695 htable_enter(param_table, csft->name, (char *) csft);
696 for (csft = str_fn_table_2; csft->name; csft++)
697 htable_enter(param_table, csft->name, (char *) csft);
698 for (rst = raw_table; rst->name; rst++)
699 htable_enter(param_table, rst->name, (char *) rst);
700 for (nst = nint_table; nst->name; nst++)
701 htable_enter(param_table, nst->name, (char *) nst);
704 /* show_strval - show string-valued parameter */
706 static void show_strval(int mode, const char *name, const char *value)
708 if (mode & SHOW_EVAL)
709 value = mail_conf_eval(value);
711 if (mode & SHOW_NAME) {
712 vstream_printf("%s = %s\n", name, value);
713 } else {
714 vstream_printf("%s\n", value);
718 /* show_intval - show integer-valued parameter */
720 static void show_intval(int mode, const char *name, int value)
722 if (mode & SHOW_NAME) {
723 vstream_printf("%s = %d\n", name, value);
724 } else {
725 vstream_printf("%d\n", value);
729 /* print_bool - print boolean parameter */
731 static void print_bool(int mode, CONFIG_BOOL_TABLE *cbt)
733 const char *value;
735 if (mode & SHOW_DEFS) {
736 show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
737 } else {
738 value = dict_lookup(CONFIG_DICT, cbt->name);
739 if ((mode & SHOW_NONDEF) == 0) {
740 if (value == 0) {
741 show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
742 } else {
743 show_strval(mode, cbt->name, value);
745 } else {
746 if (value != 0)
747 show_strval(mode, cbt->name, value);
752 /* print_time - print relative time parameter */
754 static void print_time(int mode, CONFIG_TIME_TABLE *ctt)
756 const char *value;
758 if (mode & SHOW_DEFS) {
759 show_strval(mode, ctt->name, ctt->defval);
760 } else {
761 value = dict_lookup(CONFIG_DICT, ctt->name);
762 if ((mode & SHOW_NONDEF) == 0) {
763 if (value == 0) {
764 show_strval(mode, ctt->name, ctt->defval);
765 } else {
766 show_strval(mode, ctt->name, value);
768 } else {
769 if (value != 0)
770 show_strval(mode, ctt->name, value);
775 /* print_int - print integer parameter */
777 static void print_int(int mode, CONFIG_INT_TABLE *cit)
779 const char *value;
781 if (mode & SHOW_DEFS) {
782 show_intval(mode, cit->name, cit->defval);
783 } else {
784 value = dict_lookup(CONFIG_DICT, cit->name);
785 if ((mode & SHOW_NONDEF) == 0) {
786 if (value == 0) {
787 show_intval(mode, cit->name, cit->defval);
788 } else {
789 show_strval(mode, cit->name, value);
791 } else {
792 if (value != 0)
793 show_strval(mode, cit->name, value);
798 /* print_str - print string parameter */
800 static void print_str(int mode, CONFIG_STR_TABLE *cst)
802 const char *value;
804 if (mode & SHOW_DEFS) {
805 show_strval(mode, cst->name, cst->defval);
806 } else {
807 value = dict_lookup(CONFIG_DICT, cst->name);
808 if ((mode & SHOW_NONDEF) == 0) {
809 if (value == 0) {
810 show_strval(mode, cst->name, cst->defval);
811 } else {
812 show_strval(mode, cst->name, value);
814 } else {
815 if (value != 0)
816 show_strval(mode, cst->name, value);
821 /* print_str_fn - print string-function parameter */
823 static void print_str_fn(int mode, CONFIG_STR_FN_TABLE *csft)
825 const char *value;
827 if (mode & SHOW_DEFS) {
828 show_strval(mode, csft->name, csft->defval());
829 } else {
830 value = dict_lookup(CONFIG_DICT, csft->name);
831 if ((mode & SHOW_NONDEF) == 0) {
832 if (value == 0) {
833 show_strval(mode, csft->name, csft->defval());
834 } else {
835 show_strval(mode, csft->name, value);
837 } else {
838 if (value != 0)
839 show_strval(mode, csft->name, value);
844 /* print_str_fn_2 - print string-function parameter */
846 static void print_str_fn_2(int mode, CONFIG_STR_FN_TABLE *csft)
848 const char *value;
850 if (mode & SHOW_DEFS) {
851 show_strval(mode, csft->name, csft->defval());
852 } else {
853 value = dict_lookup(CONFIG_DICT, csft->name);
854 if ((mode & SHOW_NONDEF) == 0) {
855 if (value == 0) {
856 show_strval(mode, csft->name, csft->defval());
857 } else {
858 show_strval(mode, csft->name, value);
860 } else {
861 if (value != 0)
862 show_strval(mode, csft->name, value);
867 /* print_raw - print raw string parameter */
869 static void print_raw(int mode, CONFIG_RAW_TABLE * rst)
871 const char *value;
873 if (mode & SHOW_EVAL)
874 msg_warn("parameter %s expands at run-time", rst->name);
875 mode &= ~SHOW_EVAL;
877 if (mode & SHOW_DEFS) {
878 show_strval(mode, rst->name, rst->defval);
879 } else {
880 value = dict_lookup(CONFIG_DICT, rst->name);
881 if ((mode & SHOW_NONDEF) == 0) {
882 if (value == 0) {
883 show_strval(mode, rst->name, rst->defval);
884 } else {
885 show_strval(mode, rst->name, value);
887 } else {
888 if (value != 0)
889 show_strval(mode, rst->name, value);
894 /* print_nint - print new integer parameter */
896 static void print_nint(int mode, CONFIG_NINT_TABLE * rst)
898 const char *value;
900 if (mode & SHOW_EVAL)
901 msg_warn("parameter %s expands at run-time", rst->name);
902 mode &= ~SHOW_EVAL;
904 if (mode & SHOW_DEFS) {
905 show_strval(mode, rst->name, rst->defval);
906 } else {
907 value = dict_lookup(CONFIG_DICT, rst->name);
908 if ((mode & SHOW_NONDEF) == 0) {
909 if (value == 0) {
910 show_strval(mode, rst->name, rst->defval);
911 } else {
912 show_strval(mode, rst->name, value);
914 } else {
915 if (value != 0)
916 show_strval(mode, rst->name, value);
921 /* print_parameter - show specific parameter */
923 static void print_parameter(int mode, char *ptr)
926 #define INSIDE(p,t) (ptr >= (char *) t && ptr < ((char *) t) + sizeof(t))
929 * This is gross, but the best we can do on short notice.
931 if (INSIDE(ptr, time_table))
932 print_time(mode, (CONFIG_TIME_TABLE *) ptr);
933 if (INSIDE(ptr, bool_table))
934 print_bool(mode, (CONFIG_BOOL_TABLE *) ptr);
935 if (INSIDE(ptr, int_table))
936 print_int(mode, (CONFIG_INT_TABLE *) ptr);
937 if (INSIDE(ptr, str_table))
938 print_str(mode, (CONFIG_STR_TABLE *) ptr);
939 if (INSIDE(ptr, str_fn_table))
940 print_str_fn(mode, (CONFIG_STR_FN_TABLE *) ptr);
941 if (INSIDE(ptr, str_fn_table_2))
942 print_str_fn_2(mode, (CONFIG_STR_FN_TABLE *) ptr);
943 if (INSIDE(ptr, raw_table))
944 print_raw(mode, (CONFIG_RAW_TABLE *) ptr);
945 if (INSIDE(ptr, nint_table))
946 print_nint(mode, (CONFIG_NINT_TABLE *) ptr);
947 if (msg_verbose)
948 vstream_fflush(VSTREAM_OUT);
951 /* comp_names - qsort helper */
953 static int comp_names(const void *a, const void *b)
955 HTABLE_INFO **ap = (HTABLE_INFO **) a;
956 HTABLE_INFO **bp = (HTABLE_INFO **) b;
958 return (strcmp(ap[0]->key, bp[0]->key));
961 /* show_maps - show available maps */
963 static void show_maps(void)
965 ARGV *maps_argv;
966 int i;
968 maps_argv = dict_mapnames();
969 for (i = 0; i < maps_argv->argc; i++)
970 vstream_printf("%s\n", maps_argv->argv[i]);
971 argv_free(maps_argv);
974 /* show_locks - show available mailbox locking methods */
976 static void show_locks(void)
978 ARGV *locks_argv;
979 int i;
981 locks_argv = mbox_lock_names();
982 for (i = 0; i < locks_argv->argc; i++)
983 vstream_printf("%s\n", locks_argv->argv[i]);
984 argv_free(locks_argv);
987 /* show_sasl - show SASL plug-in types */
989 static void show_sasl(int what)
991 ARGV *sasl_argv;
992 int i;
994 sasl_argv = (what & SHOW_SASL_SERV) ? xsasl_server_types() :
995 xsasl_client_types();
996 for (i = 0; i < sasl_argv->argc; i++)
997 vstream_printf("%s\n", sasl_argv->argv[i]);
998 argv_free(sasl_argv);
1001 /* show_parameters - show parameter info */
1003 static void show_parameters(int mode, char **names)
1005 HTABLE_INFO **list;
1006 HTABLE_INFO **ht;
1007 char **namep;
1008 char *value;
1011 * Show all parameters.
1013 if (*names == 0) {
1014 list = htable_list(param_table);
1015 qsort((char *) list, param_table->used, sizeof(*list), comp_names);
1016 for (ht = list; *ht; ht++)
1017 print_parameter(mode, ht[0]->value);
1018 myfree((char *) list);
1019 return;
1023 * Show named parameters.
1025 for (namep = names; *namep; namep++) {
1026 if ((value = htable_find(param_table, *namep)) == 0) {
1027 msg_warn("%s: unknown parameter", *namep);
1028 } else {
1029 print_parameter(mode, value);
1034 MAIL_VERSION_STAMP_DECLARE;
1036 /* main */
1038 int main(int argc, char **argv)
1040 int ch;
1041 int fd;
1042 struct stat st;
1043 int junk;
1044 ARGV *ext_argv = 0;
1047 * Fingerprint executables and core dumps.
1049 MAIL_VERSION_STAMP_ALLOCATE;
1052 * Be consistent with file permissions.
1054 umask(022);
1057 * To minimize confusion, make sure that the standard file descriptors
1058 * are open before opening anything else. XXX Work around for 44BSD where
1059 * fstat can return EBADF on an open file descriptor.
1061 for (fd = 0; fd < 3; fd++)
1062 if (fstat(fd, &st) == -1
1063 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
1064 msg_fatal("open /dev/null: %m");
1067 * Set up logging.
1069 msg_vstream_init(argv[0], VSTREAM_ERR);
1072 * Parse JCL.
1074 while ((ch = GETOPT(argc, argv, "aAbc:deE#hmlntv")) > 0) {
1075 switch (ch) {
1076 case 'a':
1077 cmd_mode |= SHOW_SASL_SERV;
1078 break;
1079 case 'A':
1080 cmd_mode |= SHOW_SASL_CLNT;
1081 break;
1082 case 'b':
1083 if (ext_argv)
1084 msg_fatal("specify one of -b and -t");
1085 ext_argv = argv_alloc(2);
1086 argv_add(ext_argv, "bounce", "-SVnexpand_templates", (char *) 0);
1087 break;
1088 case 'c':
1089 if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
1090 msg_fatal("out of memory");
1091 break;
1092 case 'd':
1093 cmd_mode |= SHOW_DEFS;
1094 break;
1095 case 'e':
1096 cmd_mode |= EDIT_MAIN;
1097 break;
1100 * People, this does not work unless you properly handle default
1101 * settings. For example, fast_flush_domains = $relay_domains
1102 * must not evaluate to the empty string when relay_domains is
1103 * left at its default setting of $mydestination.
1105 #if 0
1106 case 'E':
1107 cmd_mode |= SHOW_EVAL;
1108 break;
1109 #endif
1110 case '#':
1111 cmd_mode = COMMENT_OUT;
1112 break;
1114 case 'h':
1115 cmd_mode &= ~SHOW_NAME;
1116 break;
1117 case 'l':
1118 cmd_mode |= SHOW_LOCKS;
1119 break;
1120 case 'm':
1121 cmd_mode |= SHOW_MAPS;
1122 break;
1123 case 'n':
1124 cmd_mode |= SHOW_NONDEF;
1125 break;
1126 case 't':
1127 if (ext_argv)
1128 msg_fatal("specify one of -b and -t");
1129 ext_argv = argv_alloc(2);
1130 argv_add(ext_argv, "bounce", "-SVndump_templates", (char *) 0);
1131 break;
1132 case 'v':
1133 msg_verbose++;
1134 break;
1135 default:
1136 msg_fatal("usage: %s [-a (server SASL types)] [-A (client SASL types)] [-b (bounce templates)] [-c config_dir] [-d (defaults)] [-e (edit)] [-# (comment-out)] [-h (no names)] [-l (lock types)] [-m (map types)] [-n (non-defaults)] [-v] [name...]", argv[0]);
1141 * Sanity check.
1143 junk = (cmd_mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT | COMMENT_OUT));
1144 if (junk != 0 && ((junk != SHOW_DEFS && junk != SHOW_NONDEF
1145 && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN
1146 && junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT
1147 && junk != COMMENT_OUT)
1148 || ext_argv != 0))
1149 msg_fatal("specify one of -a, -A, -b, -d, -e, -#, -m, -l and -n");
1152 * Display bounce template information and exit.
1154 if (ext_argv) {
1155 if (argv[optind]) {
1156 if (argv[optind + 1])
1157 msg_fatal("options -b and -t require at most one template file");
1158 argv_add(ext_argv, "-o",
1159 concatenate(VAR_BOUNCE_TMPL, "=",
1160 argv[optind], (char *) 0),
1161 (char *) 0);
1163 /* Grr... */
1164 argv_add(ext_argv, "-o",
1165 concatenate(VAR_QUEUE_DIR, "=", ".", (char *) 0),
1166 (char *) 0);
1167 mail_conf_read();
1168 mail_run_replace(var_daemon_dir, ext_argv->argv);
1169 /* NOTREACHED */
1173 * If showing map types, show them and exit
1175 if (cmd_mode & SHOW_MAPS) {
1176 mail_dict_init();
1177 show_maps();
1181 * If showing locking methods, show them and exit
1183 else if (cmd_mode & SHOW_LOCKS) {
1184 show_locks();
1188 * If showing SASL plug-in types, show them and exit
1190 else if (cmd_mode & SHOW_SASL_SERV) {
1191 show_sasl(SHOW_SASL_SERV);
1192 } else if (cmd_mode & SHOW_SASL_CLNT) {
1193 show_sasl(SHOW_SASL_CLNT);
1197 * Edit main.cf.
1199 else if (cmd_mode & (EDIT_MAIN | COMMENT_OUT)) {
1200 edit_parameters(cmd_mode, argc - optind, argv + optind);
1204 * If showing non-default values, read main.cf.
1206 else {
1207 if ((cmd_mode & SHOW_DEFS) == 0) {
1208 read_parameters();
1209 set_parameters();
1213 * Throw together all parameters and show the asked values.
1215 hash_parameters();
1216 show_parameters(cmd_mode, argv + optind);
1218 vstream_fflush(VSTREAM_OUT);
1219 exit(0);