190792Sgshapiro/* 2261363Sgshapiro * Copyright (c) 2000-2002 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro * 990792Sgshapiro */ 1090792Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12266692SgshapiroSM_RCSID("@(#)$Id: exc.c,v 1.50 2013-11-22 20:51:42 ca Exp $") 1390792Sgshapiro 1490792Sgshapiro/* 1590792Sgshapiro** exception handling 1690792Sgshapiro** For documentation, see exc.html 1790792Sgshapiro*/ 1890792Sgshapiro 1990792Sgshapiro#include <ctype.h> 2090792Sgshapiro#include <string.h> 2190792Sgshapiro 2290792Sgshapiro#include <sm/errstring.h> 2390792Sgshapiro#include <sm/exc.h> 2490792Sgshapiro#include <sm/heap.h> 2590792Sgshapiro#include <sm/string.h> 2690792Sgshapiro#include <sm/varargs.h> 2790792Sgshapiro#include <sm/io.h> 2890792Sgshapiro 2990792Sgshapiroconst char SmExcMagic[] = "sm_exc"; 3090792Sgshapiroconst char SmExcTypeMagic[] = "sm_exc_type"; 3190792Sgshapiro 3290792Sgshapiro/* 3390792Sgshapiro** SM_ETYPE_PRINTF -- printf for exception types. 3490792Sgshapiro** 3590792Sgshapiro** Parameters: 3690792Sgshapiro** exc -- exception. 3790792Sgshapiro** stream -- file for output. 3890792Sgshapiro** 3990792Sgshapiro** Returns: 4090792Sgshapiro** none. 4190792Sgshapiro*/ 4290792Sgshapiro 4390792Sgshapiro/* 4490792Sgshapiro** A simple formatted print function that can be used as the print function 4590792Sgshapiro** by most exception types. It prints the printcontext string, interpreting 4690792Sgshapiro** occurrences of %0 through %9 as references to the argument vector. 4790792Sgshapiro** If exception argument 3 is an int or long, then %3 will print the 4890792Sgshapiro** argument in decimal, and %o3 or %x3 will print it in octal or hex. 4990792Sgshapiro*/ 5090792Sgshapiro 5190792Sgshapirovoid 5290792Sgshapirosm_etype_printf(exc, stream) 5390792Sgshapiro SM_EXC_T *exc; 5490792Sgshapiro SM_FILE_T *stream; 5590792Sgshapiro{ 5690792Sgshapiro size_t n = strlen(exc->exc_type->etype_argformat); 5790792Sgshapiro const char *p, *s; 5890792Sgshapiro char format; 5990792Sgshapiro 6090792Sgshapiro for (p = exc->exc_type->etype_printcontext; *p != '\0'; ++p) 6190792Sgshapiro { 6290792Sgshapiro if (*p != '%') 6390792Sgshapiro { 6490792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, *p); 6590792Sgshapiro continue; 6690792Sgshapiro } 6790792Sgshapiro ++p; 6890792Sgshapiro if (*p == '\0') 6990792Sgshapiro { 7090792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); 7190792Sgshapiro break; 7290792Sgshapiro } 7390792Sgshapiro if (*p == '%') 7490792Sgshapiro { 7590792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); 7690792Sgshapiro continue; 7790792Sgshapiro } 7890792Sgshapiro format = '\0'; 7990792Sgshapiro if (isalpha(*p)) 8090792Sgshapiro { 8190792Sgshapiro format = *p++; 8290792Sgshapiro if (*p == '\0') 8390792Sgshapiro { 8490792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); 8590792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, 8690792Sgshapiro format); 8790792Sgshapiro break; 8890792Sgshapiro } 8990792Sgshapiro } 9090792Sgshapiro if (isdigit(*p)) 9190792Sgshapiro { 9290792Sgshapiro size_t i = *p - '0'; 9390792Sgshapiro if (i < n) 9490792Sgshapiro { 9590792Sgshapiro switch (exc->exc_type->etype_argformat[i]) 9690792Sgshapiro { 9790792Sgshapiro case 's': 9890792Sgshapiro case 'r': 9990792Sgshapiro s = exc->exc_argv[i].v_str; 10090792Sgshapiro if (s == NULL) 10190792Sgshapiro s = "(null)"; 10290792Sgshapiro sm_io_fputs(stream, SM_TIME_DEFAULT, s); 10390792Sgshapiro continue; 10490792Sgshapiro case 'i': 10590792Sgshapiro sm_io_fprintf(stream, 10690792Sgshapiro SM_TIME_DEFAULT, 10790792Sgshapiro format == 'o' ? "%o" 10890792Sgshapiro : format == 'x' ? "%x" 10990792Sgshapiro : "%d", 11090792Sgshapiro exc->exc_argv[i].v_int); 11190792Sgshapiro continue; 11290792Sgshapiro case 'l': 11390792Sgshapiro sm_io_fprintf(stream, 11490792Sgshapiro SM_TIME_DEFAULT, 11590792Sgshapiro format == 'o' ? "%lo" 11690792Sgshapiro : format == 'x' ? "%lx" 11790792Sgshapiro : "%ld", 11890792Sgshapiro exc->exc_argv[i].v_long); 11990792Sgshapiro continue; 12090792Sgshapiro case 'e': 12190792Sgshapiro sm_exc_write(exc->exc_argv[i].v_exc, 12290792Sgshapiro stream); 12390792Sgshapiro continue; 12490792Sgshapiro } 12590792Sgshapiro } 12690792Sgshapiro } 12790792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, '%'); 12890792Sgshapiro if (format) 12990792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, format); 13090792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, *p); 13190792Sgshapiro } 13290792Sgshapiro} 13390792Sgshapiro 13490792Sgshapiro/* 13590792Sgshapiro** Standard exception types. 13690792Sgshapiro*/ 13790792Sgshapiro 13890792Sgshapiro/* 13990792Sgshapiro** SM_ETYPE_OS_PRINT -- Print OS related exception. 14090792Sgshapiro** 14190792Sgshapiro** Parameters: 14290792Sgshapiro** exc -- exception. 14390792Sgshapiro** stream -- file for output. 14490792Sgshapiro** 14590792Sgshapiro** Returns: 14690792Sgshapiro** none. 14790792Sgshapiro*/ 14890792Sgshapiro 14990792Sgshapirostatic void 15090792Sgshapirosm_etype_os_print __P(( 15190792Sgshapiro SM_EXC_T *exc, 15290792Sgshapiro SM_FILE_T *stream)); 15390792Sgshapiro 15490792Sgshapirostatic void 15590792Sgshapirosm_etype_os_print(exc, stream) 15690792Sgshapiro SM_EXC_T *exc; 15790792Sgshapiro SM_FILE_T *stream; 15890792Sgshapiro{ 15990792Sgshapiro int err = exc->exc_argv[0].v_int; 16090792Sgshapiro char *syscall = exc->exc_argv[1].v_str; 16190792Sgshapiro char *sysargs = exc->exc_argv[2].v_str; 16290792Sgshapiro 16390792Sgshapiro if (sysargs) 16490792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s: %s failed: %s", 16590792Sgshapiro sysargs, syscall, sm_errstring(err)); 16690792Sgshapiro else 16790792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s failed: %s", syscall, 16890792Sgshapiro sm_errstring(err)); 16990792Sgshapiro} 17090792Sgshapiro 17190792Sgshapiro/* 17290792Sgshapiro** SmEtypeOs represents the failure of a Unix system call. 17390792Sgshapiro** The three arguments are: 17490792Sgshapiro** int errno (eg, ENOENT) 17590792Sgshapiro** char *syscall (eg, "open") 17690792Sgshapiro** char *sysargs (eg, NULL or "/etc/mail/sendmail.cf") 17790792Sgshapiro*/ 17890792Sgshapiro 17990792Sgshapiroconst SM_EXC_TYPE_T SmEtypeOs = 18090792Sgshapiro{ 18190792Sgshapiro SmExcTypeMagic, 18290792Sgshapiro "E:sm.os", 18390792Sgshapiro "isr", 18490792Sgshapiro sm_etype_os_print, 18590792Sgshapiro NULL, 18690792Sgshapiro}; 18790792Sgshapiro 18890792Sgshapiro/* 18990792Sgshapiro** SmEtypeErr is a completely generic error which should only be 19090792Sgshapiro** used in applications and test programs. Libraries should use 19190792Sgshapiro** more specific exception codes. 19290792Sgshapiro*/ 19390792Sgshapiro 19490792Sgshapiroconst SM_EXC_TYPE_T SmEtypeErr = 19590792Sgshapiro{ 19690792Sgshapiro SmExcTypeMagic, 19790792Sgshapiro "E:sm.err", 19890792Sgshapiro "r", 19990792Sgshapiro sm_etype_printf, 20090792Sgshapiro "%0", 20190792Sgshapiro}; 20290792Sgshapiro 20390792Sgshapiro/* 20490792Sgshapiro** SM_EXC_VNEW_X -- Construct a new exception object. 20590792Sgshapiro** 20690792Sgshapiro** Parameters: 20790792Sgshapiro** etype -- type of exception. 20890792Sgshapiro** ap -- varargs. 20990792Sgshapiro** 21090792Sgshapiro** Returns: 21190792Sgshapiro** pointer to exception object. 21290792Sgshapiro*/ 21390792Sgshapiro 21490792Sgshapiro/* 21590792Sgshapiro** This is an auxiliary function called by sm_exc_new_x and sm_exc_raisenew_x. 21690792Sgshapiro** 21790792Sgshapiro** If an exception is raised, then to avoid a storage leak, we must: 21890792Sgshapiro** (a) Free all storage we have allocated. 21990792Sgshapiro** (b) Free all exception arguments in the varargs list. 22090792Sgshapiro** Getting this right is tricky. 22190792Sgshapiro** 22290792Sgshapiro** To see why (b) is required, consider the code fragment 22390792Sgshapiro** SM_EXCEPT(exc, "*") 22490792Sgshapiro** sm_exc_raisenew_x(&MyEtype, exc); 22590792Sgshapiro** SM_END_TRY 22690792Sgshapiro** In the normal case, sm_exc_raisenew_x will allocate and raise a new 22790792Sgshapiro** exception E that owns exc. When E is eventually freed, exc is also freed. 22890792Sgshapiro** In the exceptional case, sm_exc_raisenew_x must free exc before raising 22990792Sgshapiro** an out-of-memory exception so that exc is not leaked. 23090792Sgshapiro*/ 23190792Sgshapiro 232168515Sgshapirostatic SM_EXC_T *sm_exc_vnew_x __P((const SM_EXC_TYPE_T *, va_list SM_NONVOLATILE)); 233168515Sgshapiro 234168515Sgshapirostatic SM_EXC_T * 23590792Sgshapirosm_exc_vnew_x(etype, ap) 23690792Sgshapiro const SM_EXC_TYPE_T *etype; 23790792Sgshapiro va_list SM_NONVOLATILE ap; 23890792Sgshapiro{ 23990792Sgshapiro /* 24090792Sgshapiro ** All variables that are modified in the SM_TRY clause and 24190792Sgshapiro ** referenced in the SM_EXCEPT clause must be declared volatile. 24290792Sgshapiro */ 24390792Sgshapiro 24490792Sgshapiro /* NOTE: Type of si, i, and argc *must* match */ 24590792Sgshapiro SM_EXC_T * volatile exc = NULL; 24690792Sgshapiro int volatile si = 0; 24790792Sgshapiro SM_VAL_T * volatile argv = NULL; 24890792Sgshapiro int i, argc; 24990792Sgshapiro 25090792Sgshapiro SM_REQUIRE_ISA(etype, SmExcTypeMagic); 25190792Sgshapiro argc = strlen(etype->etype_argformat); 25290792Sgshapiro SM_TRY 25390792Sgshapiro { 25490792Sgshapiro /* 25590792Sgshapiro ** Step 1. Allocate the exception structure. 25690792Sgshapiro ** On failure, scan the varargs list and free all 25790792Sgshapiro ** exception arguments. 25890792Sgshapiro */ 25990792Sgshapiro 26090792Sgshapiro exc = sm_malloc_x(sizeof(SM_EXC_T)); 26190792Sgshapiro exc->sm_magic = SmExcMagic; 26290792Sgshapiro exc->exc_refcount = 1; 26390792Sgshapiro exc->exc_type = etype; 26490792Sgshapiro exc->exc_argv = NULL; 26590792Sgshapiro 26690792Sgshapiro /* 26790792Sgshapiro ** Step 2. Allocate the argument vector. 26890792Sgshapiro ** On failure, free exc, scan the varargs list and free all 26990792Sgshapiro ** exception arguments. On success, scan the varargs list, 27090792Sgshapiro ** and copy the arguments into argv. 27190792Sgshapiro */ 27290792Sgshapiro 27390792Sgshapiro argv = sm_malloc_x(argc * sizeof(SM_VAL_T)); 27490792Sgshapiro exc->exc_argv = argv; 27590792Sgshapiro for (i = 0; i < argc; ++i) 27690792Sgshapiro { 27790792Sgshapiro switch (etype->etype_argformat[i]) 27890792Sgshapiro { 27990792Sgshapiro case 'i': 28090792Sgshapiro argv[i].v_int = SM_VA_ARG(ap, int); 28190792Sgshapiro break; 28290792Sgshapiro case 'l': 28390792Sgshapiro argv[i].v_long = SM_VA_ARG(ap, long); 28490792Sgshapiro break; 28590792Sgshapiro case 'e': 28690792Sgshapiro argv[i].v_exc = SM_VA_ARG(ap, SM_EXC_T*); 28790792Sgshapiro break; 28890792Sgshapiro case 's': 28990792Sgshapiro argv[i].v_str = SM_VA_ARG(ap, char*); 29090792Sgshapiro break; 29190792Sgshapiro case 'r': 29290792Sgshapiro SM_REQUIRE(etype->etype_argformat[i+1] == '\0'); 29390792Sgshapiro argv[i].v_str = SM_VA_ARG(ap, char*); 29490792Sgshapiro break; 29590792Sgshapiro default: 29690792Sgshapiro sm_abort("sm_exc_vnew_x: bad argformat '%c'", 29790792Sgshapiro etype->etype_argformat[i]); 29890792Sgshapiro } 29990792Sgshapiro } 30090792Sgshapiro 30190792Sgshapiro /* 30290792Sgshapiro ** Step 3. Scan argv, and allocate space for all 30390792Sgshapiro ** string arguments. si is the number of elements 30490792Sgshapiro ** of argv that have been processed so far. 30590792Sgshapiro ** On failure, free exc, argv, all the exception arguments 30690792Sgshapiro ** and all of the strings that have been copied. 30790792Sgshapiro */ 30890792Sgshapiro 30990792Sgshapiro for (si = 0; si < argc; ++si) 31090792Sgshapiro { 31190792Sgshapiro switch (etype->etype_argformat[si]) 31290792Sgshapiro { 31390792Sgshapiro case 's': 31490792Sgshapiro { 31590792Sgshapiro char *str = argv[si].v_str; 31690792Sgshapiro if (str != NULL) 31790792Sgshapiro argv[si].v_str = sm_strdup_x(str); 31890792Sgshapiro } 31990792Sgshapiro break; 32090792Sgshapiro case 'r': 32190792Sgshapiro { 32290792Sgshapiro char *fmt = argv[si].v_str; 32390792Sgshapiro if (fmt != NULL) 32490792Sgshapiro argv[si].v_str = sm_vstringf_x(fmt, ap); 32590792Sgshapiro } 32690792Sgshapiro break; 32790792Sgshapiro } 32890792Sgshapiro } 32990792Sgshapiro } 33090792Sgshapiro SM_EXCEPT(e, "*") 33190792Sgshapiro { 33290792Sgshapiro if (exc == NULL || argv == NULL) 33390792Sgshapiro { 33490792Sgshapiro /* 33590792Sgshapiro ** Failure in step 1 or step 2. 33690792Sgshapiro ** Scan ap and free all exception arguments. 33790792Sgshapiro */ 33890792Sgshapiro 33990792Sgshapiro for (i = 0; i < argc; ++i) 34090792Sgshapiro { 34190792Sgshapiro switch (etype->etype_argformat[i]) 34290792Sgshapiro { 34390792Sgshapiro case 'i': 34490792Sgshapiro (void) SM_VA_ARG(ap, int); 34590792Sgshapiro break; 34690792Sgshapiro case 'l': 34790792Sgshapiro (void) SM_VA_ARG(ap, long); 34890792Sgshapiro break; 34990792Sgshapiro case 'e': 35090792Sgshapiro sm_exc_free(SM_VA_ARG(ap, SM_EXC_T*)); 35190792Sgshapiro break; 35290792Sgshapiro case 's': 35390792Sgshapiro case 'r': 35490792Sgshapiro (void) SM_VA_ARG(ap, char*); 35590792Sgshapiro break; 35690792Sgshapiro } 35790792Sgshapiro } 35890792Sgshapiro } 35990792Sgshapiro else 36090792Sgshapiro { 36190792Sgshapiro /* 36290792Sgshapiro ** Failure in step 3. Scan argv and free 36390792Sgshapiro ** all exception arguments and all string 36490792Sgshapiro ** arguments that have been duplicated. 36590792Sgshapiro ** Then free argv. 36690792Sgshapiro */ 36790792Sgshapiro 36890792Sgshapiro for (i = 0; i < argc; ++i) 36990792Sgshapiro { 37090792Sgshapiro switch (etype->etype_argformat[i]) 37190792Sgshapiro { 37290792Sgshapiro case 'e': 37390792Sgshapiro sm_exc_free(argv[i].v_exc); 37490792Sgshapiro break; 37590792Sgshapiro case 's': 37690792Sgshapiro case 'r': 37790792Sgshapiro if (i < si) 37890792Sgshapiro sm_free(argv[i].v_str); 37990792Sgshapiro break; 38090792Sgshapiro } 38190792Sgshapiro } 38290792Sgshapiro sm_free(argv); 38390792Sgshapiro } 38490792Sgshapiro sm_free(exc); 38590792Sgshapiro sm_exc_raise_x(e); 38690792Sgshapiro } 38790792Sgshapiro SM_END_TRY 38890792Sgshapiro 38990792Sgshapiro return exc; 39090792Sgshapiro} 39190792Sgshapiro 39290792Sgshapiro/* 39390792Sgshapiro** SM_EXC_NEW_X -- Construct a new exception object. 39490792Sgshapiro** 39590792Sgshapiro** Parameters: 39690792Sgshapiro** etype -- type of exception. 39790792Sgshapiro** ... -- varargs. 39890792Sgshapiro** 39990792Sgshapiro** Returns: 40090792Sgshapiro** pointer to exception object. 40190792Sgshapiro*/ 40290792Sgshapiro 40390792SgshapiroSM_EXC_T * 40490792Sgshapiro#if SM_VA_STD 40590792Sgshapirosm_exc_new_x( 40690792Sgshapiro const SM_EXC_TYPE_T *etype, 40790792Sgshapiro ...) 40890792Sgshapiro#else /* SM_VA_STD */ 40990792Sgshapirosm_exc_new_x(etype, va_alist) 41090792Sgshapiro const SM_EXC_TYPE_T *etype; 41190792Sgshapiro va_dcl 41290792Sgshapiro#endif /* SM_VA_STD */ 41390792Sgshapiro{ 41490792Sgshapiro SM_EXC_T *exc; 41590792Sgshapiro SM_VA_LOCAL_DECL 41690792Sgshapiro 41790792Sgshapiro SM_VA_START(ap, etype); 41890792Sgshapiro exc = sm_exc_vnew_x(etype, ap); 41990792Sgshapiro SM_VA_END(ap); 42090792Sgshapiro return exc; 42190792Sgshapiro} 42290792Sgshapiro 42390792Sgshapiro/* 42490792Sgshapiro** SM_EXC_FREE -- Destroy a reference to an exception object. 42590792Sgshapiro** 42690792Sgshapiro** Parameters: 42790792Sgshapiro** exc -- exception object. 42890792Sgshapiro** 42990792Sgshapiro** Returns: 43090792Sgshapiro** none. 43190792Sgshapiro*/ 43290792Sgshapiro 43390792Sgshapirovoid 43490792Sgshapirosm_exc_free(exc) 43590792Sgshapiro SM_EXC_T *exc; 43690792Sgshapiro{ 43790792Sgshapiro if (exc == NULL) 43890792Sgshapiro return; 43990792Sgshapiro SM_REQUIRE(exc->sm_magic == SmExcMagic); 44090792Sgshapiro if (exc->exc_refcount == 0) 44190792Sgshapiro return; 44290792Sgshapiro if (--exc->exc_refcount == 0) 44390792Sgshapiro { 44490792Sgshapiro int i, c; 44590792Sgshapiro 44690792Sgshapiro for (i = 0; (c = exc->exc_type->etype_argformat[i]) != '\0'; 44790792Sgshapiro ++i) 44890792Sgshapiro { 44990792Sgshapiro switch (c) 45090792Sgshapiro { 45190792Sgshapiro case 's': 45290792Sgshapiro case 'r': 45390792Sgshapiro sm_free(exc->exc_argv[i].v_str); 45490792Sgshapiro break; 45590792Sgshapiro case 'e': 45690792Sgshapiro sm_exc_free(exc->exc_argv[i].v_exc); 45790792Sgshapiro break; 45890792Sgshapiro } 45990792Sgshapiro } 46090792Sgshapiro exc->sm_magic = NULL; 46190792Sgshapiro sm_free(exc->exc_argv); 46290792Sgshapiro sm_free(exc); 46390792Sgshapiro } 46490792Sgshapiro} 46590792Sgshapiro 46690792Sgshapiro/* 46790792Sgshapiro** SM_EXC_MATCH -- Match exception category against a glob pattern. 46890792Sgshapiro** 46990792Sgshapiro** Parameters: 47090792Sgshapiro** exc -- exception. 47190792Sgshapiro** pattern -- glob pattern. 47290792Sgshapiro** 47390792Sgshapiro** Returns: 47490792Sgshapiro** true iff match. 47590792Sgshapiro*/ 47690792Sgshapiro 47790792Sgshapirobool 47890792Sgshapirosm_exc_match(exc, pattern) 47990792Sgshapiro SM_EXC_T *exc; 48090792Sgshapiro const char *pattern; 48190792Sgshapiro{ 48290792Sgshapiro if (exc == NULL) 48390792Sgshapiro return false; 48490792Sgshapiro SM_REQUIRE(exc->sm_magic == SmExcMagic); 48590792Sgshapiro return sm_match(exc->exc_type->etype_category, pattern); 48690792Sgshapiro} 48790792Sgshapiro 48890792Sgshapiro/* 48990792Sgshapiro** SM_EXC_WRITE -- Write exception message to a stream (wo trailing newline). 49090792Sgshapiro** 49190792Sgshapiro** Parameters: 49290792Sgshapiro** exc -- exception. 49390792Sgshapiro** stream -- file for output. 49490792Sgshapiro** 49590792Sgshapiro** Returns: 49690792Sgshapiro** none. 49790792Sgshapiro*/ 49890792Sgshapiro 49990792Sgshapirovoid 50090792Sgshapirosm_exc_write(exc, stream) 50190792Sgshapiro SM_EXC_T *exc; 50290792Sgshapiro SM_FILE_T *stream; 50390792Sgshapiro{ 50490792Sgshapiro SM_REQUIRE_ISA(exc, SmExcMagic); 50590792Sgshapiro exc->exc_type->etype_print(exc, stream); 50690792Sgshapiro} 50790792Sgshapiro 50890792Sgshapiro/* 50990792Sgshapiro** SM_EXC_PRINT -- Print exception message to a stream (with trailing newline). 51090792Sgshapiro** 51190792Sgshapiro** Parameters: 51290792Sgshapiro** exc -- exception. 51390792Sgshapiro** stream -- file for output. 51490792Sgshapiro** 51590792Sgshapiro** Returns: 51690792Sgshapiro** none. 51790792Sgshapiro*/ 51890792Sgshapiro 51990792Sgshapirovoid 52090792Sgshapirosm_exc_print(exc, stream) 52190792Sgshapiro SM_EXC_T *exc; 52290792Sgshapiro SM_FILE_T *stream; 52390792Sgshapiro{ 52490792Sgshapiro SM_REQUIRE_ISA(exc, SmExcMagic); 52590792Sgshapiro exc->exc_type->etype_print(exc, stream); 52690792Sgshapiro (void) sm_io_putc(stream, SM_TIME_DEFAULT, '\n'); 52790792Sgshapiro} 52890792Sgshapiro 52990792SgshapiroSM_EXC_HANDLER_T *SmExcHandler = NULL; 53090792Sgshapirostatic SM_EXC_DEFAULT_HANDLER_T SmExcDefaultHandler = NULL; 53190792Sgshapiro 53290792Sgshapiro/* 53390792Sgshapiro** SM_EXC_NEWTHREAD -- Initialize exception handling for new process/thread. 53490792Sgshapiro** 53590792Sgshapiro** Parameters: 53690792Sgshapiro** h -- default exception handler. 53790792Sgshapiro** 53890792Sgshapiro** Returns: 53990792Sgshapiro** none. 54090792Sgshapiro*/ 54190792Sgshapiro 54290792Sgshapiro/* 54390792Sgshapiro** Initialize a new process or a new thread by clearing the 54490792Sgshapiro** exception handler stack and optionally setting a default 54590792Sgshapiro** exception handler function. Call this at the beginning of main, 54690792Sgshapiro** or in a new process after calling fork, or in a new thread. 54790792Sgshapiro** 54890792Sgshapiro** This function is a luxury, not a necessity. 54990792Sgshapiro** If h != NULL then you can get the same effect by 55090792Sgshapiro** wrapping the body of main, or the body of a forked child 55190792Sgshapiro** or a new thread in SM_TRY ... SM_EXCEPT(e,"*") h(e); SM_END_TRY. 55290792Sgshapiro*/ 55390792Sgshapiro 55490792Sgshapirovoid 55590792Sgshapirosm_exc_newthread(h) 55690792Sgshapiro SM_EXC_DEFAULT_HANDLER_T h; 55790792Sgshapiro{ 55890792Sgshapiro SmExcHandler = NULL; 55990792Sgshapiro SmExcDefaultHandler = h; 56090792Sgshapiro} 56190792Sgshapiro 56290792Sgshapiro/* 56390792Sgshapiro** SM_EXC_RAISE_X -- Raise an exception. 56490792Sgshapiro** 56590792Sgshapiro** Parameters: 56690792Sgshapiro** exc -- exception. 56790792Sgshapiro** 56890792Sgshapiro** Returns: 56990792Sgshapiro** doesn't. 57090792Sgshapiro*/ 57190792Sgshapiro 572125820Sgshapirovoid SM_DEAD_D 57390792Sgshapirosm_exc_raise_x(exc) 57490792Sgshapiro SM_EXC_T *exc; 57590792Sgshapiro{ 57690792Sgshapiro SM_REQUIRE_ISA(exc, SmExcMagic); 57790792Sgshapiro 57890792Sgshapiro if (SmExcHandler == NULL) 57990792Sgshapiro { 58090792Sgshapiro if (SmExcDefaultHandler != NULL) 58190792Sgshapiro { 58290792Sgshapiro SM_EXC_DEFAULT_HANDLER_T h; 58390792Sgshapiro 58490792Sgshapiro /* 58590792Sgshapiro ** If defined, the default handler is expected 58690792Sgshapiro ** to terminate the current thread of execution 58790792Sgshapiro ** using exit() or pthread_exit(). 58890792Sgshapiro ** If it instead returns normally, then we fall 58990792Sgshapiro ** through to the default case below. If it 59090792Sgshapiro ** raises an exception, then sm_exc_raise_x is 59190792Sgshapiro ** re-entered and, because we set SmExcDefaultHandler 59290792Sgshapiro ** to NULL before invoking h, we will again 59390792Sgshapiro ** end up in the default case below. 59490792Sgshapiro */ 59590792Sgshapiro 59690792Sgshapiro h = SmExcDefaultHandler; 59790792Sgshapiro SmExcDefaultHandler = NULL; 59890792Sgshapiro (*h)(exc); 59990792Sgshapiro } 60090792Sgshapiro 60190792Sgshapiro /* 60290792Sgshapiro ** No exception handler, so print the error and exit. 60390792Sgshapiro ** To override this behaviour on a program wide basis, 60490792Sgshapiro ** call sm_exc_newthread or put an exception handler in main(). 60590792Sgshapiro ** 60690792Sgshapiro ** XXX TODO: map the exception category to an exit code 60790792Sgshapiro ** XXX from <sysexits.h>. 60890792Sgshapiro */ 60990792Sgshapiro 61090792Sgshapiro sm_exc_print(exc, smioerr); 61190792Sgshapiro exit(255); 61290792Sgshapiro } 61390792Sgshapiro 61490792Sgshapiro if (SmExcHandler->eh_value == NULL) 61590792Sgshapiro SmExcHandler->eh_value = exc; 61690792Sgshapiro else 61790792Sgshapiro sm_exc_free(exc); 61890792Sgshapiro 61990792Sgshapiro sm_longjmp_nosig(SmExcHandler->eh_context, 1); 62090792Sgshapiro} 62190792Sgshapiro 62290792Sgshapiro/* 62390792Sgshapiro** SM_EXC_RAISENEW_X -- shorthand for sm_exc_raise_x(sm_exc_new_x(...)) 62490792Sgshapiro** 62590792Sgshapiro** Parameters: 62690792Sgshapiro** etype -- type of exception. 62790792Sgshapiro** ap -- varargs. 62890792Sgshapiro** 62990792Sgshapiro** Returns: 63090792Sgshapiro** none. 63190792Sgshapiro*/ 63290792Sgshapiro 633125820Sgshapirovoid SM_DEAD_D 63490792Sgshapiro#if SM_VA_STD 63590792Sgshapirosm_exc_raisenew_x( 63690792Sgshapiro const SM_EXC_TYPE_T *etype, 63790792Sgshapiro ...) 63890792Sgshapiro#else 63990792Sgshapirosm_exc_raisenew_x(etype, va_alist) 64090792Sgshapiro const SM_EXC_TYPE_T *etype; 64190792Sgshapiro va_dcl 64290792Sgshapiro#endif 64390792Sgshapiro{ 64490792Sgshapiro SM_EXC_T *exc; 64590792Sgshapiro SM_VA_LOCAL_DECL 64690792Sgshapiro 64790792Sgshapiro SM_VA_START(ap, etype); 64890792Sgshapiro exc = sm_exc_vnew_x(etype, ap); 64990792Sgshapiro SM_VA_END(ap); 65090792Sgshapiro sm_exc_raise_x(exc); 65190792Sgshapiro} 652