|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 25552 (0x63d0)
Types: TextFile
Names: »smailconf.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦2fafebccf⟧ »EurOpenD3/mail/smail3.1.19.tar.Z«
└─⟦bcd2bc73f⟧
└─⟦this⟧ »src/smailconf.c«
/* @(#)smailconf.c 3.39 3/16/89 23:55:11 */
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*/
/*
* smailconf.c:
* loading and processing for the configuration files
*
* external functions: read_config_file, read_standard_file,
* fill_attributes, find_attribute,
* add_config_stat, is_newconf, make_lib_fn
*/
#ifdef STANDALONE
# ifdef scs
# define void int
# endif /* scs */
#endif /* STANDALONE */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "defs.h"
#include "smail.h"
#include "smailconf.h"
#include "parse.h"
#include "main.h"
#include "exitcodes.h"
#include "dys.h"
#ifndef DEPEND
# include "extern.h"
# include "debug.h"
#endif
/* functions local to this file */
static void print_config_help();
static void print_config_all();
static void print_version_banner();
/* types local to this file */
/*
* config_stat_list is used by add_config_stat() and is_newconf() to
* determine if any configuration files have changed. Optional config
* files which do not exist have a 0 stored in the mtime field.
*/
struct config_stat {
struct config_stat *succ;
char *fn; /* name of config file */
time_t mtime; /* time of last mod */
dev_t dev; /* device file resides on */
ino_t ino; /* inode number for file */
} *config_stat_list = NULL;
/* define the attributes which may be in the config file */
static struct attr_table conf_attributes[] = {
{ "auto_mkdir", t_boolean, NULL, (tup *)&auto_mkdir, 0 },
{ "auto_mkdir_mode", t_int, NULL, (tup *)&auto_mkdir_mode, 0 },
{ "config_file", t_string, NULL, (tup *)&config_file, 0 },
{ "console", t_string, NULL, (tup *)&cons_fn, 0 },
{ "copying_file", t_string, NULL, (tup *)©ing_file, 0 },
{ "date_field", t_string, NULL, (tup *)&date_field, 0 },
{ "delivery_mode", t_string, NULL, (tup *)&delivery_mode_string, 0 },
{ "director_file", t_string, NULL, (tup *)&director_file, 0 },
{ "flock_mailbox", t_boolean, NULL, (tup *)&flock_mailbox, 0 },
{ "fnlock_interval", t_int, NULL, (tup *)&fnlock_interval, 0 },
{ "fnlock_mode", t_int, NULL, (tup *)&fnlock_mode, 0 },
{ "fnlock_retries", t_int, NULL, (tup *)&fnlock_retries, 0 },
{ "grades", t_string, NULL, (tup *)&grades, 0 },
{ "hit_table_len", t_int, NULL, (tup *)&hit_table_len, 0 },
{ "hostnames", t_string, NULL, (tup *)&hostnames, 0 },
{ "hostname", t_string, NULL, (tup *)&hostnames, 0 },
{ "lock_by_name", t_boolean, NULL, (tup *)&lock_by_name, 0 },
{ "lock_mode", t_int, NULL, (tup *)&lock_mode, 0 },
{ "log_mode", t_int, NULL, (tup *)&log_mode, 0 },
{ "logfile", t_string, NULL, (tup *)&log_fn, 0 },
{ "max_hop_count", t_int, NULL, (tup *)&max_hop_count, 0 },
{ "max_load_ave", t_double, NULL, (tup *)&max_load_ave, 0 },
{ "max_message_size", t_long, NULL, (tup *)&max_message_size, 0 },
{ "message_buf_size", t_int, NULL, (tup *)&message_bufsiz, 0 },
{ "message_id_field", t_string, NULL, (tup *)&message_id_field, 0 },
{ "message_log_mode", t_int, NULL, (tup *)&message_log_mode, 0 },
{ "method_dir", t_string, NULL, (tup *)&method_dir, 0 },
{ "more_hostnames", t_string, NULL, (tup *)&more_hostnames, 0 },
{ "nobody", t_string, NULL, (tup *)&nobody, 0 },
{ "open_interval", t_int, NULL, (tup *)&open_interval, 0 },
{ "open_retries", t_int, NULL, (tup *)&open_retries, 0 },
{ "paniclog", t_string, NULL, (tup *)&panic_fn, 0 },
{ "postmaster_address", t_string, NULL, (tup *)&postmaster_address, 0 },
{ "postmaster", t_string, NULL, (tup *)&postmaster_address, 0 },
{ "primary_name", t_string, NULL, (tup *)&primary_name, 0 },
{ "qualify_file", t_string, NULL, (tup *)&qualify_file, 0 },
{ "queue_only", t_boolean, NULL, (tup *)&queue_only, 0 },
{ "received_field", t_string, NULL, (tup *)&received_field, 0 },
{ "require_configs", t_boolean, NULL, (tup *)&require_configs, 0 },
{ "return_path_field", t_string, NULL, (tup *)&return_path_field, 0 },
{ "router_file", t_string, NULL, (tup *)&router_file, 0 },
{ "second_config_file", t_string, NULL, (tup *)&second_config_file, 0 },
{ "smail", t_string, NULL, (tup *)&smail, 0 },
{ "smail_lib_dir", t_string, NULL, (tup *)&smail_lib_dir, 0 },
{ "smart_path", t_string, NULL, (tup *)&smart_path, 0 },
{ "smart_transport", t_string, NULL, (tup *)&smart_transport, 0 },
{ "smart_user", t_string, NULL, (tup *)&smart_user, 0 },
{ "smtp_banner", t_string, NULL, (tup *)&smtp_banner, 0 },
{ "smtp_debug", t_boolean, NULL, (tup *)&smtp_debug, 0 },
{ "spool_dirs", t_string, NULL, (tup *)&spool_dirs, 0 },
{ "spool_grade", t_char, NULL, (tup *)&spool_grade, 0 },
{ "spool_mode", t_int, NULL, (tup *)&spool_mode, 0 },
{ "transport_file", t_string, NULL, (tup *)&transport_file, 0 },
{ "trusted", t_string, NULL, (tup *)&trusted, 0 },
{ "trusted_users", t_string, NULL, (tup *)&trusted, 0 },
{ "trusted_groups", t_string, NULL, (tup *)&trusted_groups, 0 },
#ifdef GLOTZNET
{ "tzoffset", t_int, NULL, (tup *)&tzoffset, 0 },
{ "tznodst", t_boolean, NULL, (tup *)&tznodst, 0 },
#endif /* GLOTZNET */
{ "uucp_name", t_string, NULL, (tup *)&uucp_name, 0 },
{ "version", t_infoproc, NULL, (tup *)version, 0 },
{ "visible_domains", t_string, NULL, (tup *)&visible_domains, 0 },
{ "visible_name", t_string, NULL, (tup *)&visible_name, 0 },
};
struct attr_table *end_conf_attributes = ENDTABLE(conf_attributes);
\f
/*
* read_config_file - read a config file and fill in conf_attributes
*
* return an error message or NULL (if no error).
*/
char *
read_config_file(fn)
char *fn; /* name of a config file */
{
char *entry; /* entry found by read_entry */
FILE *f; /* input file */
struct stat statbuf;
if (fn == NULL || EQ(fn, "-")) {
/* a name of `-' turns off use of the external file */
return NULL;
}
f = fopen(fn, "r");
if (f == NULL) {
if (require_configs) {
return xprintf("%s: %s", fn, strerrno());
}
add_config_stat(fn, (struct stat *)NULL);
return NULL;
}
(void)fstat(fileno(f), &statbuf);
add_config_stat(fn, &statbuf);
/*
* read all of the entries in the config file
*/
while (entry = read_entry(f)) {
char *error;
struct attr_table *conf_attr;
struct attribute *attr = parse_config(entry, &error);
if (attr == NULL) {
return xprintf("%s: parse error: %s", fn, error);
}
conf_attr = find_attribute(attr->name, conf_attributes,
end_conf_attributes);
if (conf_attr == NULL) {
return xprintf("%s: unknown attribute: %s",
fn, attr->name);
}
conf_attr->value = attr->value;
if (conf_attr->type == t_boolean) {
/* make sure boolean types are given as booleans */
if (attr->value != on && attr->value != off) {
return xprintf("%s: boolean attribute %s has non-boolean form",
fn, attr->name);
}
} else {
/* make sure non-boolean types aren't given as booleans */
if ((attr->value == on &&
conf_attr->type != t_proc) ||
(attr->value == off &&
conf_attr->type != t_string &&
conf_attr->type != t_int &&
conf_attr->type != t_long &&
conf_attr->type != t_double &&
conf_attr->type != t_proc))
{
return xprintf("%s: non-boolean attribute %s has boolean form",
fn, attr->name);
}
}
switch (conf_attr->type) {
case t_string:
if (attr->value == off) {
conf_attr->uptr->v_string = NULL;
} else {
conf_attr->uptr->v_string = attr->value;
}
break;
case t_boolean:
conf_attr->uptr->v_boolean =
(int)c_atol(attr->value, &error);
break;
case t_char:
if (strlen(attr->value) != 1) {
return xprintf("%s: bad character constant for attribute %s",
fn, attr->name);
}
conf_attr->uptr->v_char = attr->value[0];
break;
case t_int:
error = NULL;
conf_attr->uptr->v_int = (int)c_atol(attr->value, &error);
if (error) {
return xprintf("%s: attribute %s: %s",
fn, attr->name, error);
}
break;
case t_long:
error = NULL;
conf_attr->uptr->v_long = c_atol(attr->value, &error);
if (error) {
return xprintf("%s: attribute %s: %s",
fn, attr->name, error);
}
break;
case t_double:
{
double val;
char c; /* catch sscanf spill over */
/* should be exactly one item set by sscanf */
if (sscanf(attr->value, "%lf%c", &val, &c) != 1) {
return xprintf(
"%s: attribute %s: malformed floating number %s",
fn, attr->name, attr->value);
}
conf_attr->uptr->v_double = val;
}
break;
case t_proc:
/* if (error = conf_attr->uptr->v_proc(attr)) { */
if (error = (*((char *(*)())conf_attr->uptr))(attr)) {
return xprintf("%s: %s", fn, error);
}
break;
case t_infoproc:
return xprintf("%s: %s: read-only attribute", fn, attr->name);
default:
return xprintf("%s: %s: unknown attribute type", fn, attr->name);
}
}
return NULL;
}
/*
* print_config_variable - write the value for a config variable on stdout
*/
void
print_config_variable(name)
char *name;
{
struct attr_table *conf_attr;
char *value;
if (EQ(name, "help")) {
print_config_help();
return;
}
if (EQ(name, "all")) {
print_config_all();
return;
}
conf_attr = find_attribute(name, conf_attributes, end_conf_attributes);
if (conf_attr == NULL && errfile) {
(void) fprintf(errfile, "%s: unknown attribute: %s\n", program, name);
return;
}
if (conf_attr == NULL) {
return;
}
switch (conf_attr->type) {
case t_string:
if (conf_attr->uptr->v_string) {
value = conf_attr->uptr->v_string;
} else {
value = "";
}
break;
case t_boolean:
if (conf_attr->uptr->v_boolean) {
value = "true";
} else {
value = "false";
}
break;
case t_char:
{
static char charv[2] = "x";
charv[0] = conf_attr->uptr->v_char;
value = charv;
}
break;
case t_int:
{
static char intv[20];
(void) sprintf(intv, "%d", conf_attr->uptr->v_int);
value = intv;
}
break;
case t_long:
{
static char longv[20];
(void) sprintf(longv, "%ld", conf_attr->uptr->v_long);
value = longv;
}
break;
case t_double:
{
static char doublev[20];
(void) sprintf(doublev, "%g", conf_attr->uptr->v_double);
value = doublev;
}
break;
case t_proc:
if (errfile) {
(void) fprintf(errfile, "%s: %s: cannot print proc attributes\n",
program, name);
}
return;
case t_infoproc:
value = (*((char *(*)())conf_attr->uptr))();
break;
default:
if (errfile) {
(void) fprintf(errfile, "%s: %s: unknown type\n");
}
return;
}
if (debug) {
(void) printf("%s=%s\n", name, value);
} else {
(void) printf("%s\n", value);
}
}
/*
* print_config_help - output a listing of all config attributes, with type
*/
static void
print_config_help()
{
register struct attr_table *t;
register tup *last_uptr = NULL;
for (t = conf_attributes; t < end_conf_attributes; t++) {
register char *typename;
if (t->uptr == last_uptr) {
continue;
}
last_uptr = t->uptr;
switch(t->type) {
case t_string: typename = "string"; break;
case t_boolean: typename = "boolean"; break;
case t_char: typename = "char"; break;
case t_int: typename = "int"; break;
case t_long: typename = "long"; break;
case t_double: typename = "double"; break;
case t_proc: typename = "special"; break;
case t_infoproc:typename = "info"; break;
default: typename = "unkown type"; break;
}
(void) printf("%s=%s\n", t->name, typename);
}
}
/*
* print_config_all - print all config file variables
*/
static void
print_config_all()
{
register struct attr_table *t;
register tup *last_uptr = NULL;
int save_debug = debug;
debug = 1;
for (t = conf_attributes; t < end_conf_attributes; t++) {
if (t->uptr == last_uptr) {
continue;
}
last_uptr = t->uptr;
switch(t->type) {
case t_string:
case t_boolean:
case t_char:
case t_int:
case t_long:
case t_double:
case t_infoproc:
print_config_variable(t->name);
break;
default:
(void) printf("%s: unknown type\n", t->name);
break;
}
}
debug = save_debug;
}
\f
/*
* read_standard_file - read (for example) a transport, director or router file
*
* given a template default structure, some information about that structure,
* and an attr_table describing attributes, read a file of standard
* attribute descriptions and return a list describing all of the entries
* in that file.
*
* inputs:
* f - open input file. File format must conform to what is
* expected by read_entry and parse_entry in parse.c.
* template - pointer to the template structure.
* struct_size - size of template structure.
* name_offset - offset to the name element in the template structure.
* flags_offset - offset to flags element of structure.
* succ_offset - offset to succ element of structure.
* attr_table - table defining generic attributes.
* end_attr_table- end of the attribute table
*
* driv_function - function to handle driver attributes for each entry.
* Also, this function can check the validity of the
* generic attributes in the passed structure. The
* function should return NULL, or an error message.
* It is called as:
*
* char *
* f(s, d)
* char *s; --- structure being defined
* struct attribute *d; --- driver attributes
*
* If driv_function is NULL, no driver attributes are
* allowed and no function is called.
* head - pointer to a variable in which to store the head
* of the generated structure list.
*
* output:
* If an error occured, an error message will be returned.
* Otherwise NULL will be returned and a pointer to the new
* structure list will be stored at the location pointed to by
* `head'.
*/
char *
read_standard_file(f, template, struct_size,
name_offset, flags_offset, succ_offset,
attr_table, end_attr_table,
driv_function, head)
FILE *f; /* input file */
register char *template; /* template structure */
int struct_size; /* size of template structure */
int name_offset; /* name field offset in structure */
int flags_offset; /* where to store boolean flags */
int succ_offset; /* where to store succ pointer */
struct attr_table *attr_table; /* start of attribute table */
struct attr_table *end_attr_table; /* e.g., ENDTABLE(attr_table) */
char *(*driv_function)(); /* function to handle driver attrs */
char **head; /* output structure list */
{
char **link_ptr; /* pointer to last succ element */
char *cur; /* current structure to define */
char *s; /* text for current entry */
/* start out with no structure list entries */
link_ptr = head;
*link_ptr = NULL;
/*
* scan through reading entries. For each entry allocate a
* structure and fill it in. Also, link the new structure to the
* previous structure.
*/
while (s = read_entry(f)) {
char *error;
struct attribute *generic_attrs; /* generic attributes for entry */
struct attribute *driver_attrs; /* driver attributes for entry */
char *name; /* name of entry */
/* create the new structure and forward link to it */
*link_ptr = cur = xmalloc(struct_size);
link_ptr = (char **)(cur + succ_offset);
/* fill in the entry structure, starting with the template */
(void) memcpy(cur, template, struct_size);
/* get all of the attributes */
name = parse_entry(s, &generic_attrs, &driver_attrs, &error);
if (name == NULL) {
return error;
}
/* fill in the name */
*(char **)(cur + name_offset) = name;
/*
* fill in the generic attributes, calling attr_function for
* attributes not in attr_table
*/
error = fill_attributes(cur, generic_attrs,
(long *)(cur + flags_offset),
attr_table, end_attr_table);
if (error) {
return error;
}
if (driv_function) {
error = (*driv_function)(cur, driver_attrs);
if (error) {
return error;
}
} else if (driver_attrs) {
return xprintf("no driver attributes allowed in file");
}
}
/* everything went okay */
return NULL;
}
\f
/*
* fill_attributes - build a structure and fill in attributes
*
* Given a list of attributes extracted from one of the configuration
* files and an array of known attributes, fill in a stucture to which
* those attributes pertain.
*
* inputs:
* sp - pointer to stucture that is to be filled in
* attrs - list of given attributes
* flags - pointer to long where boolean flags should be OR'd in
* attr_table - table describing known attributes
* end_attr_table- end of known attribies (i.e., ENDTABLE(attr_table))
*
* output:
* returns either an error message, or NULL if everything went okay.
*/
char *
fill_attributes(sp, attrs, flags, attr_table, end_attr_table)
char *sp;
struct attribute *attrs;
long *flags;
struct attr_table *attr_table;
struct attr_table *end_attr_table;
{
char *error;
/* step through all of the attributes from the file entry */
for (; attrs; attrs = attrs->succ) {
register struct attr_table *t; /* table entry */
register char *value = attrs->value;
/* find the attribute in the list of known attributes */
t = find_attribute(attrs->name, attr_table, end_attr_table);
if (t == NULL) {
/* didn't find the attribute */
return xprintf("%s: unknown attribute", attrs->name);
}
/* what do with this attribute? */
if (t->type == t_boolean) {
/* make sure boolean types are given as booleans */
if (attrs->value != on && attrs->value != off) {
return xprintf("boolean attribute %s has non-boolean form",
attrs->name);
}
} else {
if ((attrs->value == on &&
t->type != t_proc) ||
(attrs->value == off &&
t->type != t_string &&
t->type != t_int &&
t->type != t_long &&
t->type != t_proc))
{
return xprintf("non-boolean attribute %s has boolean form",
attrs->name);
}
}
/* fill in the attribute */
switch (t->type) {
case t_string:
if (value == off) {
*(char **)(sp + t->offset) = NULL;
} else {
*(char **)(sp + t->offset) = value;
}
break;
case t_boolean:
if (value == on) {
*flags |= t->offset;
} else {
*flags &= ~t->offset;
}
break;
case t_char:
if (strlen(attrs->value) != 1) {
return xprintf("bad character constant for attribute %s",
attrs->name);
}
*(sp + t->offset) = value[0];
break;
case t_int:
error = NULL;
*(int *)(sp + t->offset) = (int)c_atol(value, &error);
if (error) {
return xprintf("attribute %s: %s", attrs->name, error);
}
break;
case t_long:
error = NULL;
*(long *)(sp + t->offset) = c_atol(value, &error);
if (error) {
return xprintf("attribute %s: %s", attrs->name, error);
}
break;
case t_double:
{
double val;
char c; /* catch sscanf spill over */
/* should be exactly one item set by sscanf */
if (sscanf(value, "%lf%c", &val, &c) != 1) {
return xprintf(
"attribute %s: malformed floating number %s",
attrs->name, value);
}
*(double *)(sp + t->offset) = val;
}
break;
case t_proc:
/* if (error = t->uptr->v_proc(sp, attrs)) { */
if (error = (*((char *(*)())t->uptr))(sp, attrs)) {
return error;
}
}
}
return NULL;
}
/*
* find_attribute - find an attribute within an attribute table
*/
struct attr_table *
find_attribute(name, table, end)
register char *name; /* name to search for */
register struct attr_table *table; /* table to search in */
register struct attr_table *end; /* end of table */
{
while (table < end) {
if (EQ(name, table->name)) {
return table;
}
table++;
}
return NULL;
}
\f
/*
* add_config_stat - add a new config file to config_stat_list
*
* Pass a filename plus a pointer to a stat structure or NULL.
*/
void
add_config_stat(fn, statp)
char *fn; /* name of file */
struct stat *statp; /* stat of the file, or NULL */
{
struct config_stat *new = (struct config_stat *)xmalloc(sizeof(*new));
new->fn = COPY_STRING(fn);
if (statp) {
new->mtime = statp->st_mtime;
new->dev = statp->st_dev;
new->ino = statp->st_ino;
} else {
new->mtime = (time_t)0;
}
new->succ = config_stat_list;
config_stat_list = new;
}
/*
* is_newconf - check if we have a new set of configuration files
*
* returns TRUE if a configuration fie has changed, FALSE otherwise
*/
int
is_newconf()
{
struct stat statbuf;
struct config_stat *csp;
for (csp = config_stat_list; csp; csp = csp->succ) {
if (stat(csp->fn, &statbuf) < 0) {
if (csp->mtime != (time_t)0) {
/* file no longer exists */
return TRUE;
}
} else {
if (csp->mtime == (time_t)0) {
/* file now exists */
return TRUE;
}
if (csp->mtime != statbuf.st_mtime ||
csp->dev != statbuf.st_dev ||
csp->ino != statbuf.st_ino)
{
/* existing file has changed */
return TRUE;
}
}
}
/* nothing has changed */
return FALSE;
}
/*
* make_lib_fn - build a filename relative to the smail lib directory
*
* If the filename begins with '/' or is "-" return it unmodified.
* Return NULL if smail_lib_dir is undefined, or if the given
* filename is NULL.
*/
char *
make_lib_fn(fn)
char *fn; /* filename to expand */
{
if (fn == NULL) {
return NULL;
}
if (fn[0] == '/' || (fn[0] == '-' && fn[1] == '\0')) {
return fn;
}
if (smail_lib_dir == NULL) {
return NULL;
}
#ifdef GLOTZNET
return xprintf("%s/%s/%s", smail_lib_dir, glotzhost, fn);
#else /* GLOTZNET */
return xprintf("%s/%s", smail_lib_dir, fn);
#endif /* GLOTZNET */
}
\f
#ifdef STANDALONE
#include "varargs.h"
struct transport *transports;
struct director *directors;
struct router *routers;
/*
* find_direct_driver - given a driver's name, return the driver structure
*
* return NULL if driver does not exist.
*/
struct direct_driver *
find_direct_driver(name)
register char *name; /* search key */
{
#ifdef notyet
register struct direct_driver *ddp; /* pointer to table of drivers */
for (ddp = direct_drivers; ddp->name; ddp++) {
if (EQ(ddp->name, name)) {
return ddp; /* found the driver */
}
}
return NULL; /* driver not found */
#else /* notyet */
static struct direct_driver dd = {
NULL, 1, NULL, NULL, NULL, NULL,
};
return ⅆ
#endif /* notyet */
}
/*
* find_transport_driver - given a driver's name, return the driver structure
*
* return NULL if driver does not exist.
*/
struct transport_driver *
find_transport_driver(name)
register char *name; /* search key */
{
#ifdef notyet
register struct transport_driver *tdp; /* pointer to table of drivers */
for (tdp = transport_drivers; tdp->name; tdp++) {
if (EQ(tdp->name, name)) {
return tdp; /* found the driver */
}
}
return NULL; /* driver not found */
#else /* notyet */
static struct transport_driver td = {
NULL, 1, NULL, NULL, NULL, NULL,
};
return &td;
#endif /* notyet */
}
/*
* find_route_driver - given a driver's name, return the driver structure
*
* return NULL if driver does not exist.
*/
struct route_driver *
find_route_driver(name)
register char *name; /* search key */
{
#ifdef notyet
register struct route_driver *rdp; /* pointer to table of drivers */
for (rdp = route_drivers; rdp->name; rdp++) {
if (EQ(rdp->name, name)) {
return rdp; /* found the driver */
}
}
return NULL; /* driver not found */
#else /* notyet */
static struct route_driver rd = {
NULL, 1, NULL, NULL, NULL, NULL,
};
return &rd;
#endif /* notyet */
}
/*VARARGS2*/
void
panic(exitcode, fmt, va_alist)
int exitcode; /* call exit(exitcode) */
char *fmt; /* printf(3) format */
va_dcl /* arguments for printf */
{
va_list ap;
va_start(ap);
(void)fprintf(stderr, "PANIC(%s): ", exitcode);
(void)vfprintf(stderr, fmt, ap);
putc('\n', stderr); /* fatal messages not \n terminated */
va_end(ap);
return_to_sender = TRUE;
exit(exitcode);
}
/*VARARGS2*/
void
write_log(log, fmt, va_alist)
int log; /* TRUE if to write global log file */
char *fmt; /* printf(3) format */
va_dcl /* arguments for printf */
{
va_list ap;
va_start(ap);
(void)fprintf(stderr, log? "PUBLIC: ": "PRIVATE: ");
(void)vfprintf(stderr, fmt, ap);
putc('\n', stderr);
va_end(ap);
}
void
main(argc, argv)
int argc; /* count of arguments */
char *argv[]; /* vector of arguments */
{
char *error;
if (argc != 2) {
(void) fprintf(stderr, "Usage: %s config-file", argv[0]);
/*NOTREACHED*/
}
config_file = argv[1];
if ((error = read_config_file(config_file, CONFIG_PRIMARY)) ||
(second_config_file &&
error = read_config_file(second_config_file, CONFIG_SECONDARY))
(error = read_transport_file()) ||
(error = read_router_file()) ||
(error = read_director_file()) ||
(error = read_qualify_file()))
{
(void) fprintf(stderr, "%s: %s\n", argv[0], error);
}
}
#endif /* STANDALONE */