/*++ /* NAME /* dict_surrogate 3 /* SUMMARY /* surrogate table for graceful "open" failure /* SYNOPSIS /* #include /* /* DICT *dict_surrogate(dict_type, dict_name, /* open_flags, dict_flags, /* format, ...) /* const char *dict_type; /* const char *dict_name; /* int open_flags; /* int dict_flags; /* const char *format; /* /* int dict_allow_surrogate; /* DESCRIPTION /* dict_surrogate() either terminates the program with a fatal /* error, or provides a dummy dictionary that fails all /* operations with an error message, allowing the program to /* continue with reduced functionality. /* /* The global dict_allow_surrogate variable controls the choice /* between fatal error or reduced functionality. The default /* value is zero (fatal error). This is appropriate for user /* commands; the non-default is more appropriate for daemons. /* /* Arguments: /* .IP dict_type /* .IP dict_name /* .IP open_flags /* .IP dict_flags /* The parameters to the failed dictionary open() request. /* .IP format, ... /* The reason why the table could not be opened. This text is /* logged immediately as an "error" class message, and is logged /* as a "warning" class message upon every attempt to access the /* surrogate dictionary, before returning a "failed" completion /* status. /* SEE ALSO /* dict(3) generic dictionary manager /* 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 #include /* Utility library. */ #include #include #include #include /* Application-specific. */ typedef struct { DICT dict; /* generic members */ char *reason; /* open failure reason */ } DICT_SURROGATE; /* dict_surrogate_sequence - fail lookup */ static int dict_surrogate_sequence(DICT *dict, int unused_func, const char **key, const char **value) { DICT_SURROGATE *dp = (DICT_SURROGATE *) dict; msg_warn("%s:%s is unavailable. %s", dict->type, dict->name, dp->reason); DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR); } /* dict_surrogate_update - fail lookup */ static int dict_surrogate_update(DICT *dict, const char *unused_name, const char *unused_value) { DICT_SURROGATE *dp = (DICT_SURROGATE *) dict; msg_warn("%s:%s is unavailable. %s", dict->type, dict->name, dp->reason); DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR); } /* dict_surrogate_lookup - fail lookup */ static const char *dict_surrogate_lookup(DICT *dict, const char *unused_name) { DICT_SURROGATE *dp = (DICT_SURROGATE *) dict; msg_warn("%s:%s is unavailable. %s", dict->type, dict->name, dp->reason); DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0); } /* dict_surrogate_delete - fail delete */ static int dict_surrogate_delete(DICT *dict, const char *unused_name) { DICT_SURROGATE *dp = (DICT_SURROGATE *) dict; msg_warn("%s:%s is unavailable. %s", dict->type, dict->name, dp->reason); DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR); } /* dict_surrogate_close - close fail dictionary */ static void dict_surrogate_close(DICT *dict) { DICT_SURROGATE *dp = (DICT_SURROGATE *) dict; myfree((void *) dp->reason); dict_free(dict); } int dict_allow_surrogate = 0; /* dict_surrogate - terminate or provide surrogate dictionary */ DICT *dict_surrogate(const char *dict_type, const char *dict_name, int open_flags, int dict_flags, const char *fmt,...) { va_list ap; va_list ap2; DICT_SURROGATE *dp; VSTRING *buf; void (*log_fn) (const char *, va_list); int saved_errno = errno; /* * Initialize argument lists. */ va_start(ap, fmt); VA_COPY(ap2, ap); /* * Log the problem immediately when it is detected. The table may not be * accessed in every program execution (that is the whole point of * continuing with reduced functionality) but we don't want the problem * to remain unnoticed until long after a configuration mistake is made. */ log_fn = dict_allow_surrogate ? vmsg_error : vmsg_fatal; log_fn(fmt, ap); va_end(ap); /* * Log the problem upon each access. */ dp = (DICT_SURROGATE *) dict_alloc(dict_type, dict_name, sizeof(*dp)); dp->dict.lookup = dict_surrogate_lookup; if (open_flags & O_RDWR) { dp->dict.update = dict_surrogate_update; dp->dict.delete = dict_surrogate_delete; } dp->dict.sequence = dict_surrogate_sequence; dp->dict.close = dict_surrogate_close; dp->dict.flags = dict_flags | DICT_FLAG_PATTERN; dp->dict.owner.status = DICT_OWNER_TRUSTED; buf = vstring_alloc(10); errno = saved_errno; vstring_vsprintf(buf, fmt, ap2); va_end(ap2); dp->reason = vstring_export(buf); return (DICT_DEBUG (&dp->dict)); }