731 lines
18 KiB
C
731 lines
18 KiB
C
|
/*++
|
||
|
/* NAME
|
||
|
/* postconf 1
|
||
|
/* SUMMARY
|
||
|
/* Postfix configuration utility
|
||
|
/* SYNOPSIS
|
||
|
/* .fi
|
||
|
/* \fBpostconf\fR [\fB-dhmnv\fR] [\fB-c \fIconfig_dir\fR]
|
||
|
/* [\fIparameter ...\fR]
|
||
|
/*
|
||
|
/* \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
|
||
|
/* [\fIparameter=value ...\fR]
|
||
|
/* DESCRIPTION
|
||
|
/* The \fBpostconf\fR command prints the actual value of
|
||
|
/* \fIparameter\fR (all known parameters by default), one
|
||
|
/* parameter per line, changes its value, or prints other
|
||
|
/* information about the Postfix mail system.
|
||
|
/*
|
||
|
/* Options:
|
||
|
/* .IP "\fB-c \fIconfig_dir\fR"
|
||
|
/* The \fBmain.cf\fR configuration file is in the named directory.
|
||
|
/* .IP \fB-d\fR
|
||
|
/* Print default parameter settings instead of actual settings.
|
||
|
/* .IP \fB-e\fR
|
||
|
/* Edit the \fBmain.cf\fR configuration file. The file is copied
|
||
|
/* to a temporary file then renamed into place. Parameters and
|
||
|
/* values are specified on the command line. Use quotes in order
|
||
|
/* to protect shell metacharacters and whitespace.
|
||
|
/* .IP \fB-h\fR
|
||
|
/* Show parameter values only, not the ``name = '' label
|
||
|
/* that normally precedes the value.
|
||
|
/* .IP \fB-m\fR
|
||
|
/* List the names of all supported lookup table types.
|
||
|
/* .IP \fB-n\fR
|
||
|
/* Print non-default parameter settings only.
|
||
|
/* .IP \fB-v\fR
|
||
|
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
|
||
|
/* options make the software increasingly verbose.
|
||
|
/* DIAGNOSTICS
|
||
|
/* Problems are reported to the standard error stream.
|
||
|
/* LICENSE
|
||
|
/* .ad
|
||
|
/* .fi
|
||
|
/* The Secure Mailer license must be distributed with this software.
|
||
|
/* AUTHOR(S)
|
||
|
/* Wietse Venema
|
||
|
/* IBM T.J. Watson Research
|
||
|
/* P.O. Box 704
|
||
|
/* Yorktown Heights, NY 10598, USA
|
||
|
/*--*/
|
||
|
|
||
|
/* System library. */
|
||
|
|
||
|
#include <sys_defs.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <stdio.h> /* rename() */
|
||
|
#include <pwd.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#ifdef STRCASECMP_IN_STRINGS_H
|
||
|
#include <strings.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef USE_PATHS_H
|
||
|
#include <paths.h>
|
||
|
#endif
|
||
|
|
||
|
/* Utility library. */
|
||
|
|
||
|
#include <msg.h>
|
||
|
#include <vstream.h>
|
||
|
#include <msg_vstream.h>
|
||
|
#include <get_hostname.h>
|
||
|
#include <stringops.h>
|
||
|
#include <htable.h>
|
||
|
#include <dict.h>
|
||
|
#include <safe.h>
|
||
|
#include <mymalloc.h>
|
||
|
#include <argv.h>
|
||
|
#include <split_at.h>
|
||
|
#include <readlline.h>
|
||
|
#include <myflock.h>
|
||
|
|
||
|
/* Global library. */
|
||
|
|
||
|
#include <mynetworks.h>
|
||
|
#include <mail_conf.h>
|
||
|
#include <mail_proto.h>
|
||
|
#include <mail_version.h>
|
||
|
#include <mail_params.h>
|
||
|
#include <mail_addr.h>
|
||
|
|
||
|
/*
|
||
|
* What we're supposed to be doing.
|
||
|
*/
|
||
|
#define SHOW_NONDEF (1<<0) /* show non-default settings */
|
||
|
#define SHOW_DEFS (1<<1) /* show default setting */
|
||
|
#define SHOW_NAME (1<<2) /* show parameter name */
|
||
|
#define SHOW_MAPS (1<<3) /* show map types */
|
||
|
#define EDIT_MAIN (1<<4) /* edit main.cf */
|
||
|
|
||
|
/*
|
||
|
* Lookup table for in-core parameter info.
|
||
|
*/
|
||
|
HTABLE *param_table;
|
||
|
|
||
|
/*
|
||
|
* Lookup table for external parameter info.
|
||
|
*/
|
||
|
DICT *text_table;
|
||
|
|
||
|
/*
|
||
|
* Declarations generated by scanning actual C source files.
|
||
|
*/
|
||
|
#include "bool_vars.h"
|
||
|
#include "int_vars.h"
|
||
|
#include "str_vars.h"
|
||
|
|
||
|
/*
|
||
|
* Manually extracted.
|
||
|
*/
|
||
|
#include "local_vars.h"
|
||
|
#include "smtp_vars.h"
|
||
|
|
||
|
/*
|
||
|
* Lookup tables generated by scanning actual C source files.
|
||
|
*/
|
||
|
static CONFIG_BOOL_TABLE bool_table[] = {
|
||
|
#include "bool_table.h"
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
static CONFIG_INT_TABLE int_table[] = {
|
||
|
#include "int_table.h"
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
static CONFIG_STR_TABLE str_table[] = {
|
||
|
#include "str_table.h"
|
||
|
#include "local_table.h" /* XXX */
|
||
|
#include "smtp_table.h" /* XXX */
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* Parameters with default values obtained via function calls.
|
||
|
*/
|
||
|
char *var_myhostname;
|
||
|
char *var_mydomain;
|
||
|
char *var_mynetworks;
|
||
|
|
||
|
static const char *check_myhostname(void);
|
||
|
static const char *check_mydomainname(void);
|
||
|
static const char *check_mynetworks(void);
|
||
|
|
||
|
static CONFIG_STR_FN_TABLE str_fn_table[] = {
|
||
|
VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0,
|
||
|
VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0,
|
||
|
0,
|
||
|
};
|
||
|
static CONFIG_STR_FN_TABLE str_fn_table_2[] = {
|
||
|
VAR_MYNETWORKS, check_mynetworks, &var_mynetworks, 1, 0,
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* XXX Global so that call-backs can see it.
|
||
|
*/
|
||
|
static int mode = SHOW_NAME;
|
||
|
|
||
|
/* check_myhostname - lookup hostname and validate */
|
||
|
|
||
|
static const char *check_myhostname(void)
|
||
|
{
|
||
|
static const char *name;
|
||
|
const char *dot;
|
||
|
const char *domain;
|
||
|
|
||
|
/*
|
||
|
* Use cached result.
|
||
|
*/
|
||
|
if (name)
|
||
|
return (name);
|
||
|
|
||
|
/*
|
||
|
* If the local machine name is not in FQDN form, try to append the
|
||
|
* contents of $mydomain.
|
||
|
*
|
||
|
* XXX Do not complain when running as "postconf -d".
|
||
|
*/
|
||
|
name = get_hostname();
|
||
|
if ((mode & SHOW_DEFS) == 0 && (dot = strchr(name, '.')) == 0) {
|
||
|
if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) {
|
||
|
msg_warn("My hostname %s is not a fully qualified name - set %s or %s in %s/main.cf",
|
||
|
name, VAR_MYHOSTNAME, VAR_MYDOMAIN, var_config_dir);
|
||
|
} else {
|
||
|
name = concatenate(name, ".", domain, (char *) 0);
|
||
|
}
|
||
|
}
|
||
|
return (name);
|
||
|
}
|
||
|
|
||
|
/* get_myhostname - look up and store my hostname */
|
||
|
|
||
|
static void get_myhostname(void)
|
||
|
{
|
||
|
const char *name;
|
||
|
|
||
|
if ((name = dict_lookup(CONFIG_DICT, VAR_MYHOSTNAME)) == 0)
|
||
|
name = check_myhostname();
|
||
|
var_myhostname = mystrdup(name);
|
||
|
}
|
||
|
|
||
|
/* check_mydomainname - lookup domain name and validate */
|
||
|
|
||
|
static const char *check_mydomainname(void)
|
||
|
{
|
||
|
char *dot;
|
||
|
|
||
|
/*
|
||
|
* Use the hostname when it is not a FQDN ("foo"), or when the hostname
|
||
|
* actually is a domain name ("foo.com").
|
||
|
*/
|
||
|
if (var_myhostname == 0)
|
||
|
get_myhostname();
|
||
|
if ((dot = strchr(var_myhostname, '.')) == 0 || strchr(dot + 1, '.') == 0)
|
||
|
return (var_myhostname);
|
||
|
return (dot + 1);
|
||
|
}
|
||
|
|
||
|
/* check_mynetworks - lookup network address list */
|
||
|
|
||
|
static const char *check_mynetworks(void)
|
||
|
{
|
||
|
if (var_inet_interfaces == 0)
|
||
|
var_inet_interfaces = mystrdup(DEF_INET_INTERFACES);
|
||
|
return (mynetworks());
|
||
|
}
|
||
|
|
||
|
/* edit_parameters - edit parameter file */
|
||
|
|
||
|
static void edit_parameters(int argc, char **argv)
|
||
|
{
|
||
|
char *config_dir;
|
||
|
char *path;
|
||
|
char *temp;
|
||
|
VSTREAM *src;
|
||
|
VSTREAM *dst;
|
||
|
VSTRING *buf = vstring_alloc(100);
|
||
|
VSTRING *key = vstring_alloc(10);
|
||
|
char *cp;
|
||
|
char *value;
|
||
|
HTABLE *table;
|
||
|
int first = 1;
|
||
|
struct cvalue {
|
||
|
char *value;
|
||
|
int found;
|
||
|
};
|
||
|
struct cvalue *cvalue;
|
||
|
HTABLE_INFO **ht_info;
|
||
|
HTABLE_INFO **ht;
|
||
|
|
||
|
/*
|
||
|
* Store command-line parameters for quick lookup.
|
||
|
*/
|
||
|
table = htable_create(argc);
|
||
|
while ((cp = *argv++) != 0) {
|
||
|
if ((value = split_at(cp, '=')) == 0
|
||
|
|| *(cp += strspn(cp, " \t\r\n")) == 0)
|
||
|
msg_fatal("edit requires \"key = value\" arguments");
|
||
|
while (*value && ISSPACE(*value))
|
||
|
value++;
|
||
|
cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
|
||
|
cvalue->value = value;
|
||
|
cvalue->found = 0;
|
||
|
htable_enter(table, mystrtok(&cp, " \t\r\n"), (char *) cvalue);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* XXX Avoid code duplication by better code decomposition.
|
||
|
*/
|
||
|
if (var_config_dir)
|
||
|
myfree(var_config_dir);
|
||
|
var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
|
||
|
config_dir : DEF_CONFIG_DIR); /* XXX */
|
||
|
set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
|
||
|
|
||
|
/*
|
||
|
* Open the original file for input.
|
||
|
*/
|
||
|
path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
|
||
|
if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0)
|
||
|
msg_fatal("open %s for reading: %m", path);
|
||
|
|
||
|
/*
|
||
|
* Open a temp file for the result. We use a fixed name so we don't leave
|
||
|
* behind thrash with random names. Lock the temp file to avoid
|
||
|
* accidents. Truncate the file only after we have an exclusive lock.
|
||
|
*/
|
||
|
temp = concatenate(path, ".tmp", (char *) 0);
|
||
|
if ((dst = vstream_fopen(temp, O_CREAT | O_WRONLY, 0644)) == 0)
|
||
|
msg_fatal("open %s: %m", temp);
|
||
|
if (myflock(vstream_fileno(dst), MYFLOCK_EXCLUSIVE) < 0)
|
||
|
msg_fatal("lock %s: %m", temp);
|
||
|
if (ftruncate(vstream_fileno(dst), 0) < 0)
|
||
|
msg_fatal("truncate %s: %m", temp);
|
||
|
|
||
|
/*
|
||
|
* Copy original file to temp file, while replacing parameters on the
|
||
|
* fly. Issue warnings for names found multiple times.
|
||
|
*/
|
||
|
#define STR(x) vstring_str(x)
|
||
|
|
||
|
while (readlline(buf, src, (int *) 0, READLL_KEEPNL)) {
|
||
|
cp = STR(buf);
|
||
|
if (first) {
|
||
|
first = 0;
|
||
|
if (ISSPACE(*cp))
|
||
|
msg_fatal("%s: file starts with whitespace", path);
|
||
|
}
|
||
|
if (*cp == '#') {
|
||
|
vstream_fputs(STR(buf), dst);
|
||
|
continue;
|
||
|
}
|
||
|
cp += strspn(cp, " \t\r\n");
|
||
|
vstring_strncpy(key, cp, strcspn(cp, " \t\r\n="));
|
||
|
cvalue = (struct cvalue *) htable_find(table, STR(key));
|
||
|
if (cvalue == 0) {
|
||
|
vstream_fputs(STR(buf), dst);
|
||
|
} else {
|
||
|
if (cvalue->found++ == 1)
|
||
|
msg_warn("%s: multiple entries for key %s", path, STR(key));
|
||
|
vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Generate new entries for parameters that were not found.
|
||
|
*/
|
||
|
for (ht_info = ht = htable_list(table); *ht; ht++) {
|
||
|
cvalue = (struct cvalue *) ht[0]->value;
|
||
|
if (cvalue->found == 0)
|
||
|
vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
|
||
|
}
|
||
|
myfree((char *) ht_info);
|
||
|
|
||
|
/*
|
||
|
* When all is well, rename the temp file to the original one.
|
||
|
*/
|
||
|
if (vstream_fclose(src))
|
||
|
msg_fatal("read %s: %m", path);
|
||
|
if (vstream_fclose(dst))
|
||
|
msg_fatal("write %s: %m", temp);
|
||
|
if (rename(temp, path) < 0)
|
||
|
msg_fatal("rename %s to %s: %m", temp, path);
|
||
|
|
||
|
/*
|
||
|
* Cleanup.
|
||
|
*/
|
||
|
myfree(path);
|
||
|
myfree(temp);
|
||
|
vstring_free(buf);
|
||
|
vstring_free(key);
|
||
|
htable_free(table, myfree);
|
||
|
}
|
||
|
|
||
|
/* read_parameters - read parameter info from file */
|
||
|
|
||
|
static void read_parameters(void)
|
||
|
{
|
||
|
char *config_dir;
|
||
|
char *path;
|
||
|
|
||
|
/*
|
||
|
* A direct rip-off of mail_conf_read(). XXX Avoid code duplication by
|
||
|
* better code decomposition.
|
||
|
*/
|
||
|
dict_unknown_allowed = 1;
|
||
|
if (var_config_dir)
|
||
|
myfree(var_config_dir);
|
||
|
var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ?
|
||
|
config_dir : DEF_CONFIG_DIR); /* XXX */
|
||
|
set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir);
|
||
|
path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
|
||
|
dict_load_file(CONFIG_DICT, path);
|
||
|
myfree(path);
|
||
|
}
|
||
|
|
||
|
/* hash_parameters - hash all parameter names so we can find and sort them */
|
||
|
|
||
|
static void hash_parameters(void)
|
||
|
{
|
||
|
CONFIG_BOOL_TABLE *cbt;
|
||
|
CONFIG_INT_TABLE *cit;
|
||
|
CONFIG_STR_TABLE *cst;
|
||
|
CONFIG_STR_FN_TABLE *csft;
|
||
|
|
||
|
param_table = htable_create(100);
|
||
|
|
||
|
for (cbt = bool_table; cbt->name; cbt++)
|
||
|
htable_enter(param_table, cbt->name, (char *) cbt);
|
||
|
for (cit = int_table; cit->name; cit++)
|
||
|
htable_enter(param_table, cit->name, (char *) cit);
|
||
|
for (cst = str_table; cst->name; cst++)
|
||
|
htable_enter(param_table, cst->name, (char *) cst);
|
||
|
for (csft = str_fn_table; csft->name; csft++)
|
||
|
htable_enter(param_table, csft->name, (char *) csft);
|
||
|
for (csft = str_fn_table_2; csft->name; csft++)
|
||
|
htable_enter(param_table, csft->name, (char *) csft);
|
||
|
}
|
||
|
|
||
|
/* show_strval - show string-valued parameter */
|
||
|
|
||
|
static void show_strval(int mode, const char *name, const char *value)
|
||
|
{
|
||
|
if (mode & SHOW_NAME) {
|
||
|
vstream_printf("%s = %s\n", name, value);
|
||
|
} else {
|
||
|
vstream_printf("%s\n", value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* show_intval - show integer-valued parameter */
|
||
|
|
||
|
static void show_intval(int mode, const char *name, int value)
|
||
|
{
|
||
|
if (mode & SHOW_NAME) {
|
||
|
vstream_printf("%s = %d\n", name, value);
|
||
|
} else {
|
||
|
vstream_printf("%d\n", value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print_bool - print boolean parameter */
|
||
|
|
||
|
static void print_bool(int mode, CONFIG_BOOL_TABLE *cbt)
|
||
|
{
|
||
|
const char *value;
|
||
|
|
||
|
if (mode & SHOW_DEFS) {
|
||
|
show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
|
||
|
} else {
|
||
|
value = dict_lookup(CONFIG_DICT, cbt->name);
|
||
|
if ((mode & SHOW_NONDEF) == 0) {
|
||
|
if (value == 0) {
|
||
|
show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
|
||
|
} else {
|
||
|
show_strval(mode, cbt->name, value);
|
||
|
}
|
||
|
} else {
|
||
|
if (value != 0)
|
||
|
show_strval(mode, cbt->name, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print_int - print integer parameter */
|
||
|
|
||
|
static void print_int(int mode, CONFIG_INT_TABLE *cit)
|
||
|
{
|
||
|
const char *value;
|
||
|
|
||
|
if (mode & SHOW_DEFS) {
|
||
|
show_intval(mode, cit->name, cit->defval);
|
||
|
} else {
|
||
|
value = dict_lookup(CONFIG_DICT, cit->name);
|
||
|
if ((mode & SHOW_NONDEF) == 0) {
|
||
|
if (value == 0) {
|
||
|
show_intval(mode, cit->name, cit->defval);
|
||
|
} else {
|
||
|
show_strval(mode, cit->name, value);
|
||
|
}
|
||
|
} else {
|
||
|
if (value != 0)
|
||
|
show_strval(mode, cit->name, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print_str - print string parameter */
|
||
|
|
||
|
static void print_str(int mode, CONFIG_STR_TABLE *cst)
|
||
|
{
|
||
|
const char *value;
|
||
|
|
||
|
if (mode & SHOW_DEFS) {
|
||
|
show_strval(mode, cst->name, cst->defval);
|
||
|
} else {
|
||
|
value = dict_lookup(CONFIG_DICT, cst->name);
|
||
|
if ((mode & SHOW_NONDEF) == 0) {
|
||
|
if (value == 0) {
|
||
|
show_strval(mode, cst->name, cst->defval);
|
||
|
} else {
|
||
|
show_strval(mode, cst->name, value);
|
||
|
}
|
||
|
} else {
|
||
|
if (value != 0)
|
||
|
show_strval(mode, cst->name, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print_str_fn - print string-function parameter */
|
||
|
|
||
|
static void print_str_fn(int mode, CONFIG_STR_FN_TABLE *csft)
|
||
|
{
|
||
|
const char *value;
|
||
|
|
||
|
if (mode & SHOW_DEFS) {
|
||
|
show_strval(mode, csft->name, csft->defval());
|
||
|
} else {
|
||
|
value = dict_lookup(CONFIG_DICT, csft->name);
|
||
|
if ((mode & SHOW_NONDEF) == 0) {
|
||
|
if (value == 0) {
|
||
|
show_strval(mode, csft->name, csft->defval());
|
||
|
} else {
|
||
|
show_strval(mode, csft->name, value);
|
||
|
}
|
||
|
} else {
|
||
|
if (value != 0)
|
||
|
show_strval(mode, csft->name, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print_str_fn_2 - print string-function parameter */
|
||
|
|
||
|
static void print_str_fn_2(int mode, CONFIG_STR_FN_TABLE *csft)
|
||
|
{
|
||
|
const char *value;
|
||
|
|
||
|
if (mode & SHOW_DEFS) {
|
||
|
show_strval(mode, csft->name, csft->defval());
|
||
|
} else {
|
||
|
value = dict_lookup(CONFIG_DICT, csft->name);
|
||
|
if ((mode & SHOW_NONDEF) == 0) {
|
||
|
if (value == 0) {
|
||
|
show_strval(mode, csft->name, csft->defval());
|
||
|
} else {
|
||
|
show_strval(mode, csft->name, value);
|
||
|
}
|
||
|
} else {
|
||
|
if (value != 0)
|
||
|
show_strval(mode, csft->name, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print_parameter - show specific parameter */
|
||
|
|
||
|
static void print_parameter(int mode, char *ptr)
|
||
|
{
|
||
|
|
||
|
#define INSIDE(p,t) (ptr >= (char *) t && ptr < ((char *) t) + sizeof(t))
|
||
|
|
||
|
/*
|
||
|
* This is gross, but the best we can do on short notice.
|
||
|
*/
|
||
|
if (INSIDE(ptr, bool_table))
|
||
|
print_bool(mode, (CONFIG_BOOL_TABLE *) ptr);
|
||
|
if (INSIDE(ptr, int_table))
|
||
|
print_int(mode, (CONFIG_INT_TABLE *) ptr);
|
||
|
if (INSIDE(ptr, str_table))
|
||
|
print_str(mode, (CONFIG_STR_TABLE *) ptr);
|
||
|
if (INSIDE(ptr, str_fn_table))
|
||
|
print_str_fn(mode, (CONFIG_STR_FN_TABLE *) ptr);
|
||
|
if (INSIDE(ptr, str_fn_table_2))
|
||
|
print_str_fn_2(mode, (CONFIG_STR_FN_TABLE *) ptr);
|
||
|
if (msg_verbose)
|
||
|
vstream_fflush(VSTREAM_OUT);
|
||
|
}
|
||
|
|
||
|
/* comp_names - qsort helper */
|
||
|
|
||
|
static int comp_names(const void *a, const void *b)
|
||
|
{
|
||
|
HTABLE_INFO **ap = (HTABLE_INFO **) a;
|
||
|
HTABLE_INFO **bp = (HTABLE_INFO **) b;
|
||
|
|
||
|
return (strcmp(ap[0]->key, bp[0]->key));
|
||
|
}
|
||
|
|
||
|
/* show_maps - show available maps */
|
||
|
|
||
|
static void show_maps(void)
|
||
|
{
|
||
|
ARGV *maps_argv;
|
||
|
int i;
|
||
|
|
||
|
maps_argv = dict_mapnames();
|
||
|
for (i = 0; i < maps_argv->argc; i++)
|
||
|
vstream_printf("%s\n", maps_argv->argv[i]);
|
||
|
argv_free(maps_argv);
|
||
|
}
|
||
|
|
||
|
/* show_parameters - show parameter info */
|
||
|
|
||
|
static void show_parameters(int mode, char **names)
|
||
|
{
|
||
|
HTABLE_INFO **list;
|
||
|
HTABLE_INFO **ht;
|
||
|
char **namep;
|
||
|
char *value;
|
||
|
|
||
|
/*
|
||
|
* Show all parameters.
|
||
|
*/
|
||
|
if (*names == 0) {
|
||
|
list = htable_list(param_table);
|
||
|
qsort((char *) list, param_table->used, sizeof(*list), comp_names);
|
||
|
for (ht = list; *ht; ht++)
|
||
|
print_parameter(mode, ht[0]->value);
|
||
|
myfree((char *) list);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Show named parameters.
|
||
|
*/
|
||
|
for (namep = names; *namep; namep++) {
|
||
|
if ((value = htable_find(param_table, *namep)) == 0) {
|
||
|
msg_warn("%s: unknown parameter", *namep);
|
||
|
} else {
|
||
|
print_parameter(mode, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* main */
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
int ch;
|
||
|
int fd;
|
||
|
struct stat st;
|
||
|
int junk;
|
||
|
|
||
|
/*
|
||
|
* Be consistent with file permissions.
|
||
|
*/
|
||
|
umask(022);
|
||
|
|
||
|
/*
|
||
|
* To minimize confusion, make sure that the standard file descriptors
|
||
|
* are open before opening anything else. XXX Work around for 44BSD where
|
||
|
* fstat can return EBADF on an open file descriptor.
|
||
|
*/
|
||
|
for (fd = 0; fd < 3; fd++)
|
||
|
if (fstat(fd, &st) == -1
|
||
|
&& (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
|
||
|
msg_fatal("open /dev/null: %m");
|
||
|
|
||
|
/*
|
||
|
* Set up logging.
|
||
|
*/
|
||
|
msg_vstream_init(argv[0], VSTREAM_ERR);
|
||
|
|
||
|
/*
|
||
|
* Parse JCL.
|
||
|
*/
|
||
|
while ((ch = GETOPT(argc, argv, "c:dehnmv")) > 0) {
|
||
|
switch (ch) {
|
||
|
case 'c':
|
||
|
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||
|
msg_fatal("out of memory");
|
||
|
break;
|
||
|
case 'd':
|
||
|
mode |= SHOW_DEFS;
|
||
|
break;
|
||
|
case 'e':
|
||
|
mode |= EDIT_MAIN;
|
||
|
break;
|
||
|
case 'h':
|
||
|
mode &= ~SHOW_NAME;
|
||
|
break;
|
||
|
case 'm':
|
||
|
mode |= SHOW_MAPS;
|
||
|
break;
|
||
|
case 'n':
|
||
|
mode |= SHOW_NONDEF;
|
||
|
break;
|
||
|
case 'v':
|
||
|
msg_verbose++;
|
||
|
break;
|
||
|
default:
|
||
|
msg_fatal("usage: %s [-c config_dir] [-d (defaults)] [-e (edit)] [-h (no names)] [-m (map types) [-n (non-defaults)] [-v] [name...]", argv[0]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Sanity check.
|
||
|
*/
|
||
|
junk = (mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | EDIT_MAIN));
|
||
|
if (junk != 0 && junk != SHOW_DEFS && junk != SHOW_NONDEF
|
||
|
&& junk != SHOW_MAPS && junk != EDIT_MAIN)
|
||
|
msg_fatal("specify one of -d, -e, -n and -m");
|
||
|
|
||
|
/*
|
||
|
* If showing map types, show them and exit
|
||
|
*/
|
||
|
if (mode & SHOW_MAPS) {
|
||
|
show_maps();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Edit main.cf.
|
||
|
*/
|
||
|
else if (mode & EDIT_MAIN) {
|
||
|
edit_parameters(argc - optind, argv + optind);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If showing non-default values, read main.cf.
|
||
|
*/
|
||
|
else {
|
||
|
if ((mode & SHOW_DEFS) == 0)
|
||
|
read_parameters();
|
||
|
|
||
|
/*
|
||
|
* Throw together all parameters and show the asked values.
|
||
|
*/
|
||
|
hash_parameters();
|
||
|
show_parameters(mode, argv + optind);
|
||
|
}
|
||
|
vstream_fflush(VSTREAM_OUT);
|
||
|
exit(0);
|
||
|
}
|