xref: /titanic_51/usr/src/cmd/sendmail/libsm/exc.c (revision 058561cbaa119a6f2659bc27ef343e1b47266bb2)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate  * the sendmail distribution.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  */
107c478bd9Sstevel@tonic-gate 
117c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
127c478bd9Sstevel@tonic-gate 
137c478bd9Sstevel@tonic-gate #include <sm/gen.h>
14*058561cbSjbeck SM_RCSID("@(#)$Id: exc.c,v 1.49 2006/12/19 19:28:09 ca Exp $")
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate /*
177c478bd9Sstevel@tonic-gate **  exception handling
187c478bd9Sstevel@tonic-gate **  For documentation, see exc.html
197c478bd9Sstevel@tonic-gate */
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate #include <ctype.h>
227c478bd9Sstevel@tonic-gate #include <string.h>
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #include <sm/errstring.h>
257c478bd9Sstevel@tonic-gate #include <sm/exc.h>
267c478bd9Sstevel@tonic-gate #include <sm/heap.h>
277c478bd9Sstevel@tonic-gate #include <sm/string.h>
287c478bd9Sstevel@tonic-gate #include <sm/varargs.h>
297c478bd9Sstevel@tonic-gate #include <sm/io.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate const char SmExcMagic[] = "sm_exc";
327c478bd9Sstevel@tonic-gate const char SmExcTypeMagic[] = "sm_exc_type";
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate **  SM_ETYPE_PRINTF -- printf for exception types.
367c478bd9Sstevel@tonic-gate **
377c478bd9Sstevel@tonic-gate **	Parameters:
387c478bd9Sstevel@tonic-gate **		exc -- exception.
397c478bd9Sstevel@tonic-gate **		stream -- file for output.
407c478bd9Sstevel@tonic-gate **
417c478bd9Sstevel@tonic-gate **	Returns:
427c478bd9Sstevel@tonic-gate **		none.
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate **  A simple formatted print function that can be used as the print function
477c478bd9Sstevel@tonic-gate **  by most exception types.  It prints the printcontext string, interpreting
487c478bd9Sstevel@tonic-gate **  occurrences of %0 through %9 as references to the argument vector.
497c478bd9Sstevel@tonic-gate **  If exception argument 3 is an int or long, then %3 will print the
507c478bd9Sstevel@tonic-gate **  argument in decimal, and %o3 or %x3 will print it in octal or hex.
517c478bd9Sstevel@tonic-gate */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate void
547c478bd9Sstevel@tonic-gate sm_etype_printf(exc, stream)
557c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
567c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate 	size_t n = strlen(exc->exc_type->etype_argformat);
597c478bd9Sstevel@tonic-gate 	const char *p, *s;
607c478bd9Sstevel@tonic-gate 	char format;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	for (p = exc->exc_type->etype_printcontext; *p != '\0'; ++p)
637c478bd9Sstevel@tonic-gate 	{
647c478bd9Sstevel@tonic-gate 		if (*p != '%')
657c478bd9Sstevel@tonic-gate 		{
667c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, *p);
677c478bd9Sstevel@tonic-gate 			continue;
687c478bd9Sstevel@tonic-gate 		}
697c478bd9Sstevel@tonic-gate 		++p;
707c478bd9Sstevel@tonic-gate 		if (*p == '\0')
717c478bd9Sstevel@tonic-gate 		{
727c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
737c478bd9Sstevel@tonic-gate 			break;
747c478bd9Sstevel@tonic-gate 		}
757c478bd9Sstevel@tonic-gate 		if (*p == '%')
767c478bd9Sstevel@tonic-gate 		{
777c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
787c478bd9Sstevel@tonic-gate 			continue;
797c478bd9Sstevel@tonic-gate 		}
807c478bd9Sstevel@tonic-gate 		format = '\0';
817c478bd9Sstevel@tonic-gate 		if (isalpha(*p))
827c478bd9Sstevel@tonic-gate 		{
837c478bd9Sstevel@tonic-gate 			format = *p++;
847c478bd9Sstevel@tonic-gate 			if (*p == '\0')
857c478bd9Sstevel@tonic-gate 			{
867c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
877c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(stream, SM_TIME_DEFAULT,
887c478bd9Sstevel@tonic-gate 						  format);
897c478bd9Sstevel@tonic-gate 				break;
907c478bd9Sstevel@tonic-gate 			}
917c478bd9Sstevel@tonic-gate 		}
927c478bd9Sstevel@tonic-gate 		if (isdigit(*p))
937c478bd9Sstevel@tonic-gate 		{
947c478bd9Sstevel@tonic-gate 			size_t i = *p - '0';
957c478bd9Sstevel@tonic-gate 			if (i < n)
967c478bd9Sstevel@tonic-gate 			{
977c478bd9Sstevel@tonic-gate 				switch (exc->exc_type->etype_argformat[i])
987c478bd9Sstevel@tonic-gate 				{
997c478bd9Sstevel@tonic-gate 				  case 's':
1007c478bd9Sstevel@tonic-gate 				  case 'r':
1017c478bd9Sstevel@tonic-gate 					s = exc->exc_argv[i].v_str;
1027c478bd9Sstevel@tonic-gate 					if (s == NULL)
1037c478bd9Sstevel@tonic-gate 						s = "(null)";
1047c478bd9Sstevel@tonic-gate 					sm_io_fputs(stream, SM_TIME_DEFAULT, s);
1057c478bd9Sstevel@tonic-gate 					continue;
1067c478bd9Sstevel@tonic-gate 				  case 'i':
1077c478bd9Sstevel@tonic-gate 					sm_io_fprintf(stream,
1087c478bd9Sstevel@tonic-gate 						SM_TIME_DEFAULT,
1097c478bd9Sstevel@tonic-gate 						format == 'o' ? "%o"
1107c478bd9Sstevel@tonic-gate 						: format == 'x' ? "%x"
1117c478bd9Sstevel@tonic-gate 								: "%d",
1127c478bd9Sstevel@tonic-gate 						exc->exc_argv[i].v_int);
1137c478bd9Sstevel@tonic-gate 					continue;
1147c478bd9Sstevel@tonic-gate 				  case 'l':
1157c478bd9Sstevel@tonic-gate 					sm_io_fprintf(stream,
1167c478bd9Sstevel@tonic-gate 						SM_TIME_DEFAULT,
1177c478bd9Sstevel@tonic-gate 						format == 'o' ? "%lo"
1187c478bd9Sstevel@tonic-gate 						: format == 'x' ? "%lx"
1197c478bd9Sstevel@tonic-gate 								: "%ld",
1207c478bd9Sstevel@tonic-gate 						exc->exc_argv[i].v_long);
1217c478bd9Sstevel@tonic-gate 					continue;
1227c478bd9Sstevel@tonic-gate 				  case 'e':
1237c478bd9Sstevel@tonic-gate 					sm_exc_write(exc->exc_argv[i].v_exc,
1247c478bd9Sstevel@tonic-gate 						stream);
1257c478bd9Sstevel@tonic-gate 					continue;
1267c478bd9Sstevel@tonic-gate 				}
1277c478bd9Sstevel@tonic-gate 			}
1287c478bd9Sstevel@tonic-gate 		}
1297c478bd9Sstevel@tonic-gate 		(void) sm_io_putc(stream, SM_TIME_DEFAULT, '%');
1307c478bd9Sstevel@tonic-gate 		if (format)
1317c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(stream, SM_TIME_DEFAULT, format);
1327c478bd9Sstevel@tonic-gate 		(void) sm_io_putc(stream, SM_TIME_DEFAULT, *p);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate **  Standard exception types.
1387c478bd9Sstevel@tonic-gate */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate **  SM_ETYPE_OS_PRINT -- Print OS related exception.
1427c478bd9Sstevel@tonic-gate **
1437c478bd9Sstevel@tonic-gate **	Parameters:
1447c478bd9Sstevel@tonic-gate **		exc -- exception.
1457c478bd9Sstevel@tonic-gate **		stream -- file for output.
1467c478bd9Sstevel@tonic-gate **
1477c478bd9Sstevel@tonic-gate **	Returns:
1487c478bd9Sstevel@tonic-gate **		none.
1497c478bd9Sstevel@tonic-gate */
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static void
1527c478bd9Sstevel@tonic-gate sm_etype_os_print __P((
1537c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc,
1547c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream));
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static void
1577c478bd9Sstevel@tonic-gate sm_etype_os_print(exc, stream)
1587c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
1597c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	int err = exc->exc_argv[0].v_int;
1627c478bd9Sstevel@tonic-gate 	char *syscall = exc->exc_argv[1].v_str;
1637c478bd9Sstevel@tonic-gate 	char *sysargs = exc->exc_argv[2].v_str;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (sysargs)
1667c478bd9Sstevel@tonic-gate 		sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s: %s failed: %s",
1677c478bd9Sstevel@tonic-gate 			      sysargs, syscall, sm_errstring(err));
1687c478bd9Sstevel@tonic-gate 	else
1697c478bd9Sstevel@tonic-gate 		sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s failed: %s", syscall,
1707c478bd9Sstevel@tonic-gate 			      sm_errstring(err));
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate **  SmEtypeOs represents the failure of a Unix system call.
1757c478bd9Sstevel@tonic-gate **  The three arguments are:
1767c478bd9Sstevel@tonic-gate **   int errno (eg, ENOENT)
1777c478bd9Sstevel@tonic-gate **   char *syscall (eg, "open")
1787c478bd9Sstevel@tonic-gate **   char *sysargs (eg, NULL or "/etc/mail/sendmail.cf")
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate const SM_EXC_TYPE_T SmEtypeOs =
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	SmExcTypeMagic,
1847c478bd9Sstevel@tonic-gate 	"E:sm.os",
1857c478bd9Sstevel@tonic-gate 	"isr",
1867c478bd9Sstevel@tonic-gate 	sm_etype_os_print,
1877c478bd9Sstevel@tonic-gate 	NULL,
1887c478bd9Sstevel@tonic-gate };
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate **  SmEtypeErr is a completely generic error which should only be
1927c478bd9Sstevel@tonic-gate **  used in applications and test programs.  Libraries should use
1937c478bd9Sstevel@tonic-gate **  more specific exception codes.
1947c478bd9Sstevel@tonic-gate */
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate const SM_EXC_TYPE_T SmEtypeErr =
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	SmExcTypeMagic,
1997c478bd9Sstevel@tonic-gate 	"E:sm.err",
2007c478bd9Sstevel@tonic-gate 	"r",
2017c478bd9Sstevel@tonic-gate 	sm_etype_printf,
2027c478bd9Sstevel@tonic-gate 	"%0",
2037c478bd9Sstevel@tonic-gate };
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate **  SM_EXC_VNEW_X -- Construct a new exception object.
2077c478bd9Sstevel@tonic-gate **
2087c478bd9Sstevel@tonic-gate **	Parameters:
2097c478bd9Sstevel@tonic-gate **		etype -- type of exception.
2107c478bd9Sstevel@tonic-gate **		ap -- varargs.
2117c478bd9Sstevel@tonic-gate **
2127c478bd9Sstevel@tonic-gate **	Returns:
2137c478bd9Sstevel@tonic-gate **		pointer to exception object.
2147c478bd9Sstevel@tonic-gate */
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate **  This is an auxiliary function called by sm_exc_new_x and sm_exc_raisenew_x.
2187c478bd9Sstevel@tonic-gate **
2197c478bd9Sstevel@tonic-gate **  If an exception is raised, then to avoid a storage leak, we must:
2207c478bd9Sstevel@tonic-gate **  (a) Free all storage we have allocated.
2217c478bd9Sstevel@tonic-gate **  (b) Free all exception arguments in the varargs list.
2227c478bd9Sstevel@tonic-gate **  Getting this right is tricky.
2237c478bd9Sstevel@tonic-gate **
2247c478bd9Sstevel@tonic-gate **  To see why (b) is required, consider the code fragment
2257c478bd9Sstevel@tonic-gate **     SM_EXCEPT(exc, "*")
2267c478bd9Sstevel@tonic-gate **         sm_exc_raisenew_x(&MyEtype, exc);
2277c478bd9Sstevel@tonic-gate **     SM_END_TRY
2287c478bd9Sstevel@tonic-gate **  In the normal case, sm_exc_raisenew_x will allocate and raise a new
2297c478bd9Sstevel@tonic-gate **  exception E that owns exc.  When E is eventually freed, exc is also freed.
2307c478bd9Sstevel@tonic-gate **  In the exceptional case, sm_exc_raisenew_x must free exc before raising
2317c478bd9Sstevel@tonic-gate **  an out-of-memory exception so that exc is not leaked.
2327c478bd9Sstevel@tonic-gate */
2337c478bd9Sstevel@tonic-gate 
234*058561cbSjbeck static SM_EXC_T *sm_exc_vnew_x __P((const SM_EXC_TYPE_T *, va_list SM_NONVOLATILE));
235*058561cbSjbeck 
236*058561cbSjbeck static SM_EXC_T *
2377c478bd9Sstevel@tonic-gate sm_exc_vnew_x(etype, ap)
2387c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype;
2397c478bd9Sstevel@tonic-gate 	va_list SM_NONVOLATILE ap;
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	/*
2427c478bd9Sstevel@tonic-gate 	**  All variables that are modified in the SM_TRY clause and
2437c478bd9Sstevel@tonic-gate 	**  referenced in the SM_EXCEPT clause must be declared volatile.
2447c478bd9Sstevel@tonic-gate 	*/
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	/* NOTE: Type of si, i, and argc *must* match */
2477c478bd9Sstevel@tonic-gate 	SM_EXC_T * volatile exc = NULL;
2487c478bd9Sstevel@tonic-gate 	int volatile si = 0;
2497c478bd9Sstevel@tonic-gate 	SM_VAL_T * volatile argv = NULL;
2507c478bd9Sstevel@tonic-gate 	int i, argc;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(etype, SmExcTypeMagic);
2537c478bd9Sstevel@tonic-gate 	argc = strlen(etype->etype_argformat);
2547c478bd9Sstevel@tonic-gate 	SM_TRY
2557c478bd9Sstevel@tonic-gate 	{
2567c478bd9Sstevel@tonic-gate 		/*
2577c478bd9Sstevel@tonic-gate 		**  Step 1.  Allocate the exception structure.
2587c478bd9Sstevel@tonic-gate 		**  On failure, scan the varargs list and free all
2597c478bd9Sstevel@tonic-gate 		**  exception arguments.
2607c478bd9Sstevel@tonic-gate 		*/
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		exc = sm_malloc_x(sizeof(SM_EXC_T));
2637c478bd9Sstevel@tonic-gate 		exc->sm_magic = SmExcMagic;
2647c478bd9Sstevel@tonic-gate 		exc->exc_refcount = 1;
2657c478bd9Sstevel@tonic-gate 		exc->exc_type = etype;
2667c478bd9Sstevel@tonic-gate 		exc->exc_argv = NULL;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		/*
2697c478bd9Sstevel@tonic-gate 		**  Step 2.  Allocate the argument vector.
2707c478bd9Sstevel@tonic-gate 		**  On failure, free exc, scan the varargs list and free all
2717c478bd9Sstevel@tonic-gate 		**  exception arguments.  On success, scan the varargs list,
2727c478bd9Sstevel@tonic-gate 		**  and copy the arguments into argv.
2737c478bd9Sstevel@tonic-gate 		*/
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		argv = sm_malloc_x(argc * sizeof(SM_VAL_T));
2767c478bd9Sstevel@tonic-gate 		exc->exc_argv = argv;
2777c478bd9Sstevel@tonic-gate 		for (i = 0; i < argc; ++i)
2787c478bd9Sstevel@tonic-gate 		{
2797c478bd9Sstevel@tonic-gate 			switch (etype->etype_argformat[i])
2807c478bd9Sstevel@tonic-gate 			{
2817c478bd9Sstevel@tonic-gate 			  case 'i':
2827c478bd9Sstevel@tonic-gate 				argv[i].v_int = SM_VA_ARG(ap, int);
2837c478bd9Sstevel@tonic-gate 				break;
2847c478bd9Sstevel@tonic-gate 			  case 'l':
2857c478bd9Sstevel@tonic-gate 				argv[i].v_long = SM_VA_ARG(ap, long);
2867c478bd9Sstevel@tonic-gate 				break;
2877c478bd9Sstevel@tonic-gate 			  case 'e':
2887c478bd9Sstevel@tonic-gate 				argv[i].v_exc = SM_VA_ARG(ap, SM_EXC_T*);
2897c478bd9Sstevel@tonic-gate 				break;
2907c478bd9Sstevel@tonic-gate 			  case 's':
2917c478bd9Sstevel@tonic-gate 				argv[i].v_str = SM_VA_ARG(ap, char*);
2927c478bd9Sstevel@tonic-gate 				break;
2937c478bd9Sstevel@tonic-gate 			  case 'r':
2947c478bd9Sstevel@tonic-gate 				SM_REQUIRE(etype->etype_argformat[i+1] == '\0');
2957c478bd9Sstevel@tonic-gate 				argv[i].v_str = SM_VA_ARG(ap, char*);
2967c478bd9Sstevel@tonic-gate 				break;
2977c478bd9Sstevel@tonic-gate 			  default:
2987c478bd9Sstevel@tonic-gate 				sm_abort("sm_exc_vnew_x: bad argformat '%c'",
2997c478bd9Sstevel@tonic-gate 					etype->etype_argformat[i]);
3007c478bd9Sstevel@tonic-gate 			}
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 		/*
3047c478bd9Sstevel@tonic-gate 		**  Step 3.  Scan argv, and allocate space for all
3057c478bd9Sstevel@tonic-gate 		**  string arguments.  si is the number of elements
3067c478bd9Sstevel@tonic-gate 		**  of argv that have been processed so far.
3077c478bd9Sstevel@tonic-gate 		**  On failure, free exc, argv, all the exception arguments
3087c478bd9Sstevel@tonic-gate 		**  and all of the strings that have been copied.
3097c478bd9Sstevel@tonic-gate 		*/
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		for (si = 0; si < argc; ++si)
3127c478bd9Sstevel@tonic-gate 		{
3137c478bd9Sstevel@tonic-gate 			switch (etype->etype_argformat[si])
3147c478bd9Sstevel@tonic-gate 			{
3157c478bd9Sstevel@tonic-gate 			  case 's':
3167c478bd9Sstevel@tonic-gate 			    {
3177c478bd9Sstevel@tonic-gate 				char *str = argv[si].v_str;
3187c478bd9Sstevel@tonic-gate 				if (str != NULL)
3197c478bd9Sstevel@tonic-gate 				    argv[si].v_str = sm_strdup_x(str);
3207c478bd9Sstevel@tonic-gate 			    }
3217c478bd9Sstevel@tonic-gate 			    break;
3227c478bd9Sstevel@tonic-gate 			  case 'r':
3237c478bd9Sstevel@tonic-gate 			    {
3247c478bd9Sstevel@tonic-gate 				char *fmt = argv[si].v_str;
3257c478bd9Sstevel@tonic-gate 				if (fmt != NULL)
3267c478bd9Sstevel@tonic-gate 				    argv[si].v_str = sm_vstringf_x(fmt, ap);
3277c478bd9Sstevel@tonic-gate 			    }
3287c478bd9Sstevel@tonic-gate 			    break;
3297c478bd9Sstevel@tonic-gate 			}
3307c478bd9Sstevel@tonic-gate 		}
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 	SM_EXCEPT(e, "*")
3337c478bd9Sstevel@tonic-gate 	{
3347c478bd9Sstevel@tonic-gate 		if (exc == NULL || argv == NULL)
3357c478bd9Sstevel@tonic-gate 		{
3367c478bd9Sstevel@tonic-gate 			/*
3377c478bd9Sstevel@tonic-gate 			**  Failure in step 1 or step 2.
3387c478bd9Sstevel@tonic-gate 			**  Scan ap and free all exception arguments.
3397c478bd9Sstevel@tonic-gate 			*/
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 			for (i = 0; i < argc; ++i)
3427c478bd9Sstevel@tonic-gate 			{
3437c478bd9Sstevel@tonic-gate 				switch (etype->etype_argformat[i])
3447c478bd9Sstevel@tonic-gate 				{
3457c478bd9Sstevel@tonic-gate 				  case 'i':
3467c478bd9Sstevel@tonic-gate 					(void) SM_VA_ARG(ap, int);
3477c478bd9Sstevel@tonic-gate 					break;
3487c478bd9Sstevel@tonic-gate 				  case 'l':
3497c478bd9Sstevel@tonic-gate 					(void) SM_VA_ARG(ap, long);
3507c478bd9Sstevel@tonic-gate 					break;
3517c478bd9Sstevel@tonic-gate 				  case 'e':
3527c478bd9Sstevel@tonic-gate 					sm_exc_free(SM_VA_ARG(ap, SM_EXC_T*));
3537c478bd9Sstevel@tonic-gate 					break;
3547c478bd9Sstevel@tonic-gate 				  case 's':
3557c478bd9Sstevel@tonic-gate 				  case 'r':
3567c478bd9Sstevel@tonic-gate 					(void) SM_VA_ARG(ap, char*);
3577c478bd9Sstevel@tonic-gate 					break;
3587c478bd9Sstevel@tonic-gate 				}
3597c478bd9Sstevel@tonic-gate 			}
3607c478bd9Sstevel@tonic-gate 		}
3617c478bd9Sstevel@tonic-gate 		else
3627c478bd9Sstevel@tonic-gate 		{
3637c478bd9Sstevel@tonic-gate 			/*
3647c478bd9Sstevel@tonic-gate 			**  Failure in step 3.  Scan argv and free
3657c478bd9Sstevel@tonic-gate 			**  all exception arguments and all string
3667c478bd9Sstevel@tonic-gate 			**  arguments that have been duplicated.
3677c478bd9Sstevel@tonic-gate 			**  Then free argv.
3687c478bd9Sstevel@tonic-gate 			*/
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 			for (i = 0; i < argc; ++i)
3717c478bd9Sstevel@tonic-gate 			{
3727c478bd9Sstevel@tonic-gate 				switch (etype->etype_argformat[i])
3737c478bd9Sstevel@tonic-gate 				{
3747c478bd9Sstevel@tonic-gate 				  case 'e':
3757c478bd9Sstevel@tonic-gate 					sm_exc_free(argv[i].v_exc);
3767c478bd9Sstevel@tonic-gate 					break;
3777c478bd9Sstevel@tonic-gate 				  case 's':
3787c478bd9Sstevel@tonic-gate 				  case 'r':
3797c478bd9Sstevel@tonic-gate 					if (i < si)
3807c478bd9Sstevel@tonic-gate 						sm_free(argv[i].v_str);
3817c478bd9Sstevel@tonic-gate 					break;
3827c478bd9Sstevel@tonic-gate 				}
3837c478bd9Sstevel@tonic-gate 			}
3847c478bd9Sstevel@tonic-gate 			sm_free(argv);
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 		sm_free(exc);
3877c478bd9Sstevel@tonic-gate 		sm_exc_raise_x(e);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	SM_END_TRY
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	return exc;
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate **  SM_EXC_NEW_X -- Construct a new exception object.
3967c478bd9Sstevel@tonic-gate **
3977c478bd9Sstevel@tonic-gate **	Parameters:
3987c478bd9Sstevel@tonic-gate **		etype -- type of exception.
3997c478bd9Sstevel@tonic-gate **		... -- varargs.
4007c478bd9Sstevel@tonic-gate **
4017c478bd9Sstevel@tonic-gate **	Returns:
4027c478bd9Sstevel@tonic-gate **		pointer to exception object.
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate SM_EXC_T *
4067c478bd9Sstevel@tonic-gate #if SM_VA_STD
4077c478bd9Sstevel@tonic-gate sm_exc_new_x(
4087c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype,
4097c478bd9Sstevel@tonic-gate 	...)
4107c478bd9Sstevel@tonic-gate #else /* SM_VA_STD */
4117c478bd9Sstevel@tonic-gate sm_exc_new_x(etype, va_alist)
4127c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype;
4137c478bd9Sstevel@tonic-gate 	va_dcl
4147c478bd9Sstevel@tonic-gate #endif /* SM_VA_STD */
4157c478bd9Sstevel@tonic-gate {
4167c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
4177c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	SM_VA_START(ap, etype);
4207c478bd9Sstevel@tonic-gate 	exc = sm_exc_vnew_x(etype, ap);
4217c478bd9Sstevel@tonic-gate 	SM_VA_END(ap);
4227c478bd9Sstevel@tonic-gate 	return exc;
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate **  SM_EXC_FREE -- Destroy a reference to an exception object.
4277c478bd9Sstevel@tonic-gate **
4287c478bd9Sstevel@tonic-gate **	Parameters:
4297c478bd9Sstevel@tonic-gate **		exc -- exception object.
4307c478bd9Sstevel@tonic-gate **
4317c478bd9Sstevel@tonic-gate **	Returns:
4327c478bd9Sstevel@tonic-gate **		none.
4337c478bd9Sstevel@tonic-gate */
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate void
4367c478bd9Sstevel@tonic-gate sm_exc_free(exc)
4377c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	if (exc == NULL)
4407c478bd9Sstevel@tonic-gate 		return;
4417c478bd9Sstevel@tonic-gate 	SM_REQUIRE(exc->sm_magic == SmExcMagic);
4427c478bd9Sstevel@tonic-gate 	if (exc->exc_refcount == 0)
4437c478bd9Sstevel@tonic-gate 		return;
4447c478bd9Sstevel@tonic-gate 	if (--exc->exc_refcount == 0)
4457c478bd9Sstevel@tonic-gate 	{
4467c478bd9Sstevel@tonic-gate 		int i, c;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		for (i = 0; (c = exc->exc_type->etype_argformat[i]) != '\0';
4497c478bd9Sstevel@tonic-gate 		     ++i)
4507c478bd9Sstevel@tonic-gate 		{
4517c478bd9Sstevel@tonic-gate 			switch (c)
4527c478bd9Sstevel@tonic-gate 			{
4537c478bd9Sstevel@tonic-gate 			  case 's':
4547c478bd9Sstevel@tonic-gate 			  case 'r':
4557c478bd9Sstevel@tonic-gate 				sm_free(exc->exc_argv[i].v_str);
4567c478bd9Sstevel@tonic-gate 				break;
4577c478bd9Sstevel@tonic-gate 			  case 'e':
4587c478bd9Sstevel@tonic-gate 				sm_exc_free(exc->exc_argv[i].v_exc);
4597c478bd9Sstevel@tonic-gate 				break;
4607c478bd9Sstevel@tonic-gate 			}
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 		exc->sm_magic = NULL;
4637c478bd9Sstevel@tonic-gate 		sm_free(exc->exc_argv);
4647c478bd9Sstevel@tonic-gate 		sm_free(exc);
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate **  SM_EXC_MATCH -- Match exception category against a glob pattern.
4707c478bd9Sstevel@tonic-gate **
4717c478bd9Sstevel@tonic-gate **	Parameters:
4727c478bd9Sstevel@tonic-gate **		exc -- exception.
4737c478bd9Sstevel@tonic-gate **		pattern -- glob pattern.
4747c478bd9Sstevel@tonic-gate **
4757c478bd9Sstevel@tonic-gate **	Returns:
4767c478bd9Sstevel@tonic-gate **		true iff match.
4777c478bd9Sstevel@tonic-gate */
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate bool
4807c478bd9Sstevel@tonic-gate sm_exc_match(exc, pattern)
4817c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
4827c478bd9Sstevel@tonic-gate 	const char *pattern;
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 	if (exc == NULL)
4857c478bd9Sstevel@tonic-gate 		return false;
4867c478bd9Sstevel@tonic-gate 	SM_REQUIRE(exc->sm_magic == SmExcMagic);
4877c478bd9Sstevel@tonic-gate 	return sm_match(exc->exc_type->etype_category, pattern);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate **  SM_EXC_WRITE -- Write exception message to a stream (wo trailing newline).
4927c478bd9Sstevel@tonic-gate **
4937c478bd9Sstevel@tonic-gate **	Parameters:
4947c478bd9Sstevel@tonic-gate **		exc -- exception.
4957c478bd9Sstevel@tonic-gate **		stream -- file for output.
4967c478bd9Sstevel@tonic-gate **
4977c478bd9Sstevel@tonic-gate **	Returns:
4987c478bd9Sstevel@tonic-gate **		none.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate void
5027c478bd9Sstevel@tonic-gate sm_exc_write(exc, stream)
5037c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
5047c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
5077c478bd9Sstevel@tonic-gate 	exc->exc_type->etype_print(exc, stream);
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
5117c478bd9Sstevel@tonic-gate **  SM_EXC_PRINT -- Print exception message to a stream (with trailing newline).
5127c478bd9Sstevel@tonic-gate **
5137c478bd9Sstevel@tonic-gate **	Parameters:
5147c478bd9Sstevel@tonic-gate **		exc -- exception.
5157c478bd9Sstevel@tonic-gate **		stream -- file for output.
5167c478bd9Sstevel@tonic-gate **
5177c478bd9Sstevel@tonic-gate **	Returns:
5187c478bd9Sstevel@tonic-gate **		none.
5197c478bd9Sstevel@tonic-gate */
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate void
5227c478bd9Sstevel@tonic-gate sm_exc_print(exc, stream)
5237c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
5247c478bd9Sstevel@tonic-gate 	SM_FILE_T *stream;
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
5277c478bd9Sstevel@tonic-gate 	exc->exc_type->etype_print(exc, stream);
5287c478bd9Sstevel@tonic-gate 	(void) sm_io_putc(stream, SM_TIME_DEFAULT, '\n');
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate SM_EXC_HANDLER_T *SmExcHandler = NULL;
5327c478bd9Sstevel@tonic-gate static SM_EXC_DEFAULT_HANDLER_T SmExcDefaultHandler = NULL;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate **  SM_EXC_NEWTHREAD -- Initialize exception handling for new process/thread.
5367c478bd9Sstevel@tonic-gate **
5377c478bd9Sstevel@tonic-gate **	Parameters:
5387c478bd9Sstevel@tonic-gate **		h -- default exception handler.
5397c478bd9Sstevel@tonic-gate **
5407c478bd9Sstevel@tonic-gate **	Returns:
5417c478bd9Sstevel@tonic-gate **		none.
5427c478bd9Sstevel@tonic-gate */
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate **  Initialize a new process or a new thread by clearing the
5467c478bd9Sstevel@tonic-gate **  exception handler stack and optionally setting a default
5477c478bd9Sstevel@tonic-gate **  exception handler function.  Call this at the beginning of main,
5487c478bd9Sstevel@tonic-gate **  or in a new process after calling fork, or in a new thread.
5497c478bd9Sstevel@tonic-gate **
5507c478bd9Sstevel@tonic-gate **  This function is a luxury, not a necessity.
5517c478bd9Sstevel@tonic-gate **  If h != NULL then you can get the same effect by
5527c478bd9Sstevel@tonic-gate **  wrapping the body of main, or the body of a forked child
5537c478bd9Sstevel@tonic-gate **  or a new thread in SM_TRY ... SM_EXCEPT(e,"*") h(e); SM_END_TRY.
5547c478bd9Sstevel@tonic-gate */
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate void
5577c478bd9Sstevel@tonic-gate sm_exc_newthread(h)
5587c478bd9Sstevel@tonic-gate 	SM_EXC_DEFAULT_HANDLER_T h;
5597c478bd9Sstevel@tonic-gate {
5607c478bd9Sstevel@tonic-gate 	SmExcHandler = NULL;
5617c478bd9Sstevel@tonic-gate 	SmExcDefaultHandler = h;
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate **  SM_EXC_RAISE_X -- Raise an exception.
5667c478bd9Sstevel@tonic-gate **
5677c478bd9Sstevel@tonic-gate **	Parameters:
5687c478bd9Sstevel@tonic-gate **		exc -- exception.
5697c478bd9Sstevel@tonic-gate **
5707c478bd9Sstevel@tonic-gate **	Returns:
5717c478bd9Sstevel@tonic-gate **		doesn't.
5727c478bd9Sstevel@tonic-gate */
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate void SM_DEAD_D
5757c478bd9Sstevel@tonic-gate sm_exc_raise_x(exc)
5767c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	SM_REQUIRE_ISA(exc, SmExcMagic);
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if (SmExcHandler == NULL)
5817c478bd9Sstevel@tonic-gate 	{
5827c478bd9Sstevel@tonic-gate 		if (SmExcDefaultHandler != NULL)
5837c478bd9Sstevel@tonic-gate 		{
5847c478bd9Sstevel@tonic-gate 			SM_EXC_DEFAULT_HANDLER_T h;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 			/*
5877c478bd9Sstevel@tonic-gate 			**  If defined, the default handler is expected
5887c478bd9Sstevel@tonic-gate 			**  to terminate the current thread of execution
5897c478bd9Sstevel@tonic-gate 			**  using exit() or pthread_exit().
5907c478bd9Sstevel@tonic-gate 			**  If it instead returns normally, then we fall
5917c478bd9Sstevel@tonic-gate 			**  through to the default case below.  If it
5927c478bd9Sstevel@tonic-gate 			**  raises an exception, then sm_exc_raise_x is
5937c478bd9Sstevel@tonic-gate 			**  re-entered and, because we set SmExcDefaultHandler
5947c478bd9Sstevel@tonic-gate 			**  to NULL before invoking h, we will again
5957c478bd9Sstevel@tonic-gate 			**  end up in the default case below.
5967c478bd9Sstevel@tonic-gate 			*/
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 			h = SmExcDefaultHandler;
5997c478bd9Sstevel@tonic-gate 			SmExcDefaultHandler = NULL;
6007c478bd9Sstevel@tonic-gate 			(*h)(exc);
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 		/*
6047c478bd9Sstevel@tonic-gate 		**  No exception handler, so print the error and exit.
6057c478bd9Sstevel@tonic-gate 		**  To override this behaviour on a program wide basis,
6067c478bd9Sstevel@tonic-gate 		**  call sm_exc_newthread or put an exception handler in main().
6077c478bd9Sstevel@tonic-gate 		**
6087c478bd9Sstevel@tonic-gate 		**  XXX TODO: map the exception category to an exit code
6097c478bd9Sstevel@tonic-gate 		**  XXX from <sysexits.h>.
6107c478bd9Sstevel@tonic-gate 		*/
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		sm_exc_print(exc, smioerr);
6137c478bd9Sstevel@tonic-gate 		exit(255);
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (SmExcHandler->eh_value == NULL)
6177c478bd9Sstevel@tonic-gate 		SmExcHandler->eh_value = exc;
6187c478bd9Sstevel@tonic-gate 	else
6197c478bd9Sstevel@tonic-gate 		sm_exc_free(exc);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	sm_longjmp_nosig(SmExcHandler->eh_context, 1);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate **  SM_EXC_RAISENEW_X -- shorthand for sm_exc_raise_x(sm_exc_new_x(...))
6267c478bd9Sstevel@tonic-gate **
6277c478bd9Sstevel@tonic-gate **	Parameters:
6287c478bd9Sstevel@tonic-gate **		etype -- type of exception.
6297c478bd9Sstevel@tonic-gate **		ap -- varargs.
6307c478bd9Sstevel@tonic-gate **
6317c478bd9Sstevel@tonic-gate **	Returns:
6327c478bd9Sstevel@tonic-gate **		none.
6337c478bd9Sstevel@tonic-gate */
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate void SM_DEAD_D
6367c478bd9Sstevel@tonic-gate #if SM_VA_STD
6377c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(
6387c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype,
6397c478bd9Sstevel@tonic-gate 	...)
6407c478bd9Sstevel@tonic-gate #else
6417c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(etype, va_alist)
6427c478bd9Sstevel@tonic-gate 	const SM_EXC_TYPE_T *etype;
6437c478bd9Sstevel@tonic-gate 	va_dcl
6447c478bd9Sstevel@tonic-gate #endif
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	SM_EXC_T *exc;
6477c478bd9Sstevel@tonic-gate 	SM_VA_LOCAL_DECL
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	SM_VA_START(ap, etype);
6507c478bd9Sstevel@tonic-gate 	exc = sm_exc_vnew_x(etype, ap);
6517c478bd9Sstevel@tonic-gate 	SM_VA_END(ap);
6527c478bd9Sstevel@tonic-gate 	sm_exc_raise_x(exc);
6537c478bd9Sstevel@tonic-gate }
654