diff options
Diffstat (limited to 'contrib/sendmail/libsm/exc.c')
-rw-r--r-- | contrib/sendmail/libsm/exc.c | 651 |
1 files changed, 0 insertions, 651 deletions
diff --git a/contrib/sendmail/libsm/exc.c b/contrib/sendmail/libsm/exc.c deleted file mode 100644 index 0bcf17a..0000000 --- a/contrib/sendmail/libsm/exc.c +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. - * All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include <sm/gen.h> -SM_RCSID("@(#)$Id: exc.c,v 1.49 2006/12/19 19:28:09 ca Exp $") - -/* -** exception handling -** For documentation, see exc.html -*/ - -#include <ctype.h> -#include <string.h> - -#include <sm/errstring.h> -#include <sm/exc.h> -#include <sm/heap.h> -#include <sm/string.h> -#include <sm/varargs.h> -#include <sm/io.h> - -const char SmExcMagic[] = "sm_exc"; -const char SmExcTypeMagic[] = "sm_exc_type"; - -/* -** SM_ETYPE_PRINTF -- printf for exception types. -** -** Parameters: -** exc -- exception. -** stream -- file for output. -** -** Returns: -** none. -*/ - -/* -** A simple formatted print function that can be used as the print function -** by most exception types. It prints the printcontext string, interpreting -** occurrences of %0 through %9 as references to the argument vector. -** If exception argument 3 is an int or long, then %3 will print the -** argument in decimal, and %o3 or %x3 will print it in octal or hex. -*/ - -void -sm_etype_printf(exc, stream) - SM_EXC_T *exc; - SM_FILE_T *stream; -{ - size_t n = strlen(exc->exc_type->etype_argformat); - const char *p, *s; - char format; - - for (p = exc->exc_type->etype_printcontext; *p != '\0'; ++p) - { - if (*p != '%') - { - (void) sm_io_putc(stream, SM_TIME_DEFAULT, *p); - continue; - } - ++p; - if (*p == '\0') - { - (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); - break; - } - if (*p == '%') - { - (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); - continue; - } - format = '\0'; - if (isalpha(*p)) - { - format = *p++; - if (*p == '\0') - { - (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); - (void) sm_io_putc(stream, SM_TIME_DEFAULT, - format); - break; - } - } - if (isdigit(*p)) - { - size_t i = *p - '0'; - if (i < n) - { - switch (exc->exc_type->etype_argformat[i]) - { - case 's': - case 'r': - s = exc->exc_argv[i].v_str; - if (s == NULL) - s = "(null)"; - sm_io_fputs(stream, SM_TIME_DEFAULT, s); - continue; - case 'i': - sm_io_fprintf(stream, - SM_TIME_DEFAULT, - format == 'o' ? "%o" - : format == 'x' ? "%x" - : "%d", - exc->exc_argv[i].v_int); - continue; - case 'l': - sm_io_fprintf(stream, - SM_TIME_DEFAULT, - format == 'o' ? "%lo" - : format == 'x' ? "%lx" - : "%ld", - exc->exc_argv[i].v_long); - continue; - case 'e': - sm_exc_write(exc->exc_argv[i].v_exc, - stream); - continue; - } - } - } - (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); - if (format) - (void) sm_io_putc(stream, SM_TIME_DEFAULT, format); - (void) sm_io_putc(stream, SM_TIME_DEFAULT, *p); - } -} - -/* -** Standard exception types. -*/ - -/* -** SM_ETYPE_OS_PRINT -- Print OS related exception. -** -** Parameters: -** exc -- exception. -** stream -- file for output. -** -** Returns: -** none. -*/ - -static void -sm_etype_os_print __P(( - SM_EXC_T *exc, - SM_FILE_T *stream)); - -static void -sm_etype_os_print(exc, stream) - SM_EXC_T *exc; - SM_FILE_T *stream; -{ - int err = exc->exc_argv[0].v_int; - char *syscall = exc->exc_argv[1].v_str; - char *sysargs = exc->exc_argv[2].v_str; - - if (sysargs) - sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s: %s failed: %s", - sysargs, syscall, sm_errstring(err)); - else - sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s failed: %s", syscall, - sm_errstring(err)); -} - -/* -** SmEtypeOs represents the failure of a Unix system call. -** The three arguments are: -** int errno (eg, ENOENT) -** char *syscall (eg, "open") -** char *sysargs (eg, NULL or "/etc/mail/sendmail.cf") -*/ - -const SM_EXC_TYPE_T SmEtypeOs = -{ - SmExcTypeMagic, - "E:sm.os", - "isr", - sm_etype_os_print, - NULL, -}; - -/* -** SmEtypeErr is a completely generic error which should only be -** used in applications and test programs. Libraries should use -** more specific exception codes. -*/ - -const SM_EXC_TYPE_T SmEtypeErr = -{ - SmExcTypeMagic, - "E:sm.err", - "r", - sm_etype_printf, - "%0", -}; - -/* -** SM_EXC_VNEW_X -- Construct a new exception object. -** -** Parameters: -** etype -- type of exception. -** ap -- varargs. -** -** Returns: -** pointer to exception object. -*/ - -/* -** This is an auxiliary function called by sm_exc_new_x and sm_exc_raisenew_x. -** -** If an exception is raised, then to avoid a storage leak, we must: -** (a) Free all storage we have allocated. -** (b) Free all exception arguments in the varargs list. -** Getting this right is tricky. -** -** To see why (b) is required, consider the code fragment -** SM_EXCEPT(exc, "*") -** sm_exc_raisenew_x(&MyEtype, exc); -** SM_END_TRY -** In the normal case, sm_exc_raisenew_x will allocate and raise a new -** exception E that owns exc. When E is eventually freed, exc is also freed. -** In the exceptional case, sm_exc_raisenew_x must free exc before raising -** an out-of-memory exception so that exc is not leaked. -*/ - -static SM_EXC_T *sm_exc_vnew_x __P((const SM_EXC_TYPE_T *, va_list SM_NONVOLATILE)); - -static SM_EXC_T * -sm_exc_vnew_x(etype, ap) - const SM_EXC_TYPE_T *etype; - va_list SM_NONVOLATILE ap; -{ - /* - ** All variables that are modified in the SM_TRY clause and - ** referenced in the SM_EXCEPT clause must be declared volatile. - */ - - /* NOTE: Type of si, i, and argc *must* match */ - SM_EXC_T * volatile exc = NULL; - int volatile si = 0; - SM_VAL_T * volatile argv = NULL; - int i, argc; - - SM_REQUIRE_ISA(etype, SmExcTypeMagic); - argc = strlen(etype->etype_argformat); - SM_TRY - { - /* - ** Step 1. Allocate the exception structure. - ** On failure, scan the varargs list and free all - ** exception arguments. - */ - - exc = sm_malloc_x(sizeof(SM_EXC_T)); - exc->sm_magic = SmExcMagic; - exc->exc_refcount = 1; - exc->exc_type = etype; - exc->exc_argv = NULL; - - /* - ** Step 2. Allocate the argument vector. - ** On failure, free exc, scan the varargs list and free all - ** exception arguments. On success, scan the varargs list, - ** and copy the arguments into argv. - */ - - argv = sm_malloc_x(argc * sizeof(SM_VAL_T)); - exc->exc_argv = argv; - for (i = 0; i < argc; ++i) - { - switch (etype->etype_argformat[i]) - { - case 'i': - argv[i].v_int = SM_VA_ARG(ap, int); - break; - case 'l': - argv[i].v_long = SM_VA_ARG(ap, long); - break; - case 'e': - argv[i].v_exc = SM_VA_ARG(ap, SM_EXC_T*); - break; - case 's': - argv[i].v_str = SM_VA_ARG(ap, char*); - break; - case 'r': - SM_REQUIRE(etype->etype_argformat[i+1] == '\0'); - argv[i].v_str = SM_VA_ARG(ap, char*); - break; - default: - sm_abort("sm_exc_vnew_x: bad argformat '%c'", - etype->etype_argformat[i]); - } - } - - /* - ** Step 3. Scan argv, and allocate space for all - ** string arguments. si is the number of elements - ** of argv that have been processed so far. - ** On failure, free exc, argv, all the exception arguments - ** and all of the strings that have been copied. - */ - - for (si = 0; si < argc; ++si) - { - switch (etype->etype_argformat[si]) - { - case 's': - { - char *str = argv[si].v_str; - if (str != NULL) - argv[si].v_str = sm_strdup_x(str); - } - break; - case 'r': - { - char *fmt = argv[si].v_str; - if (fmt != NULL) - argv[si].v_str = sm_vstringf_x(fmt, ap); - } - break; - } - } - } - SM_EXCEPT(e, "*") - { - if (exc == NULL || argv == NULL) - { - /* - ** Failure in step 1 or step 2. - ** Scan ap and free all exception arguments. - */ - - for (i = 0; i < argc; ++i) - { - switch (etype->etype_argformat[i]) - { - case 'i': - (void) SM_VA_ARG(ap, int); - break; - case 'l': - (void) SM_VA_ARG(ap, long); - break; - case 'e': - sm_exc_free(SM_VA_ARG(ap, SM_EXC_T*)); - break; - case 's': - case 'r': - (void) SM_VA_ARG(ap, char*); - break; - } - } - } - else - { - /* - ** Failure in step 3. Scan argv and free - ** all exception arguments and all string - ** arguments that have been duplicated. - ** Then free argv. - */ - - for (i = 0; i < argc; ++i) - { - switch (etype->etype_argformat[i]) - { - case 'e': - sm_exc_free(argv[i].v_exc); - break; - case 's': - case 'r': - if (i < si) - sm_free(argv[i].v_str); - break; - } - } - sm_free(argv); - } - sm_free(exc); - sm_exc_raise_x(e); - } - SM_END_TRY - - return exc; -} - -/* -** SM_EXC_NEW_X -- Construct a new exception object. -** -** Parameters: -** etype -- type of exception. -** ... -- varargs. -** -** Returns: -** pointer to exception object. -*/ - -SM_EXC_T * -#if SM_VA_STD -sm_exc_new_x( - const SM_EXC_TYPE_T *etype, - ...) -#else /* SM_VA_STD */ -sm_exc_new_x(etype, va_alist) - const SM_EXC_TYPE_T *etype; - va_dcl -#endif /* SM_VA_STD */ -{ - SM_EXC_T *exc; - SM_VA_LOCAL_DECL - - SM_VA_START(ap, etype); - exc = sm_exc_vnew_x(etype, ap); - SM_VA_END(ap); - return exc; -} - -/* -** SM_EXC_FREE -- Destroy a reference to an exception object. -** -** Parameters: -** exc -- exception object. -** -** Returns: -** none. -*/ - -void -sm_exc_free(exc) - SM_EXC_T *exc; -{ - if (exc == NULL) - return; - SM_REQUIRE(exc->sm_magic == SmExcMagic); - if (exc->exc_refcount == 0) - return; - if (--exc->exc_refcount == 0) - { - int i, c; - - for (i = 0; (c = exc->exc_type->etype_argformat[i]) != '\0'; - ++i) - { - switch (c) - { - case 's': - case 'r': - sm_free(exc->exc_argv[i].v_str); - break; - case 'e': - sm_exc_free(exc->exc_argv[i].v_exc); - break; - } - } - exc->sm_magic = NULL; - sm_free(exc->exc_argv); - sm_free(exc); - } -} - -/* -** SM_EXC_MATCH -- Match exception category against a glob pattern. -** -** Parameters: -** exc -- exception. -** pattern -- glob pattern. -** -** Returns: -** true iff match. -*/ - -bool -sm_exc_match(exc, pattern) - SM_EXC_T *exc; - const char *pattern; -{ - if (exc == NULL) - return false; - SM_REQUIRE(exc->sm_magic == SmExcMagic); - return sm_match(exc->exc_type->etype_category, pattern); -} - -/* -** SM_EXC_WRITE -- Write exception message to a stream (wo trailing newline). -** -** Parameters: -** exc -- exception. -** stream -- file for output. -** -** Returns: -** none. -*/ - -void -sm_exc_write(exc, stream) - SM_EXC_T *exc; - SM_FILE_T *stream; -{ - SM_REQUIRE_ISA(exc, SmExcMagic); - exc->exc_type->etype_print(exc, stream); -} - -/* -** SM_EXC_PRINT -- Print exception message to a stream (with trailing newline). -** -** Parameters: -** exc -- exception. -** stream -- file for output. -** -** Returns: -** none. -*/ - -void -sm_exc_print(exc, stream) - SM_EXC_T *exc; - SM_FILE_T *stream; -{ - SM_REQUIRE_ISA(exc, SmExcMagic); - exc->exc_type->etype_print(exc, stream); - (void) sm_io_putc(stream, SM_TIME_DEFAULT, '\n'); -} - -SM_EXC_HANDLER_T *SmExcHandler = NULL; -static SM_EXC_DEFAULT_HANDLER_T SmExcDefaultHandler = NULL; - -/* -** SM_EXC_NEWTHREAD -- Initialize exception handling for new process/thread. -** -** Parameters: -** h -- default exception handler. -** -** Returns: -** none. -*/ - -/* -** Initialize a new process or a new thread by clearing the -** exception handler stack and optionally setting a default -** exception handler function. Call this at the beginning of main, -** or in a new process after calling fork, or in a new thread. -** -** This function is a luxury, not a necessity. -** If h != NULL then you can get the same effect by -** wrapping the body of main, or the body of a forked child -** or a new thread in SM_TRY ... SM_EXCEPT(e,"*") h(e); SM_END_TRY. -*/ - -void -sm_exc_newthread(h) - SM_EXC_DEFAULT_HANDLER_T h; -{ - SmExcHandler = NULL; - SmExcDefaultHandler = h; -} - -/* -** SM_EXC_RAISE_X -- Raise an exception. -** -** Parameters: -** exc -- exception. -** -** Returns: -** doesn't. -*/ - -void SM_DEAD_D -sm_exc_raise_x(exc) - SM_EXC_T *exc; -{ - SM_REQUIRE_ISA(exc, SmExcMagic); - - if (SmExcHandler == NULL) - { - if (SmExcDefaultHandler != NULL) - { - SM_EXC_DEFAULT_HANDLER_T h; - - /* - ** If defined, the default handler is expected - ** to terminate the current thread of execution - ** using exit() or pthread_exit(). - ** If it instead returns normally, then we fall - ** through to the default case below. If it - ** raises an exception, then sm_exc_raise_x is - ** re-entered and, because we set SmExcDefaultHandler - ** to NULL before invoking h, we will again - ** end up in the default case below. - */ - - h = SmExcDefaultHandler; - SmExcDefaultHandler = NULL; - (*h)(exc); - } - - /* - ** No exception handler, so print the error and exit. - ** To override this behaviour on a program wide basis, - ** call sm_exc_newthread or put an exception handler in main(). - ** - ** XXX TODO: map the exception category to an exit code - ** XXX from <sysexits.h>. - */ - - sm_exc_print(exc, smioerr); - exit(255); - } - - if (SmExcHandler->eh_value == NULL) - SmExcHandler->eh_value = exc; - else - sm_exc_free(exc); - - sm_longjmp_nosig(SmExcHandler->eh_context, 1); -} - -/* -** SM_EXC_RAISENEW_X -- shorthand for sm_exc_raise_x(sm_exc_new_x(...)) -** -** Parameters: -** etype -- type of exception. -** ap -- varargs. -** -** Returns: -** none. -*/ - -void SM_DEAD_D -#if SM_VA_STD -sm_exc_raisenew_x( - const SM_EXC_TYPE_T *etype, - ...) -#else -sm_exc_raisenew_x(etype, va_alist) - const SM_EXC_TYPE_T *etype; - va_dcl -#endif -{ - SM_EXC_T *exc; - SM_VA_LOCAL_DECL - - SM_VA_START(ap, etype); - exc = sm_exc_vnew_x(etype, ap); - SM_VA_END(ap); - sm_exc_raise_x(exc); -} |