This is smailconf.c in view mode; [Download] [Up]
/* @(#)src/smailconf.c 1.3 18 Feb 1991 16:00:27 */ /* * 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 }, { "sender_env_variable", t_string, NULL, (tup *)&sender_env_variable, 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); /* * 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; } /* * 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; } /* * 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; } /* * 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 */ } #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 */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.