summaryrefslogtreecommitdiff
path: root/gnu/usr.sbin/sendmail/libsm
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2001-09-11 18:55:53 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2001-09-11 18:55:53 +0000
commit4643c616c81fb1198b29c3eaff4d697392c8dc4b (patch)
tree4afa26a5f1a2ef0e47061eb08b6d339bc7e8dad1 /gnu/usr.sbin/sendmail/libsm
parent8afe339a41c898cc4a2d42d03d115b16f2053bad (diff)
sendmail 8.12.0 with $Id tags converted to $Sendmail
Diffstat (limited to 'gnu/usr.sbin/sendmail/libsm')
-rw-r--r--gnu/usr.sbin/sendmail/libsm/Build13
-rw-r--r--gnu/usr.sbin/sendmail/libsm/Makefile17
-rw-r--r--gnu/usr.sbin/sendmail/libsm/Makefile.m435
-rw-r--r--gnu/usr.sbin/sendmail/libsm/README113
-rw-r--r--gnu/usr.sbin/sendmail/libsm/assert.c187
-rw-r--r--gnu/usr.sbin/sendmail/libsm/assert.html359
-rw-r--r--gnu/usr.sbin/sendmail/libsm/b-strcmp.c148
-rw-r--r--gnu/usr.sbin/sendmail/libsm/b-strl.c202
-rw-r--r--gnu/usr.sbin/sendmail/libsm/cdefs.html107
-rw-r--r--gnu/usr.sbin/sendmail/libsm/cf.c100
-rw-r--r--gnu/usr.sbin/sendmail/libsm/clock.c514
-rw-r--r--gnu/usr.sbin/sendmail/libsm/clrerr.c39
-rw-r--r--gnu/usr.sbin/sendmail/libsm/config.c239
-rw-r--r--gnu/usr.sbin/sendmail/libsm/debug.c366
-rw-r--r--gnu/usr.sbin/sendmail/libsm/debug.html276
-rw-r--r--gnu/usr.sbin/sendmail/libsm/errstring.c191
-rw-r--r--gnu/usr.sbin/sendmail/libsm/exc.c668
-rw-r--r--gnu/usr.sbin/sendmail/libsm/exc.html757
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fclose.c149
-rw-r--r--gnu/usr.sbin/sendmail/libsm/feof.c42
-rw-r--r--gnu/usr.sbin/sendmail/libsm/ferror.c41
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fflush.c151
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fget.c110
-rw-r--r--gnu/usr.sbin/sendmail/libsm/findfp.c428
-rw-r--r--gnu/usr.sbin/sendmail/libsm/flags.c61
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fopen.c371
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fpos.c152
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fprintf.c55
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fpurge.c53
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fput.c52
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fread.c100
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fscanf.c55
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fseek.c335
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fvwrite.c279
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fvwrite.h30
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fwalk.c61
-rw-r--r--gnu/usr.sbin/sendmail/libsm/fwrite.c67
-rw-r--r--gnu/usr.sbin/sendmail/libsm/gen.html43
-rw-r--r--gnu/usr.sbin/sendmail/libsm/get.c46
-rw-r--r--gnu/usr.sbin/sendmail/libsm/glue.h27
-rw-r--r--gnu/usr.sbin/sendmail/libsm/heap.c819
-rw-r--r--gnu/usr.sbin/sendmail/libsm/heap.html424
-rw-r--r--gnu/usr.sbin/sendmail/libsm/index.html174
-rw-r--r--gnu/usr.sbin/sendmail/libsm/io.html745
-rw-r--r--gnu/usr.sbin/sendmail/libsm/ldap.c396
-rw-r--r--gnu/usr.sbin/sendmail/libsm/local.h340
-rw-r--r--gnu/usr.sbin/sendmail/libsm/makebuf.c132
-rw-r--r--gnu/usr.sbin/sendmail/libsm/match.c137
-rw-r--r--gnu/usr.sbin/sendmail/libsm/mbdb.c748
-rw-r--r--gnu/usr.sbin/sendmail/libsm/niprop.c213
-rw-r--r--gnu/usr.sbin/sendmail/libsm/path.c15
-rw-r--r--gnu/usr.sbin/sendmail/libsm/put.c78
-rw-r--r--gnu/usr.sbin/sendmail/libsm/refill.c294
-rw-r--r--gnu/usr.sbin/sendmail/libsm/rewind.c44
-rw-r--r--gnu/usr.sbin/sendmail/libsm/rpool.c477
-rw-r--r--gnu/usr.sbin/sendmail/libsm/rpool.html187
-rw-r--r--gnu/usr.sbin/sendmail/libsm/setvbuf.c190
-rw-r--r--gnu/usr.sbin/sendmail/libsm/shm.c103
-rw-r--r--gnu/usr.sbin/sendmail/libsm/signal.c340
-rw-r--r--gnu/usr.sbin/sendmail/libsm/smstdio.c327
-rw-r--r--gnu/usr.sbin/sendmail/libsm/snprintf.c86
-rw-r--r--gnu/usr.sbin/sendmail/libsm/sscanf.c103
-rw-r--r--gnu/usr.sbin/sendmail/libsm/stdio.c497
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strcasecmp.c106
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strdup.c72
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strerror.c60
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strexit.c127
-rw-r--r--gnu/usr.sbin/sendmail/libsm/string.c56
-rw-r--r--gnu/usr.sbin/sendmail/libsm/stringf.c86
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strio.c466
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strl.c316
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strrevcmp.c101
-rw-r--r--gnu/usr.sbin/sendmail/libsm/strto.c252
-rw-r--r--gnu/usr.sbin/sendmail/libsm/syslogio.c220
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-cf.c46
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-event.c85
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-exc.c145
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-float.c72
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-fopen.c34
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-heap.c64
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-match.c47
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-path.c35
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-rpool.c69
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-scanf.c57
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-shm.c266
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-smstdio.c75
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-string.c46
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-strio.c33
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-strl.c136
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-strrevcmp.c53
-rw-r--r--gnu/usr.sbin/sendmail/libsm/t-types.c103
-rw-r--r--gnu/usr.sbin/sendmail/libsm/test.c160
-rw-r--r--gnu/usr.sbin/sendmail/libsm/ungetc.c179
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vasprintf.c115
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vfprintf.c1107
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vfscanf.c874
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vprintf.c39
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vsnprintf.c78
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vsprintf.c66
-rw-r--r--gnu/usr.sbin/sendmail/libsm/vsscanf.c88
-rw-r--r--gnu/usr.sbin/sendmail/libsm/wbuf.c88
-rw-r--r--gnu/usr.sbin/sendmail/libsm/wsetup.c82
-rw-r--r--gnu/usr.sbin/sendmail/libsm/xtrap.c21
103 files changed, 20033 insertions, 0 deletions
diff --git a/gnu/usr.sbin/sendmail/libsm/Build b/gnu/usr.sbin/sendmail/libsm/Build
new file mode 100644
index 00000000000..79cd9be1bbb
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/Build
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Copyright (c) 1999-2001 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.
+#
+#
+# $Sendmail: Build,v 1.4 2001/02/14 04:39:46 gshapiro Exp $
+
+exec sh ../devtools/bin/Build $*
diff --git a/gnu/usr.sbin/sendmail/libsm/Makefile b/gnu/usr.sbin/sendmail/libsm/Makefile
new file mode 100644
index 00000000000..e2685542067
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/Makefile
@@ -0,0 +1,17 @@
+# $Sendmail: Makefile,v 1.1 2000/03/27 19:26:48 dmoen Exp $
+
+SHELL= /bin/sh
+BUILD= ./Build
+OPTIONS= $(CONFIG) $(FLAGS)
+
+all: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+clean: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+install: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
+
+fresh: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) -c
+
+FRC:
diff --git a/gnu/usr.sbin/sendmail/libsm/Makefile.m4 b/gnu/usr.sbin/sendmail/libsm/Makefile.m4
new file mode 100644
index 00000000000..f0f89cbf92b
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/Makefile.m4
@@ -0,0 +1,35 @@
+define(`confREQUIRE_LIBUNIX')
+include(confBUILDTOOLSDIR`/M4/switch.m4')
+
+define(`confREQUIRE_LIBSM', `true')
+PREPENDDEF(`confENVDEF', `confMAPDEF')
+bldPRODUCT_START(`library', `libsm')
+define(`bldSOURCES', ` assert.c debug.c errstring.c exc.c heap.c match.c rpool.c strdup.c strerror.c strl.c clrerr.c fclose.c feof.c ferror.c fflush.c fget.c fpos.c findfp.c flags.c fopen.c fprintf.c fpurge.c fput.c fread.c fscanf.c fseek.c fvwrite.c fwalk.c fwrite.c get.c makebuf.c put.c refill.c rewind.c setvbuf.c smstdio.c snprintf.c sscanf.c stdio.c strio.c ungetc.c vasprintf.c vfprintf.c vfscanf.c vprintf.c vsnprintf.c vsprintf.c vsscanf.c wbuf.c wsetup.c string.c stringf.c xtrap.c strto.c test.c path.c strcasecmp.c strrevcmp.c signal.c clock.c config.c shm.c mbdb.c strexit.c cf.c ldap.c niprop.c ')
+bldPRODUCT_END
+dnl sem.c msg.c
+dnl syslogio.c
+
+include(confBUILDTOOLSDIR`/M4/'bldM4_TYPE_DIR`/sm-test.m4')
+smtest(`t-event', `run')
+smtest(`t-exc', `run')
+smtest(`t-rpool', `run')
+smtest(`t-string', `run')
+smtest(`t-smstdio', `run')
+smtest(`t-match', `run')
+smtest(`t-strio', `run')
+smtest(`t-heap', `run')
+smtest(`t-fopen', `run')
+smtest(`t-strl', `run')
+smtest(`t-strrevcmp', `run')
+smtest(`t-types', `run')
+smtest(`t-path', `run')
+smtest(`t-float', `run')
+smtest(`t-scanf', `run')
+smtest(`t-shm', `run')
+dnl smtest(`t-sem', `run')
+dnl smtest(`t-msg', `run')
+smtest(`t-cf')
+smtest(`b-strcmp')
+smtest(`b-strl')
+
+bldFINISH
diff --git a/gnu/usr.sbin/sendmail/libsm/README b/gnu/usr.sbin/sendmail/libsm/README
new file mode 100644
index 00000000000..70ba2af9a92
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/README
@@ -0,0 +1,113 @@
+# Copyright (c) 2000-2001 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.
+#
+# $Sendmail: README,v 1.13 2001/08/14 18:07:18 ca Exp $
+#
+
+Libsm is a library of generally useful C abstractions.
+For documentation, see index.html.
+
+Libsm stands alone; it depends on no other sendmail libraries,
+and the only sendmail header files it depends on are its own,
+which reside in ../include/sm.
+
+The t-*.c files are regression tests.
+These tests are incomplete: we do not yet test all of the APIs,
+and we have not yet converted all tests to use the test harness.
+
+The b-*.c files are benchmarks that compare system routines with
+those provided by libsm. By default sendmail uses the routines
+provided by the OS. In several cases, the routines provided by
+libsm are faster than those of the OS. If your OS provides the
+routines, you can compare the performance of them with the libsm
+versions by running the programs with the option -d (by default
+the programs just issue an explanation when/how to use them).
+The programs are:
+
+b-strl.c tests strlcpy() and strlcat().
+b-strcmp.c tests strcasecmp().
+
++----------------------+
+| CONFIGURATION MACROS |
++----------------------+
+
+Libsm uses a set of C preprocessor macros to specify platform specific
+features of the C compiler and standard C libraries.
+
+If you are porting sendmail to a new platform, you may need to tweak
+the values of some of these macros.
+
+The following macros are given default values in <sm/config.h>.
+If the default value is wrong for a given platform, then a platform
+specific value is specified in one of two ways:
+
+ - A -D option is added to the confENVDEF macro; this change can be made
+ to the platform M4 file in devtools/OS, or to the site.config.m4
+ file in devtools/Site.
+
+ - The confSM_OS_HEADER macro in the platform M4 file defines sm_os_foo,
+ which forces "sm/os/sm_os_foo.h" to be included by "sm/config.h" via a
+ link that is made from "sm_os.h" to "sm/os/sm_os_foo.h". Platform
+ specific configuration macro settings are added to <sm/os/sm_os_foo.h>.
+
+SM_CONF_STDBOOL_H
+ Set to 1 if the header file <stdbool.h> exists,
+ and defines true, false and bool.
+
+SM_CONF_SYS_CDEFS_H
+ Set to 1 if the header file <sys/cdefs.h> exists,
+ and defines __P. You may need to do this to eliminate
+ warnings about __P being multiply defined.
+
+SM_CONF_STDDEF_H
+ Set to 0 if the header file <stddef.h> does not exist.
+
+SM_CONF_STRL
+ Set to 1 if strlcpy/strlcat are available.
+ Then compile and run the benchmark program b-strl.
+ If the benchmark shows that the libsm-provided sm_strlcpy/sm_strlcat
+ are faster, then set SM_CONF_STRL back to 0 (the default).
+
+SM_CONF_SETITIMER
+ Set to 0 if the setitimer function is not available.
+
+SM_CONF_SYSEXITS_H
+ Set to 1 if <sysexits.h> exists, and sets the EX_* macros
+ to values different from the default BSD values in <sm/sysexits.h>.
+
+SM_CONF_UID_GID
+ Set to 0 if <sys/types.h> does not define uid_t and gid_t.
+
+SM_CONF_SSIZE_T
+ Set to 0 if <sys/types.h> does not define ssize_t.
+
+SM_CONF_BROKEN_SIZE_T
+ Set to 1 if size_t is not unsigned.
+
+SM_CONF_LONGLONG
+ Set to 1 if your C compiler supports the 'long long' type.
+ This will be set automatically if you use gcc or a C compiler
+ that conforms to the 1999 ISO C standard.
+
+SM_CONF_QUAD_T
+ Set to 1 if your C compiler does not support 'long long',
+ but <sys/types.h> defines quad_t as an integral type.
+
+SM_CONF_SHM
+ Set to 1 if System V shared memory APIs are available.
+
+SM_CONF_MSG
+ Set to 1 if System V message queues are available.
+
+SM_CONF_SEM
+ Set to 1 if semaphores are available.
+
+SM_CONF_BROKEN_STRTOD
+ Set to 1 if your strtod() does not work properly.
+
+SM_CONF_GETOPT
+ Set to 1 if your operating system does not include getopt(3).
diff --git a/gnu/usr.sbin/sendmail/libsm/assert.c b/gnu/usr.sbin/sendmail/libsm/assert.c
new file mode 100644
index 00000000000..8ffe85789ec
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/assert.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: assert.c,v 1.23 2001/09/04 22:41:27 ca Exp $")
+
+/*
+** Abnormal program termination and assertion checking.
+** For documentation, see assert.html.
+*/
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sm/assert.h>
+#include <sm/exc.h>
+#include <sm/io.h>
+#include <sm/varargs.h>
+
+/*
+** Debug categories that are used to guard expensive assertion checks.
+*/
+
+SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert",
+ "@(#)$Debug: sm_check_assert - check assertions $");
+
+SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require",
+ "@(#)$Debug: sm_check_require - check function preconditions $");
+
+SM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure",
+ "@(#)$Debug: sm_check_ensure - check function postconditions $");
+
+/*
+** Debug category: send self SIGSTOP on fatal error,
+** so that you can run a debugger on the stopped process.
+*/
+
+SM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop",
+ "@(#)$Debug: sm_abort_stop - stop process on fatal error $");
+
+/*
+** SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program
+** termination.
+**
+** The goal is to display an error message without disturbing the
+** process state too much, then dump core.
+**
+** Parameters:
+** filename -- filename (can be NULL).
+** lineno -- line number.
+** msg -- message.
+**
+** Returns:
+** doesn't return.
+*/
+
+static void
+sm_abort_defaulthandler __P((
+ const char *filename,
+ int lineno,
+ const char *msg));
+
+static void
+sm_abort_defaulthandler(filename, lineno, msg)
+ const char *filename;
+ int lineno;
+ const char *msg;
+{
+ if (filename != NULL)
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename,
+ lineno, msg);
+ else
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg);
+ sm_io_flush(smioerr, SM_TIME_DEFAULT);
+#ifdef SIGSTOP
+ if (sm_debug_active(&SmAbortStop, 1))
+ kill(getpid(), SIGSTOP);
+#endif /* SIGSTOP */
+ abort();
+}
+
+/*
+** This is the action to be taken to cause abnormal program termination.
+*/
+
+static SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler;
+
+/*
+** SM_ABORT_SETHANDLER -- Set handler for SM_ABORT()
+**
+** This allows you to set a handler function for causing abnormal
+** program termination; it is called when a logic bug is detected.
+**
+** Parameters:
+** f -- handler.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_abort_sethandler(f)
+ SM_ABORT_HANDLER_T f;
+{
+ if (f == NULL)
+ SmAbortHandler = sm_abort_defaulthandler;
+ else
+ SmAbortHandler = f;
+}
+
+/*
+** SM_ABORT -- Call it when you have detected a logic bug.
+**
+** Parameters:
+** fmt -- format string.
+** ... -- arguments.
+**
+** Returns:
+** doesn't.
+*/
+
+void
+#if SM_VA_STD
+sm_abort(char *fmt, ...)
+#else /* SM_VA_STD */
+sm_abort(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ char msg[128];
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, fmt);
+ sm_vsnprintf(msg, sizeof msg, fmt, ap);
+ SM_VA_END(ap);
+ sm_abort_at(NULL, 0, msg);
+}
+
+/*
+** SM_ABORT_AT -- Initiate abnormal program termination.
+**
+** This is the low level function that is called to initiate abnormal
+** program termination. It prints an error message and terminates the
+** program. It is called by sm_abort and by the assertion macros.
+** If filename != NULL then filename and lineno specify the line of source
+** code at which the bug was detected.
+**
+** Parameters:
+** filename -- filename (can be NULL).
+** lineno -- line number.
+** msg -- message.
+**
+** Returns:
+** doesn't.
+*/
+
+void
+sm_abort_at(filename, lineno, msg)
+ const char *filename;
+ int lineno;
+ const char *msg;
+{
+ SM_TRY
+ (*SmAbortHandler)(filename, lineno, msg);
+ SM_EXCEPT(exc, "*")
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "exception raised by abort handler:\n");
+ sm_exc_print(exc, smioerr);
+ sm_io_flush(smioerr, SM_TIME_DEFAULT);
+ SM_END_TRY
+
+ /*
+ ** SmAbortHandler isn't supposed to return.
+ ** Since it has, let's make sure that the program is terminated.
+ */
+
+ abort();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/assert.html b/gnu/usr.sbin/sendmail/libsm/assert.html
new file mode 100644
index 00000000000..f88e2e1a38f
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/assert.html
@@ -0,0 +1,359 @@
+<html>
+<head>
+ <title> libsm : Assert and Abort </title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Assert and Abort </h1>
+ <br> $Sendmail: assert.html,v 1.6 2001/08/27 21:47:03 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+This package contains abstractions
+for assertion checking and abnormal program termination.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/assert.h&gt;
+
+/*
+** abnormal program termination
+*/
+
+void sm_abort_at(char *filename, int lineno, char *msg);
+typedef void (*SM_ABORT_HANDLER)(char *filename, int lineno, char *msg);
+void sm_abort_sethandler(SM_ABORT_HANDLER);
+void sm_abort(char *fmt, ...)
+
+/*
+** assertion checking
+*/
+
+SM_REQUIRE(expression)
+SM_ASSERT(expression)
+SM_ENSURE(expression)
+
+extern SM_DEBUG_T SmExpensiveRequire;
+extern SM_DEBUG_T SmExpensiveAssert;
+extern SM_DEBUG_T SmExpensiveEnsure;
+
+#if SM_CHECK_REQUIRE
+#if SM_CHECK_ASSERT
+#if SM_CHECK_ENSURE
+
+cc -DSM_CHECK_ALL=0 -DSM_CHECK_REQUIRE=1 ...
+</pre>
+
+<h2> Abnormal Program Termination </h2>
+
+The functions sm_abort and sm_abort_at are used to report a logic
+bug and terminate the program. They can be invoked directly,
+and they are also used by the assertion checking macros.
+
+<dl>
+<dt>
+ void sm_abort_at(char *filename, int lineno, char *msg)
+<dd>
+ This is the low level interface for causing abnormal program
+ termination. It is intended to be invoked from a
+ macro, such as the assertion checking macros.
+
+ If filename != NULL then filename and lineno specify the line
+ of source code on which the logic bug is detected. These
+ arguments are normally either set to __FILE__ and __LINE__
+ from an assertion checking macro, or they are set to NULL and 0.
+
+ The default action is to print an error message to smioerr
+ using the arguments, and then call abort(). This default
+ behaviour can be changed by calling sm_abort_sethandler.
+<p>
+<dt>
+ void sm_abort_sethandler(SM_ABORT_HANDLER handler)
+<dd>
+ Install 'handler' as the callback function that is invoked
+ by sm_abort_at. This callback function is passed the same
+ arguments as sm_abort_at, and is expected to log an error
+ message and terminate the program. The callback function should
+ not raise an exception or perform cleanup: see Rationale.
+
+ sm_abort_sethandler is intended to be called once, from main(),
+ before any additional threads are created: see Rationale.
+ You should not use sm_abort_sethandler to
+ switch back and forth between several handlers;
+ this is particularly dangerous when there are
+ multiple threads, or when you are in a library routine.
+<p>
+<dt>
+ void sm_abort(char *fmt, ...)
+<dd>
+ This is the high level interface for causing abnormal program
+ termination. It takes printf arguments. There is no need to
+ include a trailing newline in the format string; a trailing newline
+ will be printed if appropriate by the handler function.
+</dl>
+
+<h2> Assertions </h2>
+
+ The assertion handling package
+ supports a style of programming in which assertions are used
+ liberally throughout the code, both as a form of documentation,
+ and as a way of detecting bugs in the code by performing runtime checks.
+<p>
+ There are three kinds of assertion:
+<dl>
+<dt>
+ SM_REQUIRE(expr)
+<dd>
+ This is an assertion used at the beginning of a function
+ to check that the preconditions for calling the function
+ have been satisfied by the caller.
+<p>
+<dt>
+ SM_ENSURE(expr)
+<dd>
+ This is an assertion used just before returning from a function
+ to check that the function has satisfied all of the postconditions
+ that it is required to satisfy by its contract with the caller.
+<p>
+<dt>
+ SM_ASSERT(expr)
+<dd>
+ This is an assertion that is used in the middle of a function,
+ to check loop invariants, and for any other kind of check that is
+ not a "require" or "ensure" check.
+</dl>
+ If any of the above assertion macros fail, then sm_abort_at
+ is called. By default, a message is printed to stderr and the
+ program is aborted. For example, if SM_REQUIRE(arg &gt; 0) fails
+ because arg &lt;= 0, then the message
+<blockquote><pre>
+foo.c:47: SM_REQUIRE(arg &gt; 0) failed
+</pre></blockquote>
+ is printed to stderr, and abort() is called.
+ You can change this default behaviour using sm_abort_sethandler.
+
+<h2> How To Disable Assertion Checking At Compile Time </h2>
+
+ You can use compile time macros to selectively enable or disable
+ each of the three kinds of assertions, for performance reasons.
+ For example, you might want to enable SM_REQUIRE checking
+ (because it finds the most bugs), but disable the other two types.
+<p>
+ By default, all three types of assertion are enabled.
+ You can selectively disable individual assertion types
+ by setting one or more of the following cpp macros to 0
+ before &lt;sm/assert.h&gt; is included for the first time:
+<blockquote>
+ SM_CHECK_REQUIRE<br>
+ SM_CHECK_ENSURE<br>
+ SM_CHECK_ASSERT<br>
+</blockquote>
+ Or, you can define SM_CHECK_ALL as 0 to disable all assertion
+ types, then selectively define one or more of SM_CHECK_REQUIRE,
+ SM_CHECK_ENSURE or SM_CHECK_ASSERT as 1. For example,
+ to disable all assertions except for SM_REQUIRE, you can use
+ these C compiler flags:
+<blockquote>
+ -DSM_CHECK_ALL=0 -DSM_CHECK_REQUIRE=1
+</blockquote>
+
+ After &lt;sm/assert.h&gt; is included, the macros
+ SM_CHECK_REQUIRE, SM_CHECK_ENSURE and SM_CHECK_ASSERT
+ are each set to either 0 or 1.
+
+<h2> How To Write Complex or Expensive Assertions </h2>
+
+ Sometimes an assertion check requires more code than a simple
+ boolean expression.
+ For example, it might require an entire statement block
+ with its own local variables.
+ You can code such assertion checks by making them conditional on
+ SM_CHECK_REQUIRE, SM_CHECK_ENSURE or SM_CHECK_ASSERT,
+ and using sm_abort to signal failure.
+<p>
+ Sometimes an assertion check is significantly more expensive
+ than one or two comparisons.
+ In such cases, it is not uncommon for developers to comment out
+ the assertion once the code is unit tested.
+ Please don't do this: it makes it hard to turn the assertion
+ check back on for the purposes of regression testing.
+ What you should do instead is make the assertion check conditional
+ on one of these predefined debug objects:
+<blockquote>
+ SmExpensiveRequire<br>
+ SmExpensiveAssert<br>
+ SmExpensiveEnsure
+</blockquote>
+ By doing this, you bring the cost of the assertion checking code
+ back down to a single comparison, unless expensive assertion checking
+ has been explicitly enabled.
+ By the way, the corresponding debug category names are
+<blockquote>
+ sm_check_require<br>
+ sm_check_assert<br>
+ sm_check_ensure
+</blockquote>
+ What activation level should you check for?
+ Higher levels correspond to more expensive assertion checks.
+ Here are some basic guidelines:
+<blockquote>
+ level 1: &lt; 10 basic C operations<br>
+ level 2: &lt; 100 basic C operations<br>
+ level 3: &lt; 1000 basic C operations<br>
+ ...
+</blockquote>
+
+<p>
+ Here's a contrived example of both techniques:
+<blockquote><pre>
+void
+w_munge(WIDGET *w)
+{
+ SM_REQUIRE(w != NULL);
+#if SM_CHECK_REQUIRE
+ /*
+ ** We run this check at level 3 because we expect to check a few hundred
+ ** table entries.
+ */
+
+ if (sm_debug_active(&SmExpensiveRequire, 3))
+ {
+ int i;
+
+ for (i = 0; i &lt; WIDGET_MAX; ++i)
+ {
+ if (w[i] == NULL)
+ sm_abort("w_munge: NULL entry %d in widget table", i);
+ }
+ }
+#endif /* SM_CHECK_REQUIRE */
+</pre></blockquote>
+
+<h2> Other Guidelines </h2>
+
+ You should resist the urge to write SM_ASSERT(0) when the code has
+ reached an impossible place. It's better to call sm_abort, because
+ then you can generate a better error message. For example,
+<blockquote><pre>
+switch (foo)
+{
+ ...
+ default:
+ sm_abort("impossible value %d for foo", foo);
+}
+</pre></blockquote>
+ Note that I did not bother to guard the default clause of the switch
+ statement with #if SM_CHECK_ASSERT ... #endif, because there is
+ probably no performance gain to be had by disabling this particular check.
+<p>
+ Avoid including code that has side effects inside of assert macros,
+ or inside of SM_CHECK_* guards. You don't want the program to stop
+ working if assertion checking is disabled.
+
+<h2> Rationale for Logic Bug Handling </h2>
+
+ When a logic bug is detected, our philosophy is to log an error message
+ and terminate the program, dumping core if possible.
+ It is not a good idea to raise an exception, attempt cleanup,
+ or continue program execution. Here's why.
+<p>
+ First of all, to facilitate post-mortem analysis, we want to dump core
+ on detecting a logic bug, disturbing the process image as little as
+ possible before dumping core. We don't want to raise an exception
+ and unwind the stack, executing cleanup code, before dumping core,
+ because that would obliterate information we need to analyze the cause
+ of the abort.
+<p>
+ Second, it is a bad idea to raise an exception on an assertion failure
+ because this places unacceptable restrictions on code that uses
+ the assertion macros.
+ The reason is this: the sendmail code must be written so that
+ anywhere it is possible for an assertion to be raised, the code
+ will catch the exception and clean up if necessary, restoring
+ data structure invariants and freeing resources as required.
+ If an assertion failure was signalled by raising an exception,
+ then every time you added an assertion, you would need to check
+ both the function containing the assertion and its callers to see
+ if any exception handling code needed to be added to clean up properly
+ on assertion failure. That is far too great a burden.
+<p>
+ It is a bad idea to attempt cleanup upon detecting a logic bug
+ for several reasons:
+<ul>
+<li>If you need to perform cleanup actions in order to preserve the
+ integrity of the data that the program is handling, then the
+ program is not fault tolerant, and needs to be redesigned.
+ There are several reasons why a program might be terminated unexpectedly:
+ the system might crash, the program might receive a signal 9,
+ the program might be terminated by a memory fault (possibly as a
+ side effect of earlier data structure corruption), and the program
+ might detect a logic bug and terminate itself. Note that executing
+ cleanup actions is not feasible in most of the above cases.
+ If the program has a fault tolerant design, then it will not lose
+ data even if the system crashes in the middle of an operation.
+<p>
+<li>If the cause of the logic bug is earlier data structure corruption,
+ then cleanup actions intended to preserve the integrity of the data
+ that the program is handling might cause more harm than good: they
+ might cause information to be corrupted or lost.
+<p>
+<li>If the program uses threads, then cleanup is much more problematic.
+ Suppose that thread A is holding some locks, and is in the middle of
+ modifying a shared data structure. The locks are needed because the
+ data structure is currently in an inconsistent state. At this point,
+ a logic bug is detected deep in a library routine called by A.
+ How do we get all of the running threads to stop what they are doing
+ and perform their thread-specific cleanup actions before terminating?
+ We may not be able to get B to clean up and terminate cleanly until
+ A has restored the invariants on the data structure it is modifying
+ and releases its locks. So, we raise an exception and unwind the stack,
+ restoring data structure invariants and releasing locks at each level
+ of abstraction, and performing an orderly shutdown. There are certainly
+ many classes of error conditions for which using the exception mechanism
+ to perform an orderly shutdown is appropriate and feasible, but there
+ are also classes of error conditions for which exception handling and
+ orderly shutdown is dangerous or impossible. The abnormal program
+ termination system is intended for this second class of error conditions.
+ If you want to trigger orderly shutdown, don't call sm_abort:
+ raise an exception instead.
+</ul>
+<p>
+ Here is a strategy for making sendmail fault tolerant.
+ Sendmail is structured as a collection of processes. The "root" process
+ does as little as possible, except spawn children to do all of the real
+ work, monitor the children, and act as traffic cop.
+ We use exceptions to signal expected but infrequent error conditions,
+ so that the process encountering the exceptional condition can clean up
+ and keep going. (Worker processes are intended to be long lived, in
+ order to minimize forking and increase performance.) But when a bug
+ is detected in a sendmail worker process, the worker process does minimal
+ or no cleanup and then dies. A bug might be detected in several ways:
+ the process might dereference a NULL pointer, receive a signal 11,
+ core dump and die, or an assertion might fail, in which case the process
+ commits suicide. Either way, the root process detects the death of the
+ worker, logs the event, and spawns another worker.
+
+<h2> Rationale for Naming Conventions </h2>
+
+ The names "require" and "ensure" come from the writings of Bertrand Meyer,
+ a prominent evangelist for assertion checking who has written a number of
+ papers about the "Design By Contract" programming methodology,
+ and who created the Eiffel programming language.
+ Many other assertion checking packages for C also have "require" and
+ "ensure" assertion types. In short, we are conforming to a de-facto
+ standard.
+<p>
+ We use the names <tt>SM_REQUIRE</tt>, <tt>SM_ASSERT</tt>
+ and <tt>SM_ENSURE</tt> in preference to to <tt>REQUIRE</tt>,
+ <tt>ASSERT</tt> and <tt>ENSURE</tt> because at least two other
+ open source libraries (libisc and libnana) define <tt>REQUIRE</tt>
+ and <tt>ENSURE</tt> macros, and many libraries define <tt>ASSERT</tt>.
+ We want to avoid name conflicts with other libraries.
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/b-strcmp.c b/gnu/usr.sbin/sendmail/libsm/b-strcmp.c
new file mode 100644
index 00000000000..192c884073c
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/b-strcmp.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: b-strcmp.c,v 1.10 2001/08/31 17:49:28 gshapiro Exp $")
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sm/string.h>
+
+#define toseconds(x, y) (x.tv_sec - y.tv_sec)
+#define SIZE 512
+#define LOOPS 4000000L /* initial number of loops */
+#define MAXTIME 30L /* "maximum" time to run single test */
+
+void
+fatal(str)
+ char *str;
+{
+ perror(str);
+ exit(1);
+}
+
+void
+purpose()
+{
+ printf("This program benchmarks the performance differences between\n");
+ printf("strcasecmp() and sm_strcasecmp().\n");
+ printf("These tests may take several minutes to complete.\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ long a;
+ int k;
+ bool doit = false;
+ long loops;
+ long j;
+ long one, two;
+ struct timeval t1, t2;
+ char src1[SIZE], src2[SIZE];
+
+# define OPTIONS "d"
+ while ((k = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch ((char) k)
+ {
+ case 'd':
+ doit = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!doit)
+ {
+ purpose();
+ printf("If you want to run it, specify -d as option.\n");
+ return 0;
+ }
+
+ /* Run-time comments to the user */
+ purpose();
+ printf("\n");
+ for (k = 0; k < 3; k++)
+ {
+ switch (k)
+ {
+ case 0:
+ (void) sm_strlcpy(src1, "1234567890", SIZE);
+ (void) sm_strlcpy(src2, "1234567890", SIZE);
+ break;
+ case 1:
+ (void) sm_strlcpy(src1, "1234567890", SIZE);
+ (void) sm_strlcpy(src2, "1234567891", SIZE);
+ break;
+ case 2:
+ (void) sm_strlcpy(src1, "1234567892", SIZE);
+ (void) sm_strlcpy(src2, "1234567891", SIZE);
+ break;
+ }
+ printf("Test %d: strcasecmp(%s, %s) versus sm_strcasecmp()\n",
+ k, src1, src2);
+ loops = LOOPS;
+ for (;;)
+ {
+ j = 0;
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+ for (a = 0; a < loops; a++)
+ j += strcasecmp(src1, src2);
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+ one = toseconds(t2, t1);
+ printf("\tstrcasecmp() result: %ld seconds [%ld]\n",
+ one, j);
+
+ j = 0;
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+ for (a = 0; a < loops; a++)
+ j += sm_strcasecmp(src1, src2);
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+ two = toseconds(t2, t1);
+ printf("\tsm_strcasecmp() result: %ld seconds [%ld]\n",
+ two, j);
+
+ if (abs(one - two) > 2)
+ break;
+ loops += loops;
+ if (loops < 0L || one > MAXTIME)
+ {
+ printf("\t\t** results too close: no decision\n");
+ break;
+ }
+ else
+ {
+ printf("\t\t** results too close redoing test %ld times **\n",
+ loops);
+ }
+ }
+ }
+
+ printf("\n\n");
+ printf("Interpreting the results:\n");
+ printf("\tFor differences larger than 2 seconds, the lower value is\n");
+ printf("\tbetter and that function should be used for performance\n");
+ printf("\treasons.\n\n");
+ printf("This program will re-run the tests when the difference is\n");
+ printf("less than 2 seconds.\n");
+ printf("The result will vary depending on the compiler optimization\n"); printf("level used. Compiling the sendmail libsm library with a\n");
+ printf("better optimization level can change the results.\n");
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/b-strl.c b/gnu/usr.sbin/sendmail/libsm/b-strl.c
new file mode 100644
index 00000000000..5179642f8d5
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/b-strl.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2000-2001 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.
+ *
+ */
+
+/*
+** Compile this program using a command line similar to:
+** cc -O -L../OBJ/libsm -o b-strl b-strl.c -lsm
+** where "OBJ" is the name of the object directory for the platform
+** you are compiling on.
+** Then run the program:
+** ./b-strl
+** and read the output for results and how to interpret the results.
+*/
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Sendmail: b-strl.c,v 1.22 2001/04/03 01:53:10 gshapiro Exp $")
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sm/string.h>
+
+#define SRC_SIZE 512
+#define toseconds(x, y) (x.tv_sec - y.tv_sec)
+#define LOOPS 4000000L /* initial number of loops */
+#define MAXTIME 30L /* "maximum" time to run single test */
+
+void
+fatal(str)
+ char *str;
+{
+ perror(str);
+ exit(1);
+}
+
+void
+purpose()
+{
+ printf("This program benchmarks the performance differences between\n");
+ printf("strlcpy() and sm_strlcpy(), and strlcat() and sm_strlcat().\n");
+ printf("These tests may take several minutes to complete.\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#if !SM_CONF_STRL
+ printf("The configuration indicates the system needs the libsm\n");
+ printf("versions of strlcpy(3) and strlcat(3). Thus, performing\n");
+ printf("these tests will not be of much use.\n");
+ printf("If your OS has strlcpy(3) and strlcat(3) then set the macro\n");
+ printf("SM_CONF_STRL to 1 in your site.config.m4 file\n");
+ printf("(located in ../devtools/Site) and recompile this program.\n");
+#else /* !SM_CONF_STRL */
+ int ch;
+ long a;
+ bool doit = false;
+ long loops = LOOPS;
+ long one, two;
+ struct timeval t1, t2;
+ char dest[SRC_SIZE], source[SRC_SIZE];
+
+# define OPTIONS "d"
+ while ((ch = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch ((char) ch)
+ {
+ case 'd':
+ doit = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!doit)
+ {
+ purpose();
+ printf("If you want to run it, specify -d as option.\n");
+ return 0;
+ }
+
+ /*
+ ** Let's place a small string at the head of dest for
+ ** catenation to happen (it'll be ignored for the copy).
+ */
+ (void) sm_strlcpy(dest, "a small string at the start! ", SRC_SIZE - 1);
+
+ /*
+ ** Let's place a larger string into source for the catenation and
+ ** the copy.
+ */
+ (void) strlcpy(source,
+ " This is the longer string that will be used for catenation and copying for the the performace testing. The longer the string being catenated or copied the greater the difference in measureable performance\n",
+ SRC_SIZE - 1);
+
+ /* Run-time comments to the user */
+ purpose();
+ printf("\n");
+ printf("Test 1: strlcat() versus sm_strlcat()\n");
+
+redo_cat:
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ strlcat(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tstrlcat() result: %ld seconds\n", one = toseconds(t2, t1));
+
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ sm_strlcat(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tsm_strlcat() result: %ld seconds\n", two = toseconds(t2, t1));
+
+ if (one - two >= -2 && one - two <= 2)
+ {
+ loops += loops;
+ if (loops < 0L || one > MAXTIME)
+ {
+ printf("\t\t** results too close: no decision\n");
+ }
+ else
+ {
+ printf("\t\t** results too close redoing test %ld times **\n",
+ loops);
+ goto redo_cat;
+ }
+ }
+
+ printf("\n");
+ printf("Test 2: strlcpy() versus sm_strlpy()\n");
+ loops = LOOPS;
+redo_cpy:
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ strlcpy(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tstrlcpy() result: %ld seconds\n", one = toseconds(t2, t1));
+
+ if (gettimeofday(&t1, NULL) < 0)
+ fatal("gettimeofday");
+
+ for (a = 0; a < loops; a++)
+ sm_strlcpy(dest, source, SRC_SIZE - 1);
+
+ if (gettimeofday(&t2, NULL) < 0)
+ fatal("gettimeofday");
+
+ printf("\tsm_strlcpy() result: %ld seconds\n", two = toseconds(t2, t1));
+
+ if (one - two >= -2 && one - two <= 2)
+ {
+ loops += loops;
+ if (loops < 0L || one > MAXTIME)
+ {
+ printf("\t\t** results too close: no decision\n");
+ }
+ else
+ {
+ printf("\t\t** results too close redoing test %ld times **\n",
+ loops);
+ goto redo_cpy;
+ }
+ }
+
+ printf("\n\n");
+ printf("Interpreting the results:\n");
+ printf("\tFor differences larger than 2 seconds, the lower value is\n");
+ printf("\tbetter and that function should be used for performance\n");
+ printf("\treasons.\n\n");
+ printf("This program will re-run the tests when the difference is\n");
+ printf("less than 2 seconds.\n");
+ printf("The result will vary depending on the compiler optimization\n"); printf("level used. Compiling the sendmail libsm library with a\n");
+ printf("better optimization level can change the results.\n");
+#endif /* !SM_CONF_STRL */
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/cdefs.html b/gnu/usr.sbin/sendmail/libsm/cdefs.html
new file mode 100644
index 00000000000..9be6a4e1fd7
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/cdefs.html
@@ -0,0 +1,107 @@
+<html>
+<head>
+ <title>libsm : C Language Portability Macros</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : C Language Portability Macros </h1>
+ <br> $Sendmail: cdefs.html,v 1.2 2000/12/07 17:33:09 dmoen Exp $
+</center>
+
+<h2> Description </h2>
+
+The header file <tt>&lt;sm/cdefs.h&gt;</tt>
+defines portable interfaces to non-portable features
+of various C compilers.
+It also assists you in writing C header files that are compatible
+with C++.
+
+<dl>
+<dt>
+<tt> __P(parameterlist) </tt>
+<dd>
+ This macro is used to write portable function prototypes.
+ For example,
+
+<blockquote><pre>
+int foo __P((int));
+</pre></blockquote>
+
+<dt>
+<tt> __CONCAT(x,y) </tt>
+<dd>
+ This macro concatenates two tokens x and y,
+ forming a single token xy.
+ Warning: make sure there is no white space around the arguments x and y.
+ <p>
+
+<dt>
+<tt> __STRING(x) </tt>
+<dd>
+ This macro converts the token sequence x into a string literal.
+ <p>
+
+<dt>
+<tt> __BEGIN_DECLS, __END_DECLS </tt>
+<dd>
+ These macros are used to write C header files that are compatible
+ with C++ compilers.
+ Put <tt>__BEGIN_DECLS</tt> before the first function or variable
+ declaration in your header file,
+ and put <tt>__END_DECLS</tt> after the last function or variable
+ declaration.
+ <p>
+
+<dt>
+<tt> const, signed, volatile </tt>
+<dd>
+ For pre-ANSI C compilers, <tt>const</tt>, <tt>signed</tt>
+ and <tt>volatile</tt> are defined as empty macros.
+ This means you can use these keywords without introducing
+ portability problems.
+ <p>
+
+<dt>
+<tt> SM_DEAD(function_declaration) </tt>
+<dd>
+ This macro modifies a prototype of a function
+ that does not return to its caller.
+ With some versions of gcc, this will result in slightly better code,
+ and can suppress some useless warnings produced by gcc -Wall.
+ For example,
+
+<blockquote><pre>
+SM_DEAD(void exit __P((int)));
+</pre></blockquote>
+
+<dt>
+<tt> SM_UNUSED(variable_declaration) </tt>
+<dd>
+ This macro modifies a definition of an unused
+ local variable, global variable or function parameter
+ in order to suppress compiler warnings.
+ Examples:
+
+<blockquote><pre>
+SM_UNUSED(static const char Id[]) = "@(#)$Sendmail: cdefs.html,v 1.2 2000/12/07 17:33:09 dmoen Exp $";
+void
+foo(x)
+ SM_UNUSED(int x);
+{
+ SM_UNUSED(int y) = 0;
+ return 0;
+}
+void
+bar(SM_UNUSED(int x))
+{
+ return 0;
+}
+</pre></blockquote>
+
+</dl>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/cf.c b/gnu/usr.sbin/sendmail/libsm/cf.c
new file mode 100644
index 00000000000..9ee2bbfa218
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/cf.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: cf.c,v 1.4 2001/02/01 02:40:21 dmoen Exp $")
+
+#include <ctype.h>
+#include <errno.h>
+
+#include <sm/cf.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/heap.h>
+
+/*
+** SM_CF_GETOPT -- look up option values in the sendmail.cf file
+**
+** Open the sendmail.cf file and parse all of the 'O' directives.
+** Each time one of the options named in the option vector optv
+** is found, store a malloced copy of the option value in optv.
+**
+** Parameters:
+** path -- pathname of sendmail.cf file
+** optc -- size of option vector
+** optv -- pointer to option vector
+**
+** Results:
+** 0 on success, or an errno value on failure.
+** An exception is raised on malloc failure.
+*/
+
+int
+sm_cf_getopt(path, optc, optv)
+ char *path;
+ int optc;
+ SM_CF_OPT_T *optv;
+{
+ SM_FILE_T *cfp;
+ char buf[2048];
+ char *p;
+ char *id;
+ char *idend;
+ char *val;
+ int i;
+
+ cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, path, SM_IO_RDONLY, NULL);
+ if (cfp == NULL)
+ return errno;
+
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
+ {
+ p = strchr(buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+
+ if (buf[0] != 'O' || buf[1] != ' ')
+ continue;
+
+ id = &buf[2];
+ val = strchr(id, '=');
+ if (val == NULL)
+ val = idend = id + strlen(id);
+ else
+ {
+ idend = val;
+ ++val;
+ while (*val == ' ')
+ ++val;
+ while (idend > id && idend[-1] == ' ')
+ --idend;
+ *idend = '\0';
+ }
+
+ for (i = 0; i < optc; ++i)
+ {
+ if (sm_strcasecmp(optv[i].opt_name, id) == 0)
+ {
+ optv[i].opt_val = sm_strdup_x(val);
+ break;
+ }
+ }
+ }
+ if (sm_io_error(cfp))
+ {
+ int save_errno = errno;
+
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
+ errno = save_errno;
+ return errno;
+ }
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/clock.c b/gnu/usr.sbin/sendmail/libsm/clock.c
new file mode 100644
index 00000000000..b3f2355eee7
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/clock.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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("@(#)$Sendmail: clock.c,v 1.30 2001/08/31 20:44:28 ca Exp $")
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#if SM_CONF_SETITIMER
+# include <sys/time.h>
+#endif /* SM_CONF_SETITIMER */
+#include <sm/heap.h>
+#include <sm/debug.h>
+#include <sm/bitops.h>
+#include <sm/clock.h>
+#include "local.h"
+
+#ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+#endif /* ! sigmask */
+
+static void sm_endsleep __P((void));
+
+
+/*
+** SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
+**
+** Events are stored in a sorted list for fast processing.
+** An event only applies to the process that set it.
+** Source is #ifdef'd to work with older OS's that don't have setitimer()
+** (that is, don't have a timer granularity less than 1 second).
+**
+** Parameters:
+** intvl -- interval until next event occurs (milliseconds).
+** func -- function to call on event.
+** arg -- argument to func on event.
+**
+** Returns:
+** On success returns the SM_EVENT entry created.
+** On failure returns NULL.
+**
+** Side Effects:
+** none.
+*/
+
+static SM_EVENT *volatile SmEventQueue; /* head of event queue */
+static SM_EVENT *volatile SmFreeEventList; /* list of free events */
+
+SM_EVENT *
+sm_seteventm(intvl, func, arg)
+ int intvl;
+ void (*func)();
+ int arg;
+{
+ ENTER_CRITICAL();
+ if (SmFreeEventList == NULL)
+ {
+ SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
+ SmFreeEventList->ev_link = NULL;
+ }
+ LEAVE_CRITICAL();
+
+ return sm_sigsafe_seteventm(intvl, func, arg);
+}
+
+/*
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+SM_EVENT *
+sm_sigsafe_seteventm(intvl, func, arg)
+ int intvl;
+ void (*func)();
+ int arg;
+{
+ register SM_EVENT **evp;
+ register SM_EVENT *ev;
+#if SM_CONF_SETITIMER
+ auto struct timeval now, nowi, ival;
+ auto struct itimerval itime;
+#else /* SM_CONF_SETITIMER */
+ auto time_t now, nowi;
+#endif /* SM_CONF_SETITIMER */
+ int wasblocked;
+
+ /* negative times are not allowed */
+ if (intvl <= 0)
+ return NULL;
+
+ wasblocked = sm_blocksignal(SIGALRM);
+#if SM_CONF_SETITIMER
+ ival.tv_sec = intvl / 1000;
+ ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
+ (void) gettimeofday(&now, NULL);
+ nowi = now;
+ timeradd(&now, &ival, &nowi);
+#else /* SM_CONF_SETITIMER */
+ now = time(NULL);
+ nowi = now + (time_t)(intvl / 1000);
+#endif /* SM_CONF_SETITIMER */
+
+ /* search event queue for correct position */
+ for (evp = (SM_EVENT **) (&SmEventQueue);
+ (ev = *evp) != NULL;
+ evp = &ev->ev_link)
+ {
+#if SM_CONF_SETITIMER
+ if (timercmp(&(ev->ev_time), &nowi, >))
+#else /* SM_CONF_SETITIMER */
+ if (ev->ev_time >= nowi)
+#endif /* SM_CONF_SETITIMER */
+ break;
+ }
+
+ ENTER_CRITICAL();
+ if (SmFreeEventList == NULL)
+ {
+ /*
+ ** This shouldn't happen. If called from sm_seteventm(),
+ ** we have just malloced a SmFreeEventList entry. If
+ ** called from a signal handler, it should have been
+ ** from an existing event which sm_tick() just added to
+ ** SmFreeEventList.
+ */
+
+ LEAVE_CRITICAL();
+ return NULL;
+ }
+ else
+ {
+ ev = SmFreeEventList;
+ SmFreeEventList = ev->ev_link;
+ }
+ LEAVE_CRITICAL();
+
+ /* insert new event */
+ ev->ev_time = nowi;
+ ev->ev_func = func;
+ ev->ev_arg = arg;
+ ev->ev_pid = getpid();
+ ENTER_CRITICAL();
+ ev->ev_link = *evp;
+ *evp = ev;
+ LEAVE_CRITICAL();
+
+ (void) sm_signal(SIGALRM, sm_tick);
+# if SM_CONF_SETITIMER
+ timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
+ itime.it_interval.tv_sec = 0;
+ itime.it_interval.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &itime, NULL);
+# else /* SM_CONF_SETITIMER */
+ intvl = SmEventQueue->ev_time - now;
+ (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
+# endif /* SM_CONF_SETITIMER */
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+ return ev;
+}
+ /*
+** SM_CLREVENT -- remove an event from the event queue.
+**
+** Parameters:
+** ev -- pointer to event to remove.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** arranges for event ev to not happen.
+*/
+
+void
+sm_clrevent(ev)
+ register SM_EVENT *ev;
+{
+ register SM_EVENT **evp;
+ int wasblocked;
+# if SM_CONF_SETITIMER
+ struct itimerval clr;
+# endif /* SM_CONF_SETITIMER */
+
+ if (ev == NULL)
+ return;
+
+ /* find the parent event */
+ wasblocked = sm_blocksignal(SIGALRM);
+ for (evp = (SM_EVENT **) (&SmEventQueue);
+ *evp != NULL;
+ evp = &(*evp)->ev_link)
+ {
+ if (*evp == ev)
+ break;
+ }
+
+ /* now remove it */
+ if (*evp != NULL)
+ {
+ ENTER_CRITICAL();
+ *evp = ev->ev_link;
+ ev->ev_link = SmFreeEventList;
+ SmFreeEventList = ev;
+ LEAVE_CRITICAL();
+ }
+
+ /* restore clocks and pick up anything spare */
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+ if (SmEventQueue != NULL)
+ (void) kill(getpid(), SIGALRM);
+ else
+ {
+ /* nothing left in event queue, no need for an alarm */
+# if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+# else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+# endif /* SM_CONF_SETITIMER */
+ }
+}
+ /*
+** SM_CLEAR_EVENTS -- remove all events from the event queue.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_clear_events()
+{
+ register SM_EVENT *ev;
+#if SM_CONF_SETITIMER
+ struct itimerval clr;
+#endif /* SM_CONF_SETITIMER */
+ int wasblocked;
+
+ if (SmEventQueue == NULL)
+ return;
+
+ /* nothing will be left in event queue, no need for an alarm */
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+#endif /* SM_CONF_SETITIMER */
+ wasblocked = sm_blocksignal(SIGALRM);
+
+ /* find the end of the EventQueue */
+ for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
+ continue;
+
+ ENTER_CRITICAL();
+ ev->ev_link = SmFreeEventList;
+ SmFreeEventList = SmEventQueue;
+ SmEventQueue = NULL;
+ LEAVE_CRITICAL();
+
+ /* restore clocks and pick up anything spare */
+ if (wasblocked == 0)
+ (void) sm_releasesignal(SIGALRM);
+}
+ /*
+** SM_TICK -- take a clock tick
+**
+** Called by the alarm clock. This routine runs events as needed.
+** Always called as a signal handler, so we assume that SIGALRM
+** has been blocked.
+**
+** Parameters:
+** One that is ignored; for compatibility with signal handlers.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** calls the next function in EventQueue.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED */
+SIGFUNC_DECL
+sm_tick(sig)
+ int sig;
+{
+ register SM_EVENT *ev;
+ pid_t mypid;
+ int save_errno = errno;
+#if SM_CONF_SETITIMER
+ struct itimerval clr;
+ struct timeval now;
+#else /* SM_CONF_SETITIMER */
+ register time_t now;
+#endif /* SM_CONF_SETITIMER */
+
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ gettimeofday(&now, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+ now = time(NULL);
+#endif /* SM_CONF_SETITIMER */
+
+ FIX_SYSV_SIGNAL(sig, sm_tick);
+ errno = save_errno;
+ CHECK_CRITICAL(sig);
+
+ mypid = getpid();
+ while (PendingSignal != 0)
+ {
+ int sigbit = 0;
+ int sig = 0;
+
+ if (bitset(PEND_SIGHUP, PendingSignal))
+ {
+ sigbit = PEND_SIGHUP;
+ sig = SIGHUP;
+ }
+ else if (bitset(PEND_SIGINT, PendingSignal))
+ {
+ sigbit = PEND_SIGINT;
+ sig = SIGINT;
+ }
+ else if (bitset(PEND_SIGTERM, PendingSignal))
+ {
+ sigbit = PEND_SIGTERM;
+ sig = SIGTERM;
+ }
+ else if (bitset(PEND_SIGUSR1, PendingSignal))
+ {
+ sigbit = PEND_SIGUSR1;
+ sig = SIGUSR1;
+ }
+ else
+ {
+ /* If we get here, we are in trouble */
+ abort();
+ }
+ PendingSignal &= ~sigbit;
+ kill(mypid, sig);
+ }
+
+#if SM_CONF_SETITIMER
+ gettimeofday(&now, NULL);
+#else /* SM_CONF_SETITIMER */
+ now = time(NULL);
+#endif /* SM_CONF_SETITIMER */
+ while ((ev = SmEventQueue) != NULL &&
+ (ev->ev_pid != mypid ||
+#if SM_CONF_SETITIMER
+ timercmp(&ev->ev_time, &now, <)
+#else /* SM_CONF_SETITIMER */
+ ev->ev_time <= now
+#endif /* SM_CONF_SETITIMER */
+ ))
+ {
+ void (*f)();
+ int arg;
+ pid_t pid;
+
+ /* process the event on the top of the queue */
+ ev = SmEventQueue;
+ SmEventQueue = SmEventQueue->ev_link;
+
+ /* we must be careful in here because ev_func may not return */
+ f = ev->ev_func;
+ arg = ev->ev_arg;
+ pid = ev->ev_pid;
+ ENTER_CRITICAL();
+ ev->ev_link = SmFreeEventList;
+ SmFreeEventList = ev;
+ LEAVE_CRITICAL();
+ if (pid != getpid())
+ continue;
+ if (SmEventQueue != NULL)
+ {
+#if SM_CONF_SETITIMER
+ if (timercmp(&SmEventQueue->ev_time, &now, >))
+ {
+ timersub(&SmEventQueue->ev_time, &now,
+ &clr.it_value);
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ }
+ else
+ {
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 3;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ }
+#else /* SM_CONF_SETITIMER */
+ if (SmEventQueue->ev_time > now)
+ (void) alarm((unsigned) (SmEventQueue->ev_time
+ - now));
+ else
+ (void) alarm(3);
+#endif /* SM_CONF_SETITIMER */
+ }
+
+ /* call ev_func */
+ errno = save_errno;
+ (*f)(arg);
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 0;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+ gettimeofday(&now, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(0);
+ now = time(NULL);
+#endif /* SM_CONF_SETITIMER */
+ }
+ if (SmEventQueue != NULL)
+ {
+#if SM_CONF_SETITIMER
+ timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm((unsigned) (SmEventQueue->ev_time - now));
+#endif /* SM_CONF_SETITIMER */
+ }
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+ /*
+** SLEEP -- a version of sleep that works with this stuff
+**
+** Because Unix sleep uses the alarm facility, I must reimplement
+** it here.
+**
+** Parameters:
+** intvl -- time to sleep.
+**
+** Returns:
+** zero.
+**
+** Side Effects:
+** waits for intvl time. However, other events can
+** be run during that interval.
+*/
+
+
+static bool volatile SmSleepDone;
+
+#ifndef SLEEP_T
+# define SLEEP_T unsigned int
+#endif /* ! SLEEP_T */
+
+SLEEP_T
+sleep(intvl)
+ unsigned int intvl;
+{
+ int was_held;
+
+ if (intvl == 0)
+ return (SLEEP_T) 0;
+ SmSleepDone = false;
+ (void) sm_setevent((time_t) intvl, sm_endsleep, 0);
+ was_held = sm_releasesignal(SIGALRM);
+ while (!SmSleepDone)
+ (void) pause();
+ if (was_held > 0)
+ (void) sm_blocksignal(SIGALRM);
+ return (SLEEP_T) 0;
+}
+
+static void
+sm_endsleep()
+{
+ /*
+ ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+ ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+ ** DOING.
+ */
+
+ SmSleepDone = true;
+}
+
diff --git a/gnu/usr.sbin/sendmail/libsm/clrerr.c b/gnu/usr.sbin/sendmail/libsm/clrerr.c
new file mode 100644
index 00000000000..0fb699f9a07
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/clrerr.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: clrerr.c,v 1.11 2001/01/28 00:29:34 ca Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_CLEARERR -- public function to clear a file pointer's error status
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Returns:
+** nothing.
+*/
+#undef sm_io_clearerr
+
+void
+sm_io_clearerr(fp)
+ SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ sm_clearerr(fp);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/config.c b/gnu/usr.sbin/sendmail/libsm/config.c
new file mode 100644
index 00000000000..c6c321d97ba
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/config.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: config.c,v 1.19 2001/09/04 22:41:27 ca Exp $")
+
+#include <stdlib.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/conf.h>
+
+ /*
+** PUTENV -- emulation of putenv() in terms of setenv()
+**
+** Not needed on Posix-compliant systems.
+** This doesn't have full Posix semantics, but it's good enough
+** for sendmail.
+**
+** Parameter:
+** env -- the environment to put.
+**
+** Returns:
+** 0 on success, < 0 on failure.
+*/
+
+#if NEEDPUTENV
+
+# if NEEDPUTENV == 2 /* no setenv(3) call available */
+
+int
+putenv(str)
+ char *str;
+{
+ char **current;
+ int matchlen, envlen = 0;
+ char *tmp;
+ char **newenv;
+ static bool first = true;
+ extern char **environ;
+
+ /*
+ ** find out how much of str to match when searching
+ ** for a string to replace.
+ */
+
+ if ((tmp = strchr(str, '=')) == NULL || tmp == str)
+ matchlen = strlen(str);
+ else
+ matchlen = (int) (tmp - str);
+ ++matchlen;
+
+ /*
+ ** Search for an existing string in the environment and find the
+ ** length of environ. If found, replace and exit.
+ */
+
+ for (current = environ; *current != NULL; current++)
+ {
+ ++envlen;
+
+ if (strncmp(str, *current, matchlen) == 0)
+ {
+ /* found it, now insert the new version */
+ *current = (char *) str;
+ return 0;
+ }
+ }
+
+ /*
+ ** There wasn't already a slot so add space for a new slot.
+ ** If this is our first time through, use malloc(), else realloc().
+ */
+
+ if (first)
+ {
+ newenv = (char **) sm_malloc(sizeof(char *) * (envlen + 2));
+ if (newenv == NULL)
+ return -1;
+
+ first = false;
+ (void) memcpy(newenv, environ, sizeof(char *) * envlen);
+ }
+ else
+ {
+ newenv = (char **) sm_realloc((char *) environ,
+ sizeof(char *) * (envlen + 2));
+ if (newenv == NULL)
+ return -1;
+ }
+
+ /* actually add in the new entry */
+ environ = newenv;
+ environ[envlen] = (char *) str;
+ environ[envlen + 1] = NULL;
+
+ return 0;
+}
+
+# else /* NEEDPUTENV == 2 */
+
+int
+putenv(env)
+ char *env;
+{
+ char *p;
+ int l;
+ char nbuf[100];
+
+ p = strchr(env, '=');
+ if (p == NULL)
+ return 0;
+ l = p - env;
+ if (l > sizeof nbuf - 1)
+ l = sizeof nbuf - 1;
+ memmove(nbuf, env, l);
+ nbuf[l] = '\0';
+ return setenv(nbuf, ++p, 1);
+}
+
+# endif /* NEEDPUTENV == 2 */
+#endif /* NEEDPUTENV */
+ /*
+** UNSETENV -- remove a variable from the environment
+**
+** Not needed on newer systems.
+**
+** Parameters:
+** name -- the string name of the environment variable to be
+** deleted from the current environment.
+**
+** Returns:
+** none.
+**
+** Globals:
+** environ -- a pointer to the current environment.
+**
+** Side Effects:
+** Modifies environ.
+*/
+
+#if !HASUNSETENV
+
+void
+unsetenv(name)
+ char *name;
+{
+ extern char **environ;
+ register char **pp;
+ int len = strlen(name);
+
+ for (pp = environ; *pp != NULL; pp++)
+ {
+ if (strncmp(name, *pp, len) == 0 &&
+ ((*pp)[len] == '=' || (*pp)[len] == '\0'))
+ break;
+ }
+
+ for (; *pp != NULL; pp++)
+ *pp = pp[1];
+}
+
+#endif /* !HASUNSETENV */
+
+char *SmCompileOptions[] =
+{
+#if SM_CONF_BROKEN_STRTOD
+ "SM_CONF_BROKEN_STRTOD",
+#endif /* SM_CONF_BROKEN_STRTOD */
+#if SM_CONF_GETOPT
+ "SM_CONF_GETOPT",
+#endif /* SM_CONF_GETOPT */
+#if SM_CONF_LONGLONG
+ "SM_CONF_LONGLONG",
+#endif /* SM_CONF_LONGLONG */
+#if SM_CONF_MEMCHR
+ "SM_CONF_MEMCHR",
+#endif /* SM_CONF_MEMCHR */
+#if SM_CONF_MSG
+ "SM_CONF_MSG",
+#endif /* SM_CONF_MSG */
+#if SM_CONF_QUAD_T
+ "SM_CONF_QUAD_T",
+#endif /* SM_CONF_QUAD_T */
+#if SM_CONF_SEM
+ "SM_CONF_SEM",
+#endif /* SM_CONF_SEM */
+#if SM_CONF_SETITIMER
+ "SM_CONF_SETITIMER",
+#endif /* SM_CONF_SETITIMER */
+#if SM_CONF_SHM
+ "SM_CONF_SHM",
+#endif /* SM_CONF_SHM */
+#if SM_CONF_SHM_DELAY
+ "SM_CONF_SHM_DELAY",
+#endif /* SM_CONF_SHM_DELAY */
+#if SM_CONF_SSIZE_T
+ "SM_CONF_SSIZE_T",
+#endif /* SM_CONF_SSIZE_T */
+#if SM_CONF_STDBOOL_H
+ "SM_CONF_STDBOOL_H",
+#endif /* SM_CONF_STDBOOL_H */
+#if SM_CONF_STDDEF_H
+ "SM_CONF_STDDEF_H",
+#endif /* SM_CONF_STDDEF_H */
+
+#if 0
+/* XXX this is always enabled (for now) */
+#if SM_CONF_STRL
+ "SM_CONF_STRL",
+#endif /* SM_CONF_STRL */
+#endif /* 0 */
+
+#if SM_CONF_SYS_CDEFS_H
+ "SM_CONF_SYS_CDEFS_H",
+#endif /* SM_CONF_SYS_CDEFS_H */
+#if SM_CONF_SYSEXITS_H
+ "SM_CONF_SYSEXITS_H",
+#endif /* SM_CONF_SYSEXITS_H */
+#if SM_CONF_UID_GID
+ "SM_CONF_UID_GID",
+#endif /* SM_CONF_UID_GID */
+#if SM_HEAP_CHECK
+ "SM_HEAP_CHECK",
+#endif /* SM_HEAP_CHECK */
+#if defined(SM_OS_NAME) && defined(__STDC__)
+ "SM_OS=sm_os_" SM_OS_NAME,
+#endif /* defined(SM_OS_NAME) && defined(__STDC__) */
+#if SM_VA_STD
+ "SM_VA_STD",
+#endif /* SM_VA_STD */
+ NULL
+};
diff --git a/gnu/usr.sbin/sendmail/libsm/debug.c b/gnu/usr.sbin/sendmail/libsm/debug.c
new file mode 100644
index 00000000000..5a201967563
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/debug.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: debug.c,v 1.25 2001/09/04 22:41:27 ca Exp $")
+
+/*
+** libsm debugging and tracing
+** For documentation, see debug.html.
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/conf.h>
+#include <sm/debug.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+#include <sm/heap.h>
+
+/*
+** Abstractions for printing trace messages.
+*/
+
+/*
+** The output file to which trace output is directed.
+** There is a controversy over whether this variable
+** should be process global or thread local.
+** To make the interface more abstract, we've hidden the
+** variable behind access functions.
+*/
+
+static SM_FILE_T *SmDebugOutput = smioout;
+
+/*
+** SM_DEBUG_FILE -- Returns current debug file pointer.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** current debug file pointer.
+*/
+
+SM_FILE_T *
+sm_debug_file()
+{
+ return SmDebugOutput;
+}
+
+/*
+** SM_DEBUG_SETFILE -- Sets debug file pointer.
+**
+** Parameters:
+** fp -- new debug file pointer.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Sets SmDebugOutput.
+*/
+
+void
+sm_debug_setfile(fp)
+ SM_FILE_T *fp;
+{
+ SmDebugOutput = fp;
+}
+
+/*
+** SM_DPRINTF -- printf() for debug output.
+**
+** Parameters:
+** fmt -- format for printf()
+**
+** Returns:
+** none.
+*/
+
+void
+#if SM_VA_STD
+sm_dprintf(char *fmt, ...)
+#else /* SM_VA_STD */
+sm_dprintf(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, fmt);
+ sm_io_vfprintf(SmDebugOutput, SmDebugOutput->f_timeout, fmt, ap);
+ SM_VA_END(ap);
+}
+
+/*
+** SM_DFLUSH -- Flush debug output.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_dflush()
+{
+ sm_io_flush(SmDebugOutput, SM_TIME_DEFAULT);
+}
+
+/*
+** This is the internal database of debug settings.
+** The semantics of looking up a setting in the settings database
+** are that the *last* setting specified in a -d option on the sendmail
+** command line that matches a given SM_DEBUG structure is the one that is
+** used. That is necessary to conform to the existing semantics of
+** the sendmail -d option. We store the settings as a linked list in
+** reverse order, so when we do a lookup, we take the *first* entry
+** that matches.
+*/
+
+typedef struct sm_debug_setting SM_DEBUG_SETTING_T;
+struct sm_debug_setting
+{
+ const char *ds_pattern;
+ unsigned int ds_level;
+ SM_DEBUG_SETTING_T *ds_next;
+};
+SM_DEBUG_SETTING_T *SmDebugSettings = NULL;
+
+/*
+** We keep a linked list of SM_DEBUG structures that have been initialized,
+** for use by sm_debug_reset.
+*/
+
+SM_DEBUG_T *SmDebugInitialized = NULL;
+
+const char SmDebugMagic[] = "sm_debug";
+
+/*
+** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
+**
+** Reset all SM_DEBUG structures back to the uninitialized state.
+** This is used by sm_debug_addsetting to ensure that references to
+** SM_DEBUG structures that occur before sendmail processes its -d flags
+** do not cause those structures to be permanently forced to level 0.
+**
+** Parameters:
+** none.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_debug_reset()
+{
+ SM_DEBUG_T *debug;
+
+ for (debug = SmDebugInitialized;
+ debug != NULL;
+ debug = debug->debug_next)
+ {
+ debug->debug_level = SM_DEBUG_UNKNOWN;
+ }
+ SmDebugInitialized = NULL;
+}
+
+/*
+** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
+**
+** Parameters:
+** pattern -- a shell-style glob pattern (see sm_match).
+** WARNING: the storage for 'pattern' will be owned by
+** the debug package, so it should either be a string
+** literal or the result of a call to sm_strdup_x.
+** level -- a non-negative integer.
+**
+** Returns:
+** none.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void
+sm_debug_addsetting_x(pattern, level)
+ const char *pattern;
+ int level;
+{
+ SM_DEBUG_SETTING_T *s;
+
+ SM_REQUIRE(pattern != NULL);
+ SM_REQUIRE(level >= 0);
+ s = sm_malloc_x(sizeof(SM_DEBUG_SETTING_T));
+ s->ds_pattern = pattern;
+ s->ds_level = (unsigned int) level;
+ s->ds_next = SmDebugSettings;
+ SmDebugSettings = s;
+ sm_debug_reset();
+}
+
+/*
+** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
+**
+** Parameters:
+** s -- Points to a non-empty \0 or , terminated string,
+** of which the initial character is not a digit.
+**
+** Returns:
+** pointer to terminating \0 or , character.
+**
+** Exceptions:
+** F:sm.heap -- out of memory.
+**
+** Side Effects:
+** adds the setting to the database.
+*/
+
+static const char *
+parse_named_setting_x(s)
+ register const char *s;
+{
+ const char *pat, *endpat;
+ int level;
+
+ pat = s;
+ while (*s != '\0' && *s != ',' && *s != '.')
+ ++s;
+ endpat = s;
+ if (*s == '.')
+ {
+ ++s;
+ level = 0;
+ while (isascii(*s) && isdigit(*s))
+ {
+ level = level * 10 + (*s - '0');
+ ++s;
+ }
+ if (level < 0)
+ level = 0;
+ }
+ else
+ level = 1;
+
+ sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
+
+ /* skip trailing junk */
+ while (*s != '\0' && *s != ',')
+ ++s;
+
+ return s;
+}
+
+/*
+** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
+**
+** Parameters:
+** s -- a list of debug settings, eg the argument to the
+** sendmail -d option.
+**
+** The syntax of the string s is as follows:
+**
+** <settings> ::= <setting> | <settings> "," <setting>
+** <setting> ::= <categories> | <categories> "." <level>
+** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
+**
+** However, note that we skip over anything we don't
+** understand, rather than report an error.
+**
+** Returns:
+** none.
+**
+** Exceptions:
+** F:sm.heap -- out of memory
+**
+** Side Effects:
+** updates the database of debug settings.
+*/
+
+void
+sm_debug_addsettings_x(s)
+ register const char *s;
+{
+ for (;;)
+ {
+ if (*s == '\0')
+ return;
+ if (*s == ',')
+ {
+ ++s;
+ continue;
+ }
+ s = parse_named_setting_x(s);
+ }
+}
+
+/*
+** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
+**
+** Parameters:
+** debug -- debug object.
+**
+** Returns:
+** Activation level of the specified debug object.
+**
+** Side Effects:
+** Ensures that the debug object is initialized.
+*/
+
+int
+sm_debug_loadlevel(debug)
+ SM_DEBUG_T *debug;
+{
+ if (debug->debug_level == SM_DEBUG_UNKNOWN)
+ {
+ SM_DEBUG_SETTING_T *s;
+
+ for (s = SmDebugSettings; s != NULL; s = s->ds_next)
+ {
+ if (sm_match(debug->debug_name, s->ds_pattern))
+ {
+ debug->debug_level = s->ds_level;
+ goto initialized;
+ }
+ }
+ debug->debug_level = 0;
+ initialized:
+ debug->debug_next = SmDebugInitialized;
+ SmDebugInitialized = debug;
+ }
+ return (int) debug->debug_level;
+}
+
+/*
+** SM_DEBUG_LOADACTIVE -- Activation level reached?
+**
+** Parameters:
+** debug -- debug object.
+** level -- level to check.
+**
+** Returns:
+** true iff the activation level of the specified debug
+** object >= level.
+**
+** Side Effects:
+** Ensures that the debug object is initialized.
+*/
+
+bool
+sm_debug_loadactive(debug, level)
+ SM_DEBUG_T *debug;
+ int level;
+{
+ return sm_debug_loadlevel(debug) >= level;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/debug.html b/gnu/usr.sbin/sendmail/libsm/debug.html
new file mode 100644
index 00000000000..78325b4c367
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/debug.html
@@ -0,0 +1,276 @@
+<html>
+<head>
+ <title>libsm : Debugging and Tracing</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Debugging and Tracing </h1>
+ <br> $Sendmail: debug.html,v 1.8 2000/12/08 21:41:41 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The debug and trace package provides abstractions for writing trace
+messages, and abstractions for enabling and disabling debug and
+trace code at run time.
+
+<p>
+Sendmail 8.11 and earlier has a <tt>-d</tt> option which
+lets you turn on debug and trace code.
+Debug categories are integers from 0 to 99, with the sole exception
+of "ANSI", which is a named debug category.
+
+<p>
+The libsm debug package supports named debug categories.
+Debug category names have the form of C identifiers.
+For example, <tt>sm_trace_heap</tt> controls the output of trace
+messages from the sm heap package, while <tt>sm_check_heap</tt>
+controls the argument validity checking and memory leak detection
+features of the sm heap package.
+
+<p>
+In sendmail 8.12, the <tt>-d</tt> flag is generalized
+to support both the original style numeric categories, for backwards
+compatibility, and the new style named categories implemented by libsm.
+With this change,
+"-dANSI" is implemented using a libsm named debug category.
+You will be able to set a collection of named debug categories to
+the same activation level by specifying a glob pattern.
+For example,
+<dl>
+<dt>
+ <tt> -dANSI </tt>
+<dd>
+ sets the named category "ANSI" to level 1,
+<dt>
+ <tt> -dfoo_*.3 </tt>
+<dd>
+ sets all named categories matching the glob pattern "foo_*" to level 3,
+<dt>
+ <tt> -d0-99.1 </tt>
+<dd>
+ sets the numeric categories 0 through 99 to level 1, and
+<dt>
+ <tt> -dANSI,foo_*.3,0-99.1 </tt>
+<dd>
+ does all of the above.
+</dl>
+
+<p>
+For sendmail 9.x, I propose to drop support for numeric debug categories,
+and just use named debug categories.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/debug.h&gt;
+
+/*
+** abstractions for printing trace messages
+*/
+void sm_dprintf(char *fmt, ...)
+void sm_dflush()
+void sm_debug_setfile(SM_FILE_T *)
+
+/*
+** abstractions for setting and testing debug activation levels
+*/
+void sm_debug_addsettings(char *settings)
+void sm_debug_addsetting(char *pattern, int level)
+
+typedef struct sm_debug SM_DEBUG_T;
+SM_DEBUG_T dbg = SM_DEBUG_INITIALIZER("name", "@(#)$Debug: name - description $");
+
+bool sm_debug_active(SM_DEBUG_T *debug, int level)
+int sm_debug_level(SM_DEBUG_T *debug)
+bool sm_debug_unknown(SM_DEBUG_T *debug)
+</pre>
+
+<h2> Naming Conventions </h2>
+
+All debug categories defined by libsm have names of the form <tt>sm_*</tt>.
+Debug categories that turn on trace output have names of the form
+<tt>*_trace_*</tt>.
+Debug categories that turn on run time checks have names of the form
+<tt>*_check_*</tt>.
+Here are all of the libsm debug categories as of March 2000:
+
+<table>
+ <tr>
+ <td>Variable name</td>
+ <td>Category name</td>
+ <td>Meaning</td>
+ </tr>
+ <tr>
+ <td>SmExpensiveAssert</td>
+ <td>sm_check_assert</td>
+ <td>enable expensive SM_ASSERT checking</td>
+ </tr>
+ <tr>
+ <td>SmExpensiveRequire</td>
+ <td>sm_check_require</td>
+ <td>enable expensive SM_REQUIRE checking</td>
+ </tr>
+ <tr>
+ <td>SmExpensiveEnsure</td>
+ <td>sm_check_ensure</td>
+ <td>enable expensive SM_ENSURE checking</td>
+ </tr>
+ <tr>
+ <td>SmHeapTrace</td>
+ <td>sm_trace_heap</td>
+ <td>trace sm_{malloc,realloc,free} calls</td>
+ </tr>
+ <tr>
+ <td>SmHeapCheck</td>
+ <td>sm_check_heap</td>
+ <td>enable checking and memory leak detection in sm_{malloc,realloc,free}</td>
+ </tr>
+</table>
+
+<h2> Function Reference </h2>
+
+<dl>
+<dt>
+<tt> SM_DEBUG_INITIALIZER </tt>
+<dd>
+ To create a new debug category, use the SM_DEBUG_INITIALIZER macro
+ to initialize a static variable of type SM_DEBUG_T. For example,
+<blockquote><pre>
+SM_DEBUG_T ANSI_debug = SM_DEBUG_INITIALIZER("ANSI",
+ "@(#)$Debug: ANSI - enable reverse video in debug output $");
+</pre></blockquote>
+ There is no centralized table of category names that needs to
+ be edited in order to add a new debug category.
+ The sole purpose of the second argument to SM_DEBUG_INITIALIZER
+ is to provide an easy way to find out what named debug categories
+ are present in a sendmail binary. You can use:
+<blockquote><pre>
+ident /usr/sbin/sendmail | grep Debug
+</pre></blockquote>
+ or:
+<blockquote><pre>
+what /usr/sbin/sendmail | grep Debug
+</pre></blockquote>
+
+
+<dt>
+<tt> void sm_debug_addsetting(char *pattern, int level) </tt>
+<dd>
+ All debug categories default to activation level 0, which means
+ no activity.
+ This function updates an internal database of debug settings,
+ setting all categories whose name matches the specified glob
+ pattern to the specified activation level. The level argument
+ must be &gt;= 0.
+ <p>
+
+
+<dt>
+<tt> void sm_debug_addsettings(char *settings) </tt>
+<dd>
+ This function is used to process the <tt>-d</tt> command line
+ option of Sendmail 9.x, and of other programs that support the
+ setting of named debug categories. The settings argument is a
+ comma-separated list of settings; each setting is a glob pattern,
+ optionally followed by a '.' and a decimal numeral.
+ <p>
+
+
+<dt>
+<tt> bool sm_debug_active(SM_DEBUG_T *debug, int level) </tt>
+<dd>
+ This macro returns <tt>true</tt> if the activation level of
+ the statically initialized debug structure <tt>debug</tt>
+ is &gt;= the specified level.
+ The test is performed very efficiently: in the most common case,
+ when the result is <tt>false</tt>, only a single comparison
+ operation is performed.
+ <p>
+ This macro performs a function call only if the debug structure has
+ an unknown activation level. All debug structures are in this state
+ at the beginning of program execution, and after a call to
+ <tt>sm_debug_addsetting</tt>.
+ <p>
+
+
+<dt>
+<tt> int sm_debug_level(SM_DEBUG_T *debug) </tt>
+<dd>
+ This macro returns the activation level of the specified debug structure.
+ The comparison
+<blockquote><pre>
+sm_debug_level(debug) &gt;= level
+</pre></blockquote>
+ is slightly less efficient than, but otherwise semantically
+ equivalent to
+<blockquote><pre>
+sm_debug_active(debug, level)
+</pre></blockquote>
+ <p>
+
+
+<dt>
+<tt> bool sm_debug_unknown(SM_DEBUG_T *debug) </tt>
+<dd>
+ This macro returns true if the activation level of the specified
+ debug structure is unknown.
+ Here is an example of how the macro might be used:
+<blockquote><pre>
+if (sm_debug_unknown(&FooDebug))
+{
+ if (sm_debug_active(&FooDebug, 1))
+ {
+ ... perform some expensive data structure initializations
+ ... in order to enable the "foo" debugging mechanism
+ }
+ else
+ {
+ ... disable the "foo" debugging mechanism
+ }
+}
+</pre></blockquote>
+ The purpose of using <tt>sm_debug_unknown</tt> in the above example
+ is to avoid performing the expensive initializations each time through
+ the code. So it's a performance hack.
+ A debug structure is in the "unknown" state at the beginning of
+ program execution, and after a call to <tt>sm_debug_addsetting</tt>.
+ A side effect of calling <tt>sm_debug_active</tt> is that the
+ activation level becomes known.
+ <p>
+
+
+<dt>
+<tt> void sm_dprintf(char *fmt, ...) </tt>
+<dd>
+ This function is used to print a debug message.
+ The standard idiom is
+<blockquote><pre>
+if (sm_debug_active(&BarDebug, 1))
+ sm_dprintf("bar: about to test tensile strength of bar %d\n", i);
+</pre></blockquote>
+ <p>
+
+<dt>
+<tt> void sm_dflush() </tt>
+<dd>
+ Flush the debug output stream.
+ <p>
+
+<dt>
+<tt> void sm_debug_setfile(SM_FILE_T *file) </tt>
+<dd>
+ This function lets you specify where debug output is printed.
+ By default, debug output is written to standard output.
+ <p>
+ We want to allow you to direct debug output to syslog.
+ The current plan is to provide a standard interface for
+ creating an SM_FILE_T object that writes to syslog.
+
+</dl>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/errstring.c b/gnu/usr.sbin/sendmail/libsm/errstring.c
new file mode 100644
index 00000000000..a836dbaab24
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/errstring.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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("@(#)$Sendmail: errstring.c,v 1.8 2001/08/27 12:59:34 ca Exp $")
+
+#include <errno.h>
+#include <stdio.h> /* sys_errlist, on some platforms */
+
+#include <sm/io.h> /* sm_snprintf */
+#include <sm/string.h>
+#include <sm/errstring.h>
+
+#if NAMED_BIND
+# include <netdb.h>
+#endif
+
+#if LDAPMAP
+# include <lber.h>
+# include <ldap.h> /* for LDAP error codes */
+#endif /* LDAPMAP */
+
+/*
+** SM_ERRSTRING -- return string description of error code
+**
+** Parameters:
+** errnum -- the error number to translate
+**
+** Returns:
+** A string description of errnum.
+*/
+
+const char *
+sm_errstring(errnum)
+ int errnum;
+{
+ switch (errnum)
+ {
+ case EPERM:
+ /* SunOS gives "Not owner" -- this is the POSIX message */
+ return "Operation not permitted";
+
+ /*
+ ** Error messages used internally in sendmail.
+ */
+
+ case E_SM_OPENTIMEOUT:
+ return "Timeout on file open";
+
+ case E_SM_NOSLINK:
+ return "Symbolic links not allowed";
+
+ case E_SM_NOHLINK:
+ return "Hard links not allowed";
+
+ case E_SM_REGONLY:
+ return "Regular files only";
+
+ case E_SM_ISEXEC:
+ return "Executable files not allowed";
+
+ case E_SM_WWDIR:
+ return "World writable directory";
+
+ case E_SM_GWDIR:
+ return "Group writable directory";
+
+ case E_SM_FILECHANGE:
+ return "File changed after open";
+
+ case E_SM_WWFILE:
+ return "World writable file";
+
+ case E_SM_GWFILE:
+ return "Group writable file";
+
+ case E_SM_GRFILE:
+ return "Group readable file";
+
+ case E_SM_WRFILE:
+ return "World readable file";
+
+ /*
+ ** DNS error messages.
+ */
+
+#if NAMED_BIND
+ case HOST_NOT_FOUND + E_DNSBASE:
+ return "Name server: host not found";
+
+ case TRY_AGAIN + E_DNSBASE:
+ return "Name server: host name lookup failure";
+
+ case NO_RECOVERY + E_DNSBASE:
+ return "Name server: non-recoverable error";
+
+ case NO_DATA + E_DNSBASE:
+ return "Name server: no data known";
+#endif /* NAMED_BIND */
+
+ /*
+ ** libsmdb error messages.
+ */
+
+ case SMDBE_MALLOC:
+ return "Memory allocation failed";
+
+ case SMDBE_GDBM_IS_BAD:
+ return "GDBM is not supported";
+
+ case SMDBE_UNSUPPORTED:
+ return "Unsupported action";
+
+ case SMDBE_DUPLICATE:
+ return "Key already exists";
+
+ case SMDBE_BAD_OPEN:
+ return "Database open failed";
+
+ case SMDBE_NOT_FOUND:
+ return "Key not found";
+
+ case SMDBE_UNKNOWN_DB_TYPE:
+ return "Unknown database type";
+
+ case SMDBE_UNSUPPORTED_DB_TYPE:
+ return "Support for database type not compiled into this program";
+
+ case SMDBE_INCOMPLETE:
+ return "DB sync did not finish";
+
+ case SMDBE_KEY_EMPTY:
+ return "Key is empty";
+
+ case SMDBE_KEY_EXIST:
+ return "Key already exists";
+
+ case SMDBE_LOCK_DEADLOCK:
+ return "Locker killed to resolve deadlock";
+
+ case SMDBE_LOCK_NOT_GRANTED:
+ return "Lock unavailable";
+
+ case SMDBE_LOCK_NOT_HELD:
+ return "Lock not held by locker";
+
+ case SMDBE_RUN_RECOVERY:
+ return "Database panic, run recovery";
+
+ case SMDBE_IO_ERROR:
+ return "I/O error";
+
+ case SMDBE_READ_ONLY:
+ return "Database opened read-only";
+
+ case SMDBE_DB_NAME_TOO_LONG:
+ return "Name too long";
+
+ case SMDBE_INVALID_PARAMETER:
+ return "Invalid parameter";
+
+ case SMDBE_ONLY_SUPPORTS_ONE_CURSOR:
+ return "Only one cursor allowed";
+
+ case SMDBE_NOT_A_VALID_CURSOR:
+ return "Invalid cursor";
+
+ case SMDBE_OLD_VERSION:
+ return "Berkeley DB file is an old version, recreate it";
+ }
+
+ /*
+ ** LDAP error messages.
+ */
+
+#if LDAPMAP
+ if (errnum >= E_LDAPBASE)
+ return ldap_err2string(errnum - E_LDAPBASE);
+#endif /* LDAPMAP */
+
+ return strerror(errnum);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/exc.c b/gnu/usr.sbin/sendmail/libsm/exc.c
new file mode 100644
index 00000000000..1ce07f65ad7
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/exc.c
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: exc.c,v 1.43 2001/09/04 22:41:27 ca Exp $")
+
+/*
+** exception handling
+** For documentation, see exc.html
+*/
+
+#include <ctype.h>
+#include <string.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, strerror(err));
+ else
+ sm_io_fprintf(stream, SM_TIME_DEFAULT, "%s failed: %s", syscall,
+ strerror(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.
+*/
+
+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_ADDREF -- Add a reference to an exception object.
+**
+** Parameters:
+** exc -- exception object.
+**
+** Returns:
+** exc itself.
+*/
+
+SM_EXC_T *
+sm_addref(exc)
+ SM_EXC_T *exc;
+{
+ SM_REQUIRE_ISA(exc, SmExcMagic);
+ if (exc->exc_refcount != 0)
+ ++exc->exc_refcount;
+ 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_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
+#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);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/exc.html b/gnu/usr.sbin/sendmail/libsm/exc.html
new file mode 100644
index 00000000000..1b0c779b97b
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/exc.html
@@ -0,0 +1,757 @@
+<html>
+<head>
+ <title>libsm : Exception Handling</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Exception Handling </h1>
+ <br> $Sendmail: exc.html,v 1.12 2001/02/13 21:21:25 gshapiro Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The exception handling package provides the facilities that
+functions in libsm use to report errors.
+Here are the basic concepts:
+
+<ol>
+<li>
+ When a function detects an exceptional condition at the library level,
+ it does not print an error message, or call syslog, or
+ exit the program. Instead, it reports the error back to its
+ caller, and lets the caller decide what to do.
+ This improves modularity, because error handling is separated
+ from error reporting.
+ <p>
+<li>
+ Errors are not represented by a single integer error code,
+ because that you can't represent everything that an error handler
+ might need to know about an error by a single integer.
+ Instead, errors are represented by exception objects.
+ An exception object contains an exception code and an array
+ of zero or more exception arguments.
+ The exception code is a string that specifies what kind of exception
+ this is, and the arguments may be integers, strings or exception objects.
+ <p>
+<li>
+ Errors are not reported using a special return value,
+ because if you religiously check for error returns from every
+ function call that could fail, then most of your code ends up being
+ error handling code. Errors are reported by raising an exception.
+ When an exception is raised, we unwind the call stack
+ until we find an exception handler. If the exception is
+ not handled, then we print the exception on stderr and
+ exit the program.
+</ol>
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/exc.h&gt;
+
+typedef struct sm_exc_type SM_EXC_TYPE_T;
+typedef struct sm_exc SM_EXC_T;
+typedef union sm_val SM_VAL_T;
+
+/*
+** Exception types
+*/
+
+extern const char SmExcTypeMagic[];
+
+struct sm_exc_type
+{
+ const char *sm_magic;
+ const char *etype_category;
+ const char *etype_argformat;
+ void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream);
+ const char *etype_printcontext;
+};
+
+extern const SM_EXC_TYPE_T SmEtypeOs;
+extern const SM_EXC_TYPE_T SmEtypeErr;
+
+void
+sm_etype_printf(
+ SM_EXC_T *exc,
+ SM_FILE_T *stream);
+
+/*
+** Exception objects
+*/
+
+extern const char SmExcMagic[];
+
+union sm_val
+{
+ int v_int;
+ long v_long;
+ char *v_str;
+ SM_EXC_T *v_exc;
+};
+
+struct sm_exc
+{
+ const char *sm_magic;
+ size_t exc_refcount;
+ const SM_EXC_TYPE_T *exc_type;
+ SM_VAL_T *exc_argv;
+};
+
+SM_EXC_T *
+sm_exc_new_x(
+ const SM_EXC_TYPE_T *type,
+ ...);
+
+SM_EXC_T *
+sm_exc_addref(
+ SM_EXC_T *exc);
+
+void
+sm_exc_free(
+ SM_EXC_T *exc);
+
+bool
+sm_exc_match(
+ SM_EXC_T *exc,
+ const char *pattern);
+
+void
+sm_exc_print(
+ SM_EXC_T *exc,
+ SM_FILE_T *stream);
+
+void
+sm_exc_write(
+ SM_EXC_T *exc,
+ SM_FILE_T *stream);
+
+void
+sm_exc_raise_x(
+ SM_EXC_T *exc);
+
+void
+sm_exc_raisenew_x(
+ const SM_EXC_TYPE_T *type,
+ ...);
+
+/*
+** Ensure that cleanup code is executed,
+** and/or handle an exception.
+*/
+SM_TRY
+ Block of code that may raise an exception.
+SM_FINALLY
+ Cleanup code that may raise an exception.
+ This clause is guaranteed to be executed even if an exception is
+ raised by the SM_TRY clause or by an earlier SM_FINALLY clause.
+ You may have 0 or more SM_FINALLY clauses.
+SM_EXCEPT(exc, pattern)
+ Exception handling code, triggered by an exception
+ whose category matches 'pattern'.
+ You may have 0 or more SM_EXCEPT clauses.
+SM_END_TRY
+</pre>
+
+<h2> Overview </h2>
+
+ An exception is an object which represents an exceptional condition,
+ which might be an error condition like "out of memory", or might be
+ a condition like "end of file".
+<p>
+ Functions in libsm report errors and other unusual conditions by
+ raising an exception, rather than by returning an error code or
+ setting a global variable such as errno. If a libsm function is
+ capable of raising an exception, its name ends in "_x".
+ (We do not raise an exception when a bug is detected in the
+ program; instead, we terminate the program using <tt>sm_abort</tt>.
+ See <a href="assert.html">the assertion package</a>
+ for details.)
+<p>
+ When you are using the libsm exception handling package,
+ you are using a new programming paradigm.
+ You will need to abandon some of the programming idioms
+ you are accustomed to, and switch to new idioms.
+ Here is an overview of some of these idioms.
+<ol>
+<li>
+ When a function is unable to complete its task because
+ of an exceptional condition, it reports this condition
+ by raising an exception.
+ <p>
+ Here is an example of how to construct an exception object
+ and raise an exception.
+ In this example, we convert a Unix system error into an exception.
+<blockquote><pre>
+fd = open(path, O_RDONLY);
+if (fd == -1)
+ sm_exc_raise_x(sm_exc_new_x(&SmEtypeOs, errno, "open", "%s", path));
+</pre></blockquote>
+
+ Because the idiom <tt>sm_exc_raise_x(sm_exc_new_x(...))</tt>
+ is so common, it can be abbreviated as <tt>sm_exc_raisenew_x(...)</tt>.
+<p>
+<li>
+ When you detect an error at the application level,
+ you don't call a function like BSD's <tt>errx</tt>,
+ which prints an error message on stderr and exits the program.
+ Instead, you raise an exception.
+ This causes cleanup code in surrounding exception handlers
+ to be run before the program exits.
+ For example, instead of this:
+<blockquote><pre>
+errx(1, "%s:%d: syntax error", filename, lineno);
+</pre></blockquote>
+
+ use this:
+
+<blockquote><pre>
+sm_exc_raisenew_x(&SmEtypeErr, "%s:%d: syntax error", filename, lineno);
+</pre></blockquote>
+
+ The latter code raises an exception, unwinding the call stack
+ and executing cleanup code.
+ If the exception is not handled, then the exception is printed
+ to stderr and the program exits.
+ The end result is substantially the same as a call to <tt>errx</tt>.
+<p>
+<li>
+ The SM_TRY ... SM_FINALLY ... control structure
+ ensures that cleanup code is executed and resources are released
+ in the presence of exceptions.
+<p>
+ For example, suppose that you have written the following code:
+
+<blockquote><pre>
+rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
+... some code ...
+sm_rpool_free_x(rpool);
+</pre></blockquote>
+
+ If any of the functions called within "... some code ..." have
+ names ending in _x, then it is possible that an exception will be
+ raised, and if that happens, then "rpool" will not be freed.
+ And that's a bug. To fix this bug, change your code so it looks
+ like this:
+
+<blockquote><pre>
+rpool = sm_rpool_new_x(&SmRpoolRoot, 0);
+SM_TRY
+ ... some code that can raise an exception ...
+SM_FINALLY
+ sm_rpool_free_x(rpool);
+SM_END_TRY
+</pre></blockquote>
+
+<li>
+ The SM_TRY ... SM_EXCEPT ... control structure handles an exception.
+ Unhandled exceptions terminate the program.
+ For example, here is a simple exception handler
+ that traps all exceptions, and prints the exceptions:
+
+<blockquote><pre>
+SM_TRY
+ /* code that can raise an exception */
+ ...
+SM_EXCEPT(exc, "*")
+ /* catch all exceptions */
+ sm_exc_print(exc, stderr);
+SM_END_TRY
+</pre></blockquote>
+
+ Exceptions are reference counted. The SM_END_TRY macro contains a
+ call to sm_exc_free, so you don't normally need to worry about freeing
+ an exception after handling it. In the rare case that you want an
+ exception to outlive an exception handler, then you increment its
+ reference count by calling sm_exc_addref.
+<p>
+<li>
+ The second argument of the SM_EXCEPT macro is a glob pattern
+ which specifies the types of exceptions that are to be handled.
+ For example, you might want to handle an end-of-file exception
+ differently from other exceptions.
+ Here's how you do that:
+
+<blockquote><pre>
+SM_TRY
+ /* code that might raise end-of-file, or some other exception */
+ ...
+SM_EXCEPT(exc, "E:sm.eof")
+ /* what to do if end-of-file is encountered */
+ ...
+SM_EXCEPT(exc, "*")
+ /* what to do if some other exception is raised */
+ ...
+SM_END_TRY
+</pre></blockquote>
+</ol>
+
+<h2> Exception Values </h2>
+
+In traditional C code, errors are usually denoted by a single integer,
+such as errno. In practice, errno does not carry enough information
+to describe everything that an error handler might want to know about
+an error. And the scheme is not very extensible: if several different
+packages want to add additional error codes, it is hard to avoid
+collisions.
+
+<p>
+In libsm, an exceptional condition is described
+by an object of type SM_EXC_T.
+An exception object is created by specifying an exception type
+and a list of exception arguments.
+
+<p>
+The exception arguments are an array of zero or more values.
+The values may be a mixture of ints, longs, strings, and exceptions.
+In the SM_EXC_T structure, the argument vector is represented
+by <tt>SM_VAL_T&nbsp;*exc_argv</tt>, where <tt>SM_VAL_T</tt>
+is a union of the possible argument types.
+The number and types of exception arguments is determined by
+the exception type.
+
+<p>
+An exception type is a statically initialized const object
+of type SM_EXC_TYPE_T, which has the following members:
+
+<dl>
+<dt>
+<tt> const char *sm_magic </tt>
+<dd>
+ A pointer to <tt>SmExcTypeMagic</tt>.
+ <p>
+<dt>
+<tt> const char *etype_category </tt>
+<dd>
+ This is a string of the form
+ <tt>"</tt><i>class</i><tt>:</tt><i>name</i><tt>"</tt>.
+ <p>
+ The <i>class</i> is used to assign the exception type to
+ one of a number of broad categories of exceptions on which an
+ exception handler might want to discriminate.
+ I suspect that what we want is a hierarchical taxonomy,
+ but I don't have a full design for this yet.
+ For now, I am recommending the following classes:
+ <dl>
+ <dt><tt>"F"</tt>
+ <dd>A fatal error has occurred.
+ This is an error that prevents the application
+ from making any further progress, so the only
+ recourse is to raise an exception, execute cleanup code
+ as the stack is unwound, then exit the application.
+ The out-of-memory exception raised by sm_malloc_x
+ has category "F:sm.heap" because sendmail commits suicide
+ (after logging the error and cleaning up) when it runs out
+ of memory.
+
+ <dt><tt>"E"</tt>
+ <dd>The function could not complete its task because an error occurred.
+ (It might be useful to define subclasses of this category,
+ in which case our taxonony becomes a tree, and 'F' becomes
+ a subclass of 'E'.)
+
+ <dt><tt>"J"</tt>
+ <dd>This exception is being raised in order to effect a
+ non-local jump. No error has occurred; we are just
+ performing the non-local equivalent of a <tt>continue</tt>,
+ <tt>break</tt> or <tt>return</tt>.
+
+ <dt><tt>"S"</tt>
+ <dd>The function was interrupted by a signal.
+ Signals are not errors because they occur asynchronously,
+ and they are semantically unrelated to the function that
+ happens to be executing when the signal arrives.
+ Note that it is extremely dangerous to raise an exception
+ from a signal handler. For example, if you are in the middle
+ of a call to malloc, you might corrupt the heap.
+ </dl>
+ Eric's libsm paper defines <tt>"W"</tt>, <tt>"D"</tt> and <tt>"I"</tt>
+ for Warning, Debug and Informational:
+ I suspect these categories only make sense in the context of
+ Eric's 1985 exception handling system which allowed you to
+ raise conditions without terminating the calling function.
+ <p>
+ The <i>name</i> uniquely identifies the exception type.
+ I recommend a string of the form
+ <i>library</i><tt>.</tt><i>package</i><tt>.</tt><i>detail</i>.
+ <p>
+<dt>
+<tt> const char *etype_argformat </tt>
+<dd>
+ This is an array of single character codes.
+ Each code indicates the type of one of the exception arguments.
+ <tt>sm_exc_new_x</tt> uses this string to decode its variable
+ argument list into an exception argument vector.
+ The following type codes are supported:
+ <dl>
+ <dt><tt>i</tt>
+ <dd>
+ The exception argument has type <tt>int</tt>.
+ <dt><tt>l</tt>
+ <dd>
+ The exception argument has type <tt>long</tt>.
+ <dt><tt>e</tt>
+ <dd>
+ The exception argument has type <tt>SM_EXC_T*</tt>.
+ The value may either be <tt>NULL</tt> or a pointer
+ to an exception. The pointer value is simply copied
+ into the exception argument vector.
+ <dt><tt>s</tt>
+ <dd>
+ The exception argument has type <tt>char*</tt>.
+ The value may either be <tt>NULL</tt> or a pointer
+ to a character string. In the latter case,
+ <tt>sm_exc_new_x</tt> will make a copy of the string.
+ <dt><tt>r</tt>
+ <dd>
+ The exception argument has type <tt>char*</tt>.
+ <tt>sm_exc_new_x</tt> will read a printf-style
+ format string argument followed by a list of printf
+ arguments from its variable argument list, and convert
+ these into a string.
+ This type code can only occur as the last element
+ of <tt>exc_argformat</tt>.
+ </dl>
+ <p>
+<dt>
+<tt> void (*etype_print)(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
+<dd>
+ This function prints an exception of the specified type
+ onto an output stream.
+ The final character printed is not a newline.
+</dl>
+
+<h2> Standard Exceptions and Exception Types </h2>
+
+Libsm defines one standard exception value, <tt>SmHeapOutOfMemory</tt>.
+This is a statically initialized const variable, because it seems
+like a bad idea to dynamically allocate an exception object to
+report a low memory condition.
+This exception has category <tt>"F:sm.heap"</tt>.
+If you need to, you can explicitly raise this exception
+with <tt>sm_exc_raise_x(&SmHeapOutOfMemory)</tt>.
+
+<p>
+Statically initialized exception values cannot contain any
+run-time parameters, so the normal case is to dynamically allocate
+a new exception object whenever you raise an exception.
+Before you can create an exception, you need an exception type.
+Libsm defines the following standard exception types.
+
+<dl>
+<dt>
+<tt> SmEtypeOs </tt>
+<dd>
+ This represents a generic operating system error.
+ The category is <tt>"E:sm.os"</tt>.
+ The argformat is <tt>"isr"</tt>,
+ where argv[0] is the value of <tt>errno</tt>
+ after a system call has failed,
+ argv[1] is the name of the function (usually a system call) that failed,
+ and argv[2] is either <tt>NULL</tt>
+ or a character string which describes some of the arguments
+ to the failing system call (usually it is just a file name).
+ Here's an example of raising an exception:
+
+<blockquote><pre>
+fd = open(filename, O_RDONLY);
+if (fd == -1)
+ sm_exc_raisenew_x(&SmEtypeOs, errno, "open", "%s", filename);
+</pre></blockquote>
+
+ If errno is ENOENT and filename is "/etc/mail/snedmail.cf",
+ then the exception raised by the above code will be printed as
+
+<blockquote><pre>
+/etc/mail/snedmail.cf: open failed: No such file or directory
+</pre></blockquote>
+
+<dt>
+<tt> SmEtypeErr </tt>
+<dd>
+ This represents a generic error.
+ The category is <tt>"E:sm.err"</tt>,
+ and the argformat is <tt>"r"</tt>.
+ You can use it
+ in application contexts where you are raising an exception
+ for the purpose of terminating the program.
+ You know the exception won't be handled,
+ so you don't need to worry about packaging the error for
+ later analysis by an exception handler.
+ All you need to specify is the message string that
+ will be printed to stderr before the program exits.
+ For example,
+
+<blockquote><pre>
+sm_exc_raisenew_x(&SmEtypeErr, "name lookup failed: %s", name);
+</pre></blockquote>
+</dl>
+
+<h2> Custom Exception Types </h2>
+
+If you are writing a library package, and you need to raise
+exceptions that are not standard Unix system errors,
+then you need to define one or more new exception types.
+
+<p>
+Every new exception type needs a print function.
+The standard print function <tt>sm_etype_printf</tt>
+is all you need in the majority of cases.
+It prints the <tt>etype_printcontext</tt> string of the exception type,
+substituting occurrences of %0 through %9 with the corresponding
+exception argument.
+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.
+
+<p>
+In the following example, I will assume that your library
+package implements regular expressions, and can raise 5 different exceptions.
+When compiling a regular expression, 3 different syntax errors
+can be reported:
+<ul>
+<li>unbalanced parenthesis
+<li>unbalanced bracket
+<li>missing argument for repetition operator
+</ul>
+Whenever one of these errors is reported, you will also report
+the index of the character within the regex string at which the
+syntax error was detected.
+The fourth exception is raised if a compiled regular expression
+is invalid: this exception has no arguments.
+The fifth exception is raised if the package runs out of memory:
+for this, you use the standard <tt>SmHeapOutOfMemory</tt> exception.
+
+<p>
+The obvious approach is to define 4 separate exception types.
+Here they are:
+
+<blockquote><pre>
+/* print a regular expression syntax error */
+void
+rx_esyntax_print(SM_EXC_T *exc, SM_FILE_T *stream)
+{
+ sm_io_fprintf(stream, "rx syntax error at character %d: %s",
+ exc-&gt;exc_argv[0].v_int,
+ exc-&gt;exc_type-&gt;etype_printcontext);
+}
+SM_EXC_TYPE_T RxSyntaxParen = {
+ SmExcTypeMagic,
+ "E:mylib.rx.syntax.paren",
+ "i",
+ rx_esyntax_print,
+ "unbalanced parenthesis"
+};
+SM_EXC_TYPE_T RxSyntaxBracket = {
+ SmExcTypeMagic,
+ "E:mylib.rx.syntax.bracket",
+ "i",
+ rx_esyntax_print,
+ "unbalanced bracket"
+};
+SM_EXC_TYPE_T RxSyntaxMissingArg = {
+ SmExcTypeMagic,
+ "E:mylib.rx.syntax.missingarg",
+ "i",
+ rx_esyntax_print,
+ "missing argument for repetition operator"
+};
+
+SM_EXC_TYPE_T RxRunCorrupt = {
+ SmExcTypeMagic,
+ "E:mylib.rx.run.corrupt",
+ "",
+ sm_etype_printf,
+ "rx runtime error: compiled regular expression is corrupt"
+};
+</pre></blockquote>
+
+<p>
+With the above definitions, you can raise a syntax error reporting
+an unbalanced parenthesis at string offset <tt>i</tt> using:
+<blockquote><pre>
+sm_exc_raisenew_x(&RxSyntaxParen, i);
+</pre></blockquote>
+
+If <tt>i==42</tt> then this exception will be printed as:
+<blockquote><pre>
+rx syntax error at character 42: unbalanced parenthesis
+</pre></blockquote>
+
+An exception handler can provide special handling for regular
+expression syntax errors using this code:
+<blockquote><pre>
+SM_TRY
+ ... code that might raise an exception ...
+SM_EXCEPT(exc, "E:mylib.rx.syntax.*")
+ int i = exc-&gt;exc_argv[0].v_int;
+ ... handle a regular expression syntax error ...
+SM_END_TRY
+</pre></blockquote>
+
+<p>
+External requirements may force you to define an integer code
+for each error reported by your package. Or you may be wrapping
+an existing package that works this way. In this case, it might
+make sense to define a single exception type, patterned after SmEtypeOs,
+and include the integer code as an exception argument.
+
+<p>
+Your package might intercept an exception E generated by a lower
+level package, and then reclassify it as a different expression E'.
+For example, a package for reading a configuration file might
+reclassify one of the regular expression syntax errors from the
+previous example as a configuration file syntax error.
+When you do this, the new exception E' should include the original
+exception E as an exception parameter, and the print function for
+exception E' should print the high level description of the exception
+(eg, "syntax error in configuration file %s at line %d\n"),
+then print the subexception that is stored as an exception parameter.
+
+<h2> Function Reference </h2>
+
+<dl>
+<dt>
+<tt> SM_EXC_T *sm_exc_new_x(const SM_EXC_TYPE_T *type, ...) </tt>
+<dd>
+ Create a new exception. Raise an exception on heap exhaustion.
+ The new exception has a reference count of 1.
+ <p>
+
+ A list of zero or more exception arguments follows the exception type;
+ these are copied into the new exception object.
+ The number and types of these arguments is determined
+ by <tt>type-&gt;etype_argformat</tt>.
+ <p>
+
+ Note that there is no rpool argument to sm_exc_new_x.
+ Exceptions are allocated directly from the heap.
+ This is because exceptions are normally raised at low levels
+ of abstraction and handled at high levels. Because the low
+ level code typically has no idea of how or at what level the
+ exception will be handled, it also has no idea of which resource
+ pool, if any, should own the exception.
+ <p>
+<dt>
+<tt> SM_EXC_T *sm_exc_addref(SM_EXC_T *exc) </tt>
+<dd>
+ Increment the reference count of an exception.
+ Return the first argument.
+ <p>
+<dt>
+<tt> void sm_exc_free(SM_EXC_T *exc) </tt>
+<dd>
+ Decrement the reference count of an exception.
+ If it reaches 0, free the exception object.
+ <p>
+<dt>
+<tt> bool sm_exc_match(SM_EXC_T *exc, const char *pattern) </tt>
+<dd>
+ Compare the exception's category to the specified glob pattern,
+ return true if they match.
+ <p>
+<dt>
+<tt> void sm_exc_print(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
+<dd>
+ Print the exception on the stream
+ as a sequence of one or more newline terminated lines.
+ <p>
+<dt>
+<tt> void sm_exc_write(SM_EXC_T *exc, SM_FILE_T *stream) </tt>
+<dd>
+ Write the exception on the stream without a terminating newline.
+ <p>
+<dt>
+<tt> void sm_exc_raise_x(SM_EXC_T *exc) </tt>
+<dd>
+ Raise the exception. This function does not return to its caller.
+ <p>
+<dt>
+<tt> void sm_exc_raisenew_x(const SM_EXC_TYPE_T *type, ...) </tt>
+<dd>
+ A short form for <tt>sm_exc_raise_x(sm_exc_new_x(type,...))</tt>.
+</dl>
+
+<h2> Macro Reference </h2>
+
+The SM_TRY ... SM_END_TRY control structure
+ensures that cleanup code is executed in the presence of exceptions,
+and permits exceptions to be handled.
+
+<blockquote><pre>
+SM_TRY
+ A block of code that may raise an exception.
+SM_FINALLY
+ Cleanup code that may raise an exception.
+ This code is guaranteed to be executed whether or not
+ an exception was raised by a previous clause.
+ You may have 0 or more SM_FINALLY clauses.
+SM_EXCEPT(e, pat)
+ Exception handling code, which is triggered by an exception
+ whose category matches the glob pattern 'pat'.
+ The exception value is bound to the local variable 'e'.
+ You may have 0 or more SM_EXCEPT clauses.
+SM_END_TRY
+</pre></blockquote>
+
+First, the SM_TRY clause is executed, then each SM_FINALLY clause is
+executed in sequence.
+If one or more of these clauses was terminated by an exception,
+then the first such exception is remembered, and the other exceptions
+are lost.
+
+If no exception was raised, then we are done.
+
+Otherwise, each of the SM_EXCEPT clauses is examined in sequence.
+and the first SM_EXCEPT clause whose pattern argument matches the exception
+(see <tt>sm_exc_match</tt>) is executed.
+If none of the SM_EXCEPT clauses matched the exception, or if there are
+no SM_EXCEPT clauses, then the remembered exception is re-raised.
+
+<p>
+SM_TRY .. SM_END_TRY clauses may be nested arbitrarily.
+
+<p>
+It is illegal to jump out of a SM_TRY or SM_FINALLY clause
+using goto, break, continue, return or longjmp.
+If you do this, you will corrupt the internal exception handling stack.
+You can't use <tt>break</tt> or <tt>continue</tt> in an SM_EXCEPT clause;
+these are reserved for use by the implementation.
+It is legal to jump out of an SM_EXCEPT clause using goto or return;
+however, in this case, you must take responsibility
+for freeing the exception object.
+
+<p>
+The SM_TRY and SM_FINALLY macros contain calls to setjmp,
+and consequently, they suffer from the limitations imposed on setjmp
+by the C standard.
+Suppose you declare an auto variable <tt>i</tt> outside of a
+SM_TRY ... SM_END_TRY statement, initializing it to 0.
+Then you modify <tt>i</tt> inside of a SM_TRY or SM_FINALLY clause,
+setting it to 1.
+If you reference <tt>i</tt> in a different SM_FINALLY clause, or in
+an SM_EXCEPT clause, then it is implementation dependent whether <tt>i</tt>
+will be 0 or 1, unless you have declared <tt>i</tt> to be <tt>volatile</tt>.
+
+<blockquote><pre>
+int volatile i = 0;
+
+SM_TRY
+ i = 1;
+ ...
+SM_FINALLY
+ /* the following reference to i only works if i is declared volatile */
+ use(i);
+ ...
+SM_EXCEPT(exc, "*")
+ /* the following reference to i only works if i is declared volatile */
+ use(i);
+ ...
+SM_END_TRY
+</pre></blockquote>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/fclose.c b/gnu/usr.sbin/sendmail/libsm/fclose.c
new file mode 100644
index 00000000000..7fb8785af70
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fclose.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fclose.c,v 1.39 2001/06/06 00:25:48 ca Exp $")
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <setjmp.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/heap.h>
+#include <sm/signal.h>
+#include <sm/conf.h>
+#include <sm/clock.h>
+#include "local.h"
+
+static jmp_buf CloseTimeOut;
+
+/*
+** CLOSEALRM -- handler when timeout activated for sm_io_close()
+**
+** Returns flow of control to where setjmp(CloseTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(CloseTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+closealrm(sig)
+ int sig;
+{
+ longjmp(CloseTimeOut, 1);
+}
+
+/*
+** SM_IO_CLOSE -- close a file handle/pointer
+**
+** Parameters:
+** fp -- file pointer to be closed
+** timeout -- maximum time allowed to perform the close (millisecs)
+**
+** Returns:
+** 0 on success
+** -1 on failure and sets errno
+**
+** Side Effects:
+** file pointer 'fp' will no longer be valid.
+*/
+
+int
+sm_io_close(fp, timeout)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+{
+ register int SM_NONVOLATILE r;
+ SM_EVENT *evt = NULL;
+
+ if (fp == NULL)
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if (fp->sm_magic == NULL)
+ {
+ /* not open! */
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ if (fp->f_close == NULL)
+ {
+ /* no close function! */
+ errno = ENODEV;
+ return SM_IO_EOF;
+ }
+ if (fp->f_dup_cnt > 0)
+ {
+ /* decrement file pointer open count */
+ fp->f_dup_cnt--;
+ return 0;
+ }
+
+ /* Okay, this is where we set the timeout. */
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ /* No more duplicates of file pointer. Flush buffer and close */
+ r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0;
+
+ /* sm_flush() has updated to.it_value for the time it's used */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(CloseTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+ evt = sm_seteventm(timeout, closealrm, 0);
+ }
+ if ((*fp->f_close)(fp) < 0)
+ r = SM_IO_EOF;
+
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+ if (fp->f_flags & SMMBF)
+ {
+ sm_free((char *)fp->f_bf.smb_base);
+ fp->f_bf.smb_base = NULL;
+ }
+ if (HASUB(fp))
+ FREEUB(fp);
+ if (HASLB(fp))
+ FREELB(fp);
+ fp->f_flags = 0; /* clear flags */
+ fp->sm_magic = NULL; /* Release this SM_FILE_T for reuse. */
+ fp->f_r = fp->f_w = 0; /* Mess up if reaccessed. */
+ return r;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/feof.c b/gnu/usr.sbin/sendmail/libsm/feof.c
new file mode 100644
index 00000000000..487dc07a6e7
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/feof.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: feof.c,v 1.11 2001/04/03 01:46:40 ca Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_EOF -- subroutine version of the macro sm_io_eof.
+**
+** Tests if the file for 'fp' has reached the end.
+**
+** Parameters:
+** fp -- file pointer.
+**
+** Returns:
+** 0 (zero) when the file is not at end
+** non-zero when EOF has been found
+*/
+#undef sm_io_eof
+
+int
+sm_io_eof(fp)
+ SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ return sm_eof(fp);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/ferror.c b/gnu/usr.sbin/sendmail/libsm/ferror.c
new file mode 100644
index 00000000000..94e9adc84ce
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/ferror.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: ferror.c,v 1.11 2001/04/03 01:46:40 ca Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_ERROR -- subroutine version of the macro sm_io_error.
+**
+** Parameters:
+** fp -- file pointer
+**
+** Returns:
+** 0 (zero) when 'fp' is not in an error state
+** non-zero when 'fp' is in an error state
+*/
+
+#undef sm_io_error
+
+int
+sm_io_error(fp)
+ SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ return sm_error(fp);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fflush.c b/gnu/usr.sbin/sendmail/libsm/fflush.c
new file mode 100644
index 00000000000..a65a8ec2307
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fflush.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fflush.c,v 1.41 2001/05/15 16:55:27 ca Exp $")
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/setjmp.h>
+#include "local.h"
+#include <sm/conf.h>
+
+/*
+** SM_IO_FLUSH -- flush the buffer for a 'fp' to the "file"
+**
+** Flush a single file. We don't allow this function to flush
+** all open files when fp==NULL any longer.
+**
+** Parameters:
+** fp -- the file pointer buffer to flush
+** timeout -- time to complete the flush
+**
+** Results:
+** Failure: SM_IO_EOF and sets errno
+** Success: 0 (zero)
+*/
+
+int
+sm_io_flush(fp, timeout)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+{
+ int fd;
+ struct timeval to;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if ((fp->f_flags & (SMWR | SMRW)) == 0)
+ {
+ /*
+ ** The file is not opened for writing, so it cannot be flushed
+ ** (writable means SMWR [write] or SMRW [read/write].
+ */
+
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ /* Now do the flush */
+ return sm_flush(fp, (int *) &timeout);
+}
+
+/*
+** SM_FLUSH -- perform the actual flush
+**
+** Assumes that 'fp' has been validated before this function called.
+**
+** Parameters:
+** fp -- file pointer to be flushed
+** timeout -- max time allowed for flush (milliseconds)
+**
+** Results:
+** Success: 0 (zero)
+** Failure: SM_IO_EOF and errno set
+**
+** Side Effects:
+** timeout will get updated with the time remaining (if any)
+*/
+
+int
+sm_flush(fp, timeout)
+ register SM_FILE_T *fp;
+ int *timeout;
+{
+ register unsigned char *p;
+ register int n, t;
+ int fd;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ t = fp->f_flags;
+ if ((t & SMWR) == 0)
+ return 0;
+
+ if (t & SMSTR)
+ {
+ *fp->f_p = '\0';
+ return 0;
+ }
+
+ if ((p = fp->f_bf.smb_base) == NULL)
+ return 0;
+
+ n = fp->f_p - p; /* write this much */
+
+ if ((fd = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1)
+ {
+ /* can't get an fd, likely internal 'fake' fp */
+ errno = 0;
+ fd = -1;
+ }
+
+ /*
+ ** Set these immediately to avoid problems with longjmp and to allow
+ ** exchange buffering (via setvbuf) in user write function.
+ */
+
+ fp->f_p = p;
+ fp->f_w = t & (SMLBF|SMNBF) ? 0 : fp->f_bf.smb_size; /* implies SMFBF */
+
+ for (; n > 0; n -= t, p += t)
+ {
+ errno = 0; /* needed to ensure EOF correctly found */
+
+ /* Call the file type's write function */
+ t = (*fp->f_write)(fp, (char *)p, n);
+ if (t <= 0)
+ {
+ if (t == 0 && errno == 0)
+ break; /* EOF found */
+
+ if (IS_IO_ERROR(fd, t, *timeout))
+ {
+ fp->f_flags |= SMERR;
+
+ /* errno set by fp->f_write */
+ return SM_IO_EOF;
+ }
+ SM_IO_WR_TIMEOUT(fp, fd, *timeout);
+ }
+ }
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fget.c b/gnu/usr.sbin/sendmail/libsm/fget.c
new file mode 100644
index 00000000000..de77a4ae03d
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fget.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fget.c,v 1.22 2001/08/27 18:54:14 gshapiro Exp $")
+#include <stdlib.h>
+#include <string.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_FGETS -- get a string from a file
+**
+** Read at most n-1 characters from the given file.
+** Stop when a newline has been read, or the count ('n') runs out.
+**
+** Parameters:
+** fp -- the file to read from
+** timeout -- time to complete reading the string in milliseconds
+** buf -- buffer to place read string in
+** n -- size of 'buf'
+**
+** Returns:
+** success: returns value of 'buf'
+** failure: NULL (no characters were read)
+** timeout: NULL and errno set to EAGAIN
+**
+** Side Effects:
+** may move the file pointer
+*/
+
+char *
+sm_io_fgets(fp, timeout, buf, n)
+ register SM_FILE_T *fp;
+ int timeout;
+ char *buf;
+ register int n;
+{
+ register int len;
+ register char *s;
+ register unsigned char *p, *t;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (n <= 0) /* sanity check */
+ return NULL;
+
+ s = buf;
+ n--; /* leave space for NUL */
+ while (n > 0)
+ {
+ /* If the buffer is empty, refill it. */
+ if ((len = fp->f_r) <= 0)
+ {
+
+ /*
+ ** Timeout is only passed if we can't get the data
+ ** from the buffer (which is counted as immediately).
+ */
+
+ if (sm_refill(fp, timeout) != 0)
+ {
+ /* EOF/error: stop with partial or no line */
+ if (s == buf)
+ return NULL;
+ break;
+ }
+ len = fp->f_r;
+ }
+ p = fp->f_p;
+
+ /*
+ ** Scan through at most n bytes of the current buffer,
+ ** looking for '\n'. If found, copy up to and including
+ ** newline, and stop. Otherwise, copy entire chunk
+ ** and loop.
+ */
+
+ if (len > n)
+ len = n;
+ t = (unsigned char *) memchr((void *) p, '\n', len);
+ if (t != NULL)
+ {
+ len = ++t - p;
+ fp->f_r -= len;
+ fp->f_p = t;
+ (void) memcpy((void *) s, (void *) p, len);
+ s[len] = 0;
+ return buf;
+ }
+ fp->f_r -= len;
+ fp->f_p += len;
+ (void) memcpy((void *) s, (void *) p, len);
+ s += len;
+ n -= len;
+ }
+ *s = 0;
+ return buf;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/findfp.c b/gnu/usr.sbin/sendmail/libsm/findfp.c
new file mode 100644
index 00000000000..01aacacc823
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/findfp.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: findfp.c,v 1.58 2001/08/31 21:02:50 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "glue.h"
+
+bool Sm_IO_DidInit; /* IO system has been initialized? */
+
+const char SmFileMagic[] = "sm_file";
+
+/* An open type to map to fopen()-like behavior */
+SM_FILE_T SmFtStdio_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
+ sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
+ sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "stdio" };
+
+/* An open type to map to fdopen()-like behavior */
+SM_FILE_T SmFtStdiofd_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMFBF), -1, {0, 0}, 0, 0, 0,
+ sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite,
+ sm_stdfdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "stdiofd" };
+
+/* A string file type */
+SM_FILE_T _SmFtString_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
+ sm_strclose, sm_strread, sm_strseek, sm_strwrite,
+ sm_stropen, sm_strsetinfo, sm_strgetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "string" };
+
+#if 0
+/* A file type for syslog communications */
+SM_FILE_T SmFtSyslog_def =
+ {SmFileMagic, 0, 0, 0, (SMRW|SMNBF), -1, {0, 0}, 0, 0, 0,
+ sm_syslogclose, sm_syslogread, sm_syslogseek, sm_syslogwrite,
+ sm_syslogopen, sm_syslogsetinfo, sm_sysloggetinfo, SM_TIME_FOREVER,
+ SM_TIME_BLOCK, "syslog" };
+#endif /* 0 */
+
+#define NDYNAMIC 10 /* add ten more whenever necessary */
+
+#define smio(flags, file, name) \
+ {SmFileMagic, 0, 0, 0, flags, file, {0}, 0, SmIoF+file, 0, \
+ sm_stdclose, sm_stdread, sm_stdseek, sm_stdwrite, \
+ sm_stdopen, sm_stdsetinfo, sm_stdgetinfo, SM_TIME_FOREVER, \
+ SM_TIME_BLOCK, name}
+
+/* sm_magic p r w flags file bf lbfsize cookie ival */
+#define smstd(flags, file, name) \
+ {SmFileMagic, 0, 0, 0, flags, -1, {0}, 0, 0, file, \
+ sm_stdioclose, sm_stdioread, sm_stdioseek, sm_stdiowrite, \
+ sm_stdioopen, sm_stdiosetinfo, sm_stdiogetinfo, SM_TIME_FOREVER,\
+ SM_TIME_BLOCK, name}
+
+/* A file type for interfacing to stdio FILE* streams. */
+SM_FILE_T SmFtRealStdio_def = smstd(SMRW|SMNBF, -1, "realstdio");
+
+ /* the usual - (stdin + stdout + stderr) */
+static SM_FILE_T usual[SM_IO_OPEN_MAX - 3];
+static struct sm_glue smuglue = { 0, SM_IO_OPEN_MAX - 3, usual };
+
+/* List of builtin automagically already open file pointers */
+SM_FILE_T SmIoF[6] =
+{
+ smio(SMRD|SMLBF, SMIOIN_FILENO, "smioin"), /* smioin */
+ smio(SMWR|SMLBF, SMIOOUT_FILENO, "smioout"), /* smioout */
+ smio(SMWR|SMNBF, SMIOERR_FILENO, "smioerr"), /* smioerr */
+ smstd(SMRD|SMNBF, SMIOIN_FILENO, "smiostdin"), /* smiostdin */
+ smstd(SMWR|SMNBF, SMIOOUT_FILENO, "smiostdout"),/* smiostdout */
+ smstd(SMWR|SMNBF, SMIOERR_FILENO, "smiostderr") /* smiostderr */
+};
+
+/* Structure containing list of currently open file pointers */
+struct sm_glue smglue = { &smuglue, 3, SmIoF };
+
+/*
+** SM_MOREGLUE -- adds more space for open file pointers
+**
+** Parameters:
+** n -- number of new spaces for file pointers
+**
+** Returns:
+** Raises an exception if no more memory.
+** Otherwise, returns a pointer to new spaces.
+*/
+
+static struct sm_glue *sm_moreglue_x __P((int));
+
+static struct sm_glue *
+sm_moreglue_x(n)
+ register int n;
+{
+ register struct sm_glue *g;
+ register SM_FILE_T *p;
+ static SM_FILE_T empty;
+
+ g = (struct sm_glue *) sm_pmalloc_x(sizeof(*g) + ALIGNBYTES +
+ n * sizeof(SM_FILE_T));
+ p = (SM_FILE_T *) ALIGN(g + 1);
+ g->gl_next = NULL;
+ g->gl_niobs = n;
+ g->gl_iobs = p;
+ while (--n >= 0)
+ {
+ *p++ = empty;
+ p->f_type = NULL;
+ p->sm_magic = NULL;
+ }
+ return g;
+}
+
+/*
+** SM_FP -- allocate and initialize an SM_FILE structure
+**
+** Parameters:
+** t -- file type requested to be opened.
+** flags -- control flags for file type behavior
+** oldfp -- file pointer to reuse if available (optional)
+**
+** Returns:
+** Raises exception on memory exhaustion.
+** Aborts if type is invalid.
+** Otherwise, returns file pointer for requested file type.
+*/
+
+SM_FILE_T *
+sm_fp(t, flags, oldfp)
+ const SM_FILE_T *t;
+ const int flags;
+ SM_FILE_T *oldfp;
+{
+ register SM_FILE_T *fp;
+ register int n;
+ register struct sm_glue *g;
+
+ SM_REQUIRE(t->f_open && t->f_close && (t->f_read || t->f_write));
+
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ if (oldfp != NULL)
+ {
+ fp = oldfp;
+ goto found; /* for opening reusing an 'fp' */
+ }
+
+ for (g = &smglue;; g = g->gl_next)
+ {
+ for (fp = g->gl_iobs, n = g->gl_niobs; --n >= 0; fp++)
+ if (fp->sm_magic == NULL)
+ goto found;
+ if (g->gl_next == NULL)
+ g->gl_next = sm_moreglue_x(NDYNAMIC);
+ }
+found:
+ fp->sm_magic = SmFileMagic; /* 'fp' now valid and in-use */
+ fp->f_p = NULL; /* no current pointer */
+ fp->f_w = 0; /* nothing to write */
+ fp->f_r = 0; /* nothing to read */
+ fp->f_flags = flags;
+ fp->f_file = -1; /* no file */
+ fp->f_bf.smb_base = NULL; /* no buffer */
+ fp->f_bf.smb_size = 0; /* no buffer size with no buffer */
+ fp->f_lbfsize = 0; /* not line buffered */
+ fp->f_flushfp = NULL; /* no associated flush file */
+
+ fp->f_cookie = fp; /* default: *open* overrides cookie setting */
+ fp->f_close = t->f_close; /* assign close function */
+ fp->f_read = t->f_read; /* assign read function */
+ fp->f_seek = t->f_seek; /* assign seek function */
+ fp->f_write = t->f_write; /* assign write function */
+ fp->f_open = t->f_open; /* assign open function */
+ fp->f_setinfo = t->f_setinfo; /* assign setinfo function */
+ fp->f_getinfo = t->f_getinfo; /* assign getinfo function */
+ fp->f_type = t->f_type; /* file type */
+ fp->f_self = fp; /* self reference for future use */
+
+ fp->f_ub.smb_base = NULL; /* no ungetc buffer */
+ fp->f_ub.smb_size = 0; /* no size for no ungetc buffer */
+
+ fp->f_lb.smb_base = NULL; /* no line buffer */
+ fp->f_lb.smb_size = 0; /* no size for no line buffer */
+ if (fp->f_timeout == SM_TIME_DEFAULT)
+ fp->f_timeout = SM_TIME_FOREVER;
+ else
+ fp->f_timeout = t->f_timeout; /* traditional behavior */
+ fp->f_timeoutstate = SM_TIME_BLOCK; /* by default */
+
+ return fp;
+}
+
+/*
+** SM_CLEANUP -- cleanup function when exit called.
+**
+** This function is registered via atexit().
+**
+** Parameters:
+** none
+**
+** Returns:
+** nothing.
+**
+** Side Effects:
+** flushes open files before they are forced closed
+*/
+
+void
+sm_cleanup()
+{
+ int timeout = SM_TIME_DEFAULT;
+
+ (void) sm_fwalk(sm_flush, &timeout); /* `cheating' */
+}
+
+/*
+** SM_INIT -- called whenever sm_io's internal variables must be set up.
+**
+** Parameters:
+** none
+**
+** Returns:
+** none
+**
+** Side Effects:
+** Registers sm_cleanup() using atexit().
+*/
+
+void
+sm_init()
+{
+ if (Sm_IO_DidInit) /* paranoia */
+ return;
+
+ /* make sure we clean up on exit */
+ atexit(sm_cleanup); /* conservative */
+ Sm_IO_DidInit = true;
+}
+
+/*
+** SM_IO_SETINFO -- change info for an open file type (fp)
+**
+** The generic SM_IO_WHAT_VECTORS is auto supplied for all file types.
+** If the request is to set info other than SM_IO_WHAT_VECTORS then
+** the request is passed on to the file type's specific setinfo vector.
+** WARNING: this is working on an active/open file type.
+**
+** Parameters:
+** fp -- file to make the setting on
+** what -- type of information to set
+** valp -- structure to obtain info from
+**
+** Returns:
+** 0 on success
+** -1 on error and sets errno:
+** - when what != SM_IO_WHAT_VECTORS and setinfo vector
+** not set
+** - when vectored setinfo returns -1
+*/
+
+int
+sm_io_setinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ SM_FILE_T *v = (SM_FILE_T *) valp;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ switch (what)
+ {
+ case SM_IO_WHAT_VECTORS:
+
+ /*
+ ** This is the "generic" available for all.
+ ** This allows the function vectors to be replaced
+ ** while the file type is active.
+ */
+
+ fp->f_close = v->f_close;
+ fp->f_read = v->f_read;
+ fp->f_seek = v->f_seek;
+ fp->f_write = v->f_write;
+ fp->f_open = v->f_open;
+ fp->f_setinfo = v->f_setinfo;
+ fp->f_getinfo = v->f_getinfo;
+ sm_free(fp->f_type);
+ fp->f_type = sm_strdup_x(v->f_type);
+ return 0;
+ case SM_IO_WHAT_TIMEOUT:
+ fp->f_timeout = *((int *)valp);
+ return 0;
+ }
+
+ /* Otherwise the vector will check it out */
+ if (fp->f_setinfo == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ else
+ return (*fp->f_setinfo)(fp, what, valp);
+}
+
+/*
+** SM_IO_GETINFO -- get information for an active file type (fp)
+**
+** This function supplies for all file types the answers for the
+** three requests SM_IO_WHAT_VECTORS, SM_IO_WHAT_TYPE and
+** SM_IO_WHAT_ISTYPE. Other requests are handled by the getinfo
+** vector if available for the open file type.
+** SM_IO_WHAT_VECTORS returns information for the file pointer vectors.
+** SM_IO_WHAT_TYPE returns the type identifier for the file pointer
+** SM_IO_WHAT_ISTYPE returns >0 if the passed in type matches the
+** file pointer's type.
+** SM_IO_IS_READABLE returns 1 if there is data available for reading,
+** 0 otherwise.
+**
+** Parameters:
+** fp -- file pointer for active file type
+** what -- type of information request
+** valp -- structure to place obtained info into
+**
+** Returns:
+** -1 on error and sets errno:
+** - when valp==NULL and request expects otherwise
+** - when request is not SM_IO_WHAT_VECTORS and not
+** SM_IO_WHAT_TYPE and not SM_IO_WHAT_ISTYPE
+** and getinfo vector is NULL
+** - when getinfo type vector returns -1
+** >=0 on success
+*/
+
+int
+sm_io_getinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ SM_FILE_T *v = (SM_FILE_T *) valp;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ switch (what)
+ {
+ case SM_IO_WHAT_VECTORS:
+
+ /* This is the "generic" available for all */
+ v->f_close = fp->f_close;
+ v->f_read = fp->f_read;
+ v->f_seek = fp->f_seek;
+ v->f_write = fp->f_write;
+ v->f_open = fp->f_open;
+ v->f_setinfo = fp->f_setinfo;
+ v->f_getinfo = fp->f_getinfo;
+ v->f_type = fp->f_type;
+ return 0;
+
+ case SM_IO_WHAT_TYPE:
+ if (valp == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ valp = sm_strdup_x(fp->f_type);
+ return 0;
+
+ case SM_IO_WHAT_ISTYPE:
+ if (valp == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return strcmp(fp->f_type, valp) == 0;
+
+ case SM_IO_IS_READABLE:
+
+ /* if there is data in the buffer, it must be readable */
+ if (fp->f_r > 0)
+ return 1;
+
+ /* otherwise query the underlying file */
+ break;
+
+ case SM_IO_WHAT_TIMEOUT:
+ *((int *) valp) = fp->f_timeout;
+ return 0;
+
+ case SM_IO_WHAT_FD:
+ if (fp->f_file > -1)
+ return fp->f_file;
+
+ /* try the file type specific getinfo to see if it knows */
+ break;
+ }
+
+ /* Otherwise the vector will check it out */
+ if (fp->f_getinfo == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return (*fp->f_getinfo)(fp, what, valp);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/flags.c b/gnu/usr.sbin/sendmail/libsm/flags.c
new file mode 100644
index 00000000000..54f9863913c
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/flags.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: flags.c,v 1.18 2001/04/03 01:46:40 ca Exp $")
+#include <sys/types.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <sm/io.h>
+
+/*
+** SM_FLAGS -- translate external (user) flags into internal flags
+**
+** Paramters:
+** flags -- user select flags
+**
+** Returns:
+** Internal flag value matching user selected flags
+*/
+
+int
+sm_flags(flags)
+ register int flags;
+{
+ register int ret;
+
+ switch(flags)
+ {
+ case SM_IO_RDONLY: /* open for reading */
+ ret = SMRD;
+ break;
+
+ case SM_IO_WRONLY: /* open for writing */
+ ret = SMWR;
+ break;
+
+ case SM_IO_APPEND: /* open for appending */
+ ret = SMWR;
+ break;
+
+ case SM_IO_RDWR: /* open for read and write */
+ ret = SMRW;
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fopen.c b/gnu/usr.sbin/sendmail/libsm/fopen.c
new file mode 100644
index 00000000000..081ff7aead2
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fopen.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fopen.c,v 1.55 2001/08/27 18:38:17 gshapiro Exp $")
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/heap.h>
+#include <sm/signal.h>
+#include <sm/assert.h>
+#include <sm/io.h>
+#include <sm/clock.h>
+#include "local.h"
+
+extern int sm_io_fclose __P((SM_FILE_T *));
+
+static jmp_buf OpenTimeOut, ReopenTimeOut;
+
+/*
+** OPENALRM -- handler when timeout activated for sm_io_open()
+**
+** Returns flow of control to where setjmp(OpenTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(OpenTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+openalrm(sig)
+ int sig;
+{
+ longjmp(OpenTimeOut, 1);
+}
+ /*
+** REOPENALRM -- handler when timeout activated for sm_io_reopen()
+**
+** Returns flow of control to where setjmp(ReopenTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(ReopenTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+reopenalrm(sig)
+ int sig;
+{
+ longjmp(ReopenTimeOut, 1);
+}
+
+/*
+** SM_IO_OPEN -- open a file of a specific type
+**
+** Parameters:
+** type -- type of file to open
+** timeout -- time to complete the open
+** info -- info describing what is to be opened (type dependant)
+** flags -- user selected flags
+** rpool -- pointer to rpool to be used for this open
+**
+** Returns:
+** Raises exception on heap exhaustion.
+** Aborts if type is invalid.
+** Returns NULL and sets errno
+** - when the type specific open fails
+** - when open vector errors
+** - when flags not set or invalid
+** Success returns a file pointer to the opened file type.
+*/
+
+SM_FILE_T *
+sm_io_open(type, timeout, info, flags, rpool)
+ const SM_FILE_T *type;
+ int SM_NONVOLATILE timeout; /* this is not the file type timeout */
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ register SM_FILE_T *fp;
+ int ioflags;
+ SM_EVENT *evt = NULL;
+
+ ioflags = sm_flags(flags);
+
+ if (ioflags == 0)
+ {
+ errno = EINVAL;
+ return NULL; /* must give some indication/intent */
+ }
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = SM_TIME_FOREVER;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ errno = EAGAIN;
+ return NULL;
+ }
+
+ fp = sm_fp(type, ioflags, NULL);
+
+ /* Okay, this is where we set the timeout. */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(OpenTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return NULL;
+ }
+ evt = sm_seteventm(timeout, openalrm, 0);
+ }
+
+ if ((*fp->f_open)(fp, info, flags, rpool) < 0)
+ {
+ fp->f_flags = 0; /* release */
+ fp->sm_magic = NULL; /* release */
+ return NULL;
+ }
+
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+
+#if SM_RPOOL
+ if (rpool != NULL)
+ sm_rpool_attach_x(rpool, sm_io_fclose, fp);
+#endif /* SM_RPOOL */
+
+ return fp;
+}
+ /*
+** SM_IO_DUP -- duplicate a file pointer
+**
+** Parameters:
+** fp -- file pointer to duplicate
+**
+** Returns:
+** Success - the duplicated file pointer
+** Failure - NULL (was an invalid file pointer or too many open)
+**
+** Increments the duplicate counter (dup_cnt) for the open file pointer.
+** The counter counts the number of duplicates. When the duplicate
+** counter is 0 (zero) then the file pointer is the only one left
+** (no duplicates, it is the only one).
+*/
+
+SM_FILE_T *
+sm_io_dup(fp)
+ SM_FILE_T *fp;
+{
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (fp->sm_magic != SmFileMagic)
+ {
+ errno = EBADF;
+ return NULL;
+ }
+ if (fp->f_dup_cnt >= INT_MAX - 1)
+ {
+ /* Can't let f_dup_cnt wrap! */
+ errno = EMFILE;
+ return NULL;
+ }
+ fp->f_dup_cnt++;
+ return fp;
+}
+ /*
+** SM_IO_REOPEN -- open a new file using the old file pointer
+**
+** Parameters:
+** type -- file type to be opened
+** timeout -- time to complete the reopen
+** info -- infomation about what is to be "re-opened" (type dep.)
+** flags -- user flags to map to internal flags
+** rpool -- rpool file to be associated with
+** fp -- the file pointer to reuse
+**
+** Returns:
+** Raises an exception on heap exhaustion.
+** Aborts if type is invalid.
+** Failure: returns NULL
+** Success: returns "reopened" file pointer
+*/
+
+SM_FILE_T *
+sm_io_reopen(type, timeout, info, flags, rpool, fp)
+ const SM_FILE_T *type;
+ int SM_NONVOLATILE timeout;
+ const void *info;
+ int flags;
+ const void *rpool;
+ SM_FILE_T *fp;
+{
+ int ioflags, ret;
+ SM_FILE_T *fp2;
+ SM_EVENT *evt = NULL;
+
+ if ((ioflags = sm_flags(flags)) == 0)
+ {
+ (void) sm_io_close(fp, timeout);
+ return NULL;
+ }
+
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = SM_TIME_FOREVER;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return NULL;
+ }
+ /* Okay, this is where we set the timeout. */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(ReopenTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return NULL;
+ }
+
+ evt = sm_seteventm(timeout, reopenalrm, 0);
+ }
+
+ /*
+ ** There are actually programs that depend on being able to "reopen"
+ ** descriptors that weren't originally open. Keep this from breaking.
+ ** Remember whether the stream was open to begin with, and which file
+ ** descriptor (if any) was associated with it. If it was attached to
+ ** a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin)
+ ** should work. This is unnecessary if it was not a Unix file.
+ */
+
+ if (fp != NULL)
+ {
+ if (fp->sm_magic != SmFileMagic)
+ fp->f_flags = SMFEOF; /* hold on to it */
+ else
+ {
+ /* flush the stream; ANSI doesn't require this. */
+ (void) sm_io_flush(fp, SM_TIME_FOREVER);
+ (void) sm_io_close(fp, SM_TIME_FOREVER);
+ }
+ }
+
+ fp2 = sm_fp(type, ioflags, fp);
+ ret = (*fp2->f_open)(fp2, info, flags, rpool);
+
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+
+ if (ret < 0)
+ {
+ fp2->f_flags = 0; /* release */
+ fp2->sm_magic = NULL; /* release */
+ return NULL;
+ }
+
+ /*
+ ** We're not preserving this logic (below) for sm_io because it is now
+ ** abstracted at least one "layer" away. By closing and reopening
+ ** the 1st fd used should be the just released one (when Unix
+ ** behavior followed). Old comment::
+ ** If reopening something that was open before on a real file, try
+ ** to maintain the descriptor. Various C library routines (perror)
+ ** assume stderr is always fd STDERR_FILENO, even if being reopen'd.
+ */
+
+#if SM_RPOOL
+ if (rpool != NULL)
+ sm_rpool_attach_x(rpool, sm_io_close, fp2);
+#endif /* SM_RPOOL */
+
+ return fp2;
+}
+ /*
+** SM_IO_AUTOFLUSH -- link another file to this for auto-flushing
+**
+** When a read occurs on fp, fp2 will be flushed iff there is no
+** data waiting on fp.
+**
+** Parameters:
+** fp -- the file opened for reading.
+** fp2 -- the file opened for writing.
+**
+** Returns:
+** The old flush file pointer.
+*/
+
+SM_FILE_T *
+sm_io_autoflush(fp, fp2)
+ SM_FILE_T *fp;
+ SM_FILE_T *fp2;
+{
+ SM_FILE_T *savefp;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (fp2 != NULL)
+ SM_REQUIRE_ISA(fp2, SmFileMagic);
+
+ savefp = fp->f_flushfp;
+ fp->f_flushfp = fp2;
+ return savefp;
+}
+ /*
+** SM_IO_AUTOMODE -- link another file to this for auto-moding
+**
+** When the mode (blocking or non-blocking) changes for fp1 then
+** update fp2's mode at the same time. This is to be used when
+** a system dup() has generated a second file descriptor for
+** another sm_io_open() by file descriptor. The modes have been
+** linked in the system and this formalizes it for sm_io internally.
+**
+** Parameters:
+** fp1 -- the first file
+** fp2 -- the second file
+**
+** Returns:
+** nothing
+*/
+
+void
+sm_io_automode(fp1, fp2)
+ SM_FILE_T *fp1;
+ SM_FILE_T *fp2;
+{
+ SM_REQUIRE_ISA(fp1, SmFileMagic);
+ SM_REQUIRE_ISA(fp2, SmFileMagic);
+
+ fp1->f_modefp = fp2;
+ fp2->f_modefp = fp1;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fpos.c b/gnu/usr.sbin/sendmail/libsm/fpos.c
new file mode 100644
index 00000000000..279d017aba5
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fpos.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fpos.c,v 1.35 2001/06/06 00:25:48 ca Exp $")
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/heap.h>
+#include <sm/signal.h>
+#include <sm/clock.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+static jmp_buf TellTimeOut;
+
+/*
+** TELLALRM -- handler when timeout activated for sm_io_tell()
+**
+** Returns flow of control to where setjmp(TellTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(TellTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+tellalrm(sig)
+ int sig;
+{
+ longjmp(TellTimeOut, 1);
+}
+
+/*
+** SM_IO_TELL -- position the file pointer
+**
+** Paramters:
+** fp -- the file pointer to get repositioned
+** timeout -- time to complete the tell (milliseconds)
+**
+** Returns:
+** Success -- the repositioned location.
+** Failure -- -1 (minus 1) and sets errno
+*/
+
+long
+sm_io_tell(fp, timeout)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+{
+ register off_t pos;
+ SM_EVENT *evt = NULL;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (fp->f_seek == NULL)
+ {
+ errno = ESPIPE; /* historic practice */
+ return -1L;
+ }
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return -1L;
+ }
+
+ /*
+ ** Find offset of underlying I/O object, then adjust byte position
+ ** may adjust seek offset on append stream
+ */
+
+ (void) sm_flush(fp, (int *) &timeout);
+
+ /* This is where we start the timeout */
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(TellTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return -1L;
+ }
+
+ evt = sm_seteventm(timeout, tellalrm, 0);
+ }
+
+ if (fp->f_flags & SMOFF)
+ pos = fp->f_lseekoff;
+ else
+ {
+ /* XXX only set the timeout here? */
+ pos = (*fp->f_seek)(fp, (off_t) 0, SM_IO_SEEK_CUR);
+ if (pos == -1L)
+ goto clean;
+ }
+ if (fp->f_flags & SMRD)
+ {
+ /*
+ ** Reading. Any unread characters (including
+ ** those from ungetc) cause the position to be
+ ** smaller than that in the underlying object.
+ */
+
+ pos -= fp->f_r;
+ if (HASUB(fp))
+ pos -= fp->f_ur;
+ }
+ else if (fp->f_flags & SMWR && fp->f_p != NULL)
+ {
+ /*
+ ** Writing. Any buffered characters cause the
+ ** position to be greater than that in the
+ ** underlying object.
+ */
+
+ pos += fp->f_p - fp->f_bf.smb_base;
+ }
+
+clean:
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+ return pos;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fprintf.c b/gnu/usr.sbin/sendmail/libsm/fprintf.c
new file mode 100644
index 00000000000..d5605bb3495
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fprintf.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fprintf.c,v 1.15 2001/03/02 23:53:41 ca Exp $")
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_FPRINTF -- format and print a string to a file pointer
+**
+** Parameters:
+** fp -- file pointer to be printed to
+** timeout -- time to complete print
+** fmt -- markup format for the string to be printed
+** ... -- additional information for 'fmt'
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns the number of characters o/p
+*/
+
+int
+#if SM_VA_STD
+sm_io_fprintf(SM_FILE_T *fp, int timeout, const char *fmt, ...)
+#else /* SM_VA_STD */
+sm_io_fprintf(fp, timeout, fmt, va_alist)
+ SM_FILE_T *fp;
+ int timeout;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_VA_LOCAL_DECL
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ SM_VA_START(ap, fmt);
+ ret = sm_io_vfprintf(fp, timeout, fmt, ap);
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fpurge.c b/gnu/usr.sbin/sendmail/libsm/fpurge.c
new file mode 100644
index 00000000000..fd18d458da2
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fpurge.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fpurge.c,v 1.18 2001/01/28 00:29:35 ca Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_PURGE -- purge/empty the buffer without committing buffer content
+**
+** Parameters:
+** fp -- file pointer to purge
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0 (zero)
+*/
+
+int
+sm_io_purge(fp)
+ register SM_FILE_T *fp;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (!fp->f_flags)
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_p = fp->f_bf.smb_base;
+ fp->f_r = 0;
+
+ /* implies SMFBF */
+ fp->f_w = fp->f_flags & (SMLBF|SMNBF) ? 0 : fp->f_bf.smb_size;
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fput.c b/gnu/usr.sbin/sendmail/libsm/fput.c
new file mode 100644
index 00000000000..fd7dca085e2
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fput.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fput.c,v 1.18 2001/01/28 00:29:35 ca Exp $")
+#include <string.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_IO_FPUTS -- add a string to the buffer for the file pointer
+**
+** Parameters:
+** fp -- the file pointer for the buffer to be written to
+** timeout -- time to complete the put-string
+** s -- string to be placed in the buffer
+**
+** Returns:
+** Failure: returns SM_IO_EOF
+** Success: returns 0 (zero)
+*/
+
+int
+sm_io_fputs(fp, timeout, s)
+ SM_FILE_T *fp;
+ int timeout;
+ const char *s;
+{
+ struct sm_uio uio;
+ struct sm_iov iov;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ iov.iov_base = (void *) s;
+ iov.iov_len = uio.uio_resid = strlen(s);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ return sm_fvwrite(fp, timeout, &uio);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fread.c b/gnu/usr.sbin/sendmail/libsm/fread.c
new file mode 100644
index 00000000000..0e0a97e7fba
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fread.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fread.c,v 1.26 2001/02/28 20:54:03 ca Exp $")
+#include <string.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_READ -- read data from the file pointer
+**
+** Parameters:
+** fp -- file pointer to read from
+** timeout -- time to complete the read
+** buf -- location to place read data
+** size -- size of each chunk of data
+**
+** Returns:
+** Failure: returns 0 (zero) _and_ sets errno
+** Success: returns the number of whole chunks read.
+**
+** A read returning 0 (zero) is only an indication of error when errno
+** has been set.
+*/
+
+size_t
+sm_io_read(fp, timeout, buf, size)
+ SM_FILE_T *fp;
+ int timeout;
+ void *buf;
+ size_t size;
+{
+ register size_t resid = size;
+ register char *p;
+ register int r;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if (fp->f_read == NULL)
+ {
+ errno = ENODEV;
+ return 0;
+ }
+
+ /*
+ ** The ANSI standard requires a return value of 0 for a count
+ ** or a size of 0. Peculiarily, it imposes no such requirements
+ ** on fwrite; it only requires read to be broken.
+ */
+
+ if (resid == 0)
+ return 0;
+ if (fp->f_r < 0)
+ fp->f_r = 0;
+ p = buf;
+ while ((int) resid > (r = fp->f_r))
+ {
+ (void) memcpy((void *) p, (void *) fp->f_p, (size_t) r);
+ fp->f_p += r;
+ /* fp->f_r = 0 ... done in sm_refill */
+ p += r;
+ resid -= r;
+ if ((fp->f_flags & SMNOW) != 0 && r > 0)
+ {
+ /*
+ ** Take whatever we have available. Spend no more time
+ ** trying to get all that has been requested.
+ ** This is needed on some file types (such as
+ ** SASL) that would jam when given extra, untimely
+ ** reads.
+ */
+
+ fp->f_r -= r;
+ return size - resid;
+ }
+ if (sm_refill(fp, timeout) != 0)
+ {
+ /* no more input: return partial result */
+ return size - resid;
+ }
+ }
+ (void) memcpy((void *) p, (void *) fp->f_p, resid);
+ fp->f_r -= resid;
+ fp->f_p += resid;
+ return size;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fscanf.c b/gnu/usr.sbin/sendmail/libsm/fscanf.c
new file mode 100644
index 00000000000..71254d05c95
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fscanf.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fscanf.c,v 1.15 2001/03/02 23:53:41 ca Exp $")
+#include <sm/varargs.h>
+#include <sm/assert.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_IO_FSCANF -- convert input data to translated format
+**
+** Parameters:
+** fp -- the file pointer to obtain the data from
+** timeout -- time to complete scan
+** fmt -- the format to translate the data to
+** ... -- memory locations to place the formated data
+**
+** Returns:
+** Failure: returns SM_IO_EOF
+** Success: returns the number of data units translated
+*/
+
+int
+#if SM_VA_STD
+sm_io_fscanf(SM_FILE_T *fp, int timeout, char const *fmt, ...)
+#else /* SM_VA_STD */
+sm_io_fscanf(fp, timeout, fmt, va_alist)
+ SM_FILE_T *fp;
+ int timeout;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_VA_LOCAL_DECL
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ SM_VA_START(ap, fmt);
+ ret = sm_vfscanf(fp, timeout, fmt, ap);
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fseek.c b/gnu/usr.sbin/sendmail/libsm/fseek.c
new file mode 100644
index 00000000000..bb7d3308573
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fseek.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fseek.c,v 1.42 2001/08/27 18:54:14 gshapiro Exp $")
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/signal.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/clock.h>
+#include "local.h"
+
+#define POS_ERR (-(off_t)1)
+
+static jmp_buf SeekTimeOut;
+
+ /*
+** SEEKALRM -- handler when timeout activated for sm_io_seek()
+**
+** Returns flow of control to where setjmp(SeekTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(SeekTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+seekalrm(sig)
+ int sig;
+{
+ longjmp(SeekTimeOut, 1);
+}
+
+/*
+** SM_IO_SEEK -- position the file pointer
+**
+** Parameters:
+** fp -- the file pointer to be seek'd
+** timeout -- time to complete seek (milliseconds)
+** offset -- seek offset based on 'whence'
+** whence -- indicates where seek is relative from.
+** One of SM_IO_SEEK_{CUR,SET,END}.
+** Returns:
+** Failure: returns -1 (minus 1) and sets errno
+** Success: returns 0 (zero)
+*/
+
+int
+sm_io_seek(fp, timeout, offset, whence)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+ long SM_NONVOLATILE offset;
+ int SM_NONVOLATILE whence;
+{
+ bool havepos;
+ off_t target, curoff;
+ size_t n;
+ struct stat st;
+ int ret;
+ SM_EVENT *evt = NULL;
+ register off_t (*seekfn) __P((SM_FILE_T *, off_t, int));
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ /* make sure stdio is set up */
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ /* Have to be able to seek. */
+ if ((seekfn = fp->f_seek) == NULL)
+ {
+ errno = ESPIPE; /* historic practice */
+ return -1;
+ }
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return -1;
+ }
+
+#define SM_SET_ALARM() \
+ if (timeout != SM_TIME_FOREVER) \
+ { \
+ if (setjmp(SeekTimeOut) != 0) \
+ { \
+ errno = EAGAIN; \
+ return -1; \
+ } \
+ evt = sm_seteventm(timeout, seekalrm, 0); \
+ }
+
+ /*
+ ** Change any SM_IO_SEEK_CUR to SM_IO_SEEK_SET, and check `whence'
+ ** argument. After this, whence is either SM_IO_SEEK_SET or
+ ** SM_IO_SEEK_END.
+ */
+
+ switch (whence)
+ {
+ case SM_IO_SEEK_CUR:
+
+ /*
+ ** In order to seek relative to the current stream offset,
+ ** we have to first find the current stream offset a la
+ ** ftell (see ftell for details).
+ */
+
+ /* may adjust seek offset on append stream */
+ sm_flush(fp, (int *) &timeout);
+ SM_SET_ALARM();
+ if (fp->f_flags & SMOFF)
+ curoff = fp->f_lseekoff;
+ else
+ {
+ curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
+ if (curoff == -1L)
+ {
+ ret = -1;
+ goto clean;
+ }
+ }
+ if (fp->f_flags & SMRD)
+ {
+ curoff -= fp->f_r;
+ if (HASUB(fp))
+ curoff -= fp->f_ur;
+ }
+ else if (fp->f_flags & SMWR && fp->f_p != NULL)
+ curoff += fp->f_p - fp->f_bf.smb_base;
+
+ offset += curoff;
+ whence = SM_IO_SEEK_SET;
+ havepos = true;
+ break;
+
+ case SM_IO_SEEK_SET:
+ case SM_IO_SEEK_END:
+ SM_SET_ALARM();
+ curoff = 0; /* XXX just to keep gcc quiet */
+ havepos = false;
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ ** Can only optimise if:
+ ** reading (and not reading-and-writing);
+ ** not unbuffered; and
+ ** this is a `regular' Unix file (and hence seekfn==sm_stdseek).
+ ** We must check SMNBF first, because it is possible to have SMNBF
+ ** and SMSOPT both set.
+ */
+
+ if (fp->f_bf.smb_base == NULL)
+ sm_makebuf(fp);
+ if (fp->f_flags & (SMWR | SMRW | SMNBF | SMNPT))
+ goto dumb;
+ if ((fp->f_flags & SMOPT) == 0)
+ {
+ if (seekfn != sm_stdseek ||
+ fp->f_file < 0 || fstat(fp->f_file, &st) ||
+ (st.st_mode & S_IFMT) != S_IFREG)
+ {
+ fp->f_flags |= SMNPT;
+ goto dumb;
+ }
+ fp->f_blksize = st.st_blksize;
+ fp->f_flags |= SMOPT;
+ }
+
+ /*
+ ** We are reading; we can try to optimise.
+ ** Figure out where we are going and where we are now.
+ */
+
+ if (whence == SM_IO_SEEK_SET)
+ target = offset;
+ else
+ {
+ if (fstat(fp->f_file, &st))
+ goto dumb;
+ target = st.st_size + offset;
+ }
+
+ if (!havepos)
+ {
+ if (fp->f_flags & SMOFF)
+ curoff = fp->f_lseekoff;
+ else
+ {
+ curoff = (*seekfn)(fp, (off_t) 0, SM_IO_SEEK_CUR);
+ if (curoff == POS_ERR)
+ goto dumb;
+ }
+ curoff -= fp->f_r;
+ if (HASUB(fp))
+ curoff -= fp->f_ur;
+ }
+
+ /*
+ ** Compute the number of bytes in the input buffer (pretending
+ ** that any ungetc() input has been discarded). Adjust current
+ ** offset backwards by this count so that it represents the
+ ** file offset for the first byte in the current input buffer.
+ */
+
+ if (HASUB(fp))
+ {
+ curoff += fp->f_r; /* kill off ungetc */
+ n = fp->f_up - fp->f_bf.smb_base;
+ curoff -= n;
+ n += fp->f_ur;
+ }
+ else
+ {
+ n = fp->f_p - fp->f_bf.smb_base;
+ curoff -= n;
+ n += fp->f_r;
+ }
+
+ /*
+ ** If the target offset is within the current buffer,
+ ** simply adjust the pointers, clear SMFEOF, undo ungetc(),
+ ** and return. (If the buffer was modified, we have to
+ ** skip this; see getln in fget.c.)
+ */
+
+ if (target >= curoff && target < curoff + (off_t) n)
+ {
+ register int o = target - curoff;
+
+ fp->f_p = fp->f_bf.smb_base + o;
+ fp->f_r = n - o;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_flags &= ~SMFEOF;
+ ret = 0;
+ goto clean;
+ }
+
+ /*
+ ** The place we want to get to is not within the current buffer,
+ ** but we can still be kind to the kernel copyout mechanism.
+ ** By aligning the file offset to a block boundary, we can let
+ ** the kernel use the VM hardware to map pages instead of
+ ** copying bytes laboriously. Using a block boundary also
+ ** ensures that we only read one block, rather than two.
+ */
+
+ curoff = target & ~(fp->f_blksize - 1);
+ if ((*seekfn)(fp, curoff, SM_IO_SEEK_SET) == POS_ERR)
+ goto dumb;
+ fp->f_r = 0;
+ fp->f_p = fp->f_bf.smb_base;
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_flags &= ~SMFEOF;
+ n = target - curoff;
+ if (n)
+ {
+ /* Note: SM_TIME_FOREVER since fn timeout already set */
+ if (sm_refill(fp, SM_TIME_FOREVER) || fp->f_r < (int) n)
+ goto dumb;
+ fp->f_p += n;
+ fp->f_r -= n;
+ }
+
+ ret = 0;
+clean:
+ /* We're back. So undo our timeout and handler */
+ if (evt != NULL)
+ sm_clrevent(evt);
+ return ret;
+dumb:
+ /*
+ ** We get here if we cannot optimise the seek ... just
+ ** do it. Allow the seek function to change fp->f_bf.smb_base.
+ */
+
+ /* Note: SM_TIME_FOREVER since fn timeout already set */
+ ret = SM_TIME_FOREVER;
+ if (sm_flush(fp, &ret) != 0 ||
+ (*seekfn)(fp, (off_t) offset, whence) == POS_ERR)
+ {
+ ret = -1;
+ goto clean;
+ }
+
+ /* success: clear SMFEOF indicator and discard ungetc() data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_p = fp->f_bf.smb_base;
+ fp->f_r = 0;
+ fp->f_flags &= ~SMFEOF;
+ ret = 0;
+ goto clean;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fvwrite.c b/gnu/usr.sbin/sendmail/libsm/fvwrite.c
new file mode 100644
index 00000000000..19e3ed0cc5f
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fvwrite.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fvwrite.c,v 1.47 2001/08/27 13:02:20 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/setjmp.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_FVWRITE -- write memory regions and buffer for file pointer
+**
+** Parameters:
+** fp -- the file pointer to write to
+** timeout -- time length for function to return by
+** uio -- the memory regions to write
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0 (zero)
+**
+** This routine is large and unsightly, but most of the ugliness due
+** to the different kinds of output buffering handled here.
+*/
+
+#define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
+#define GETIOV(extra_work) \
+ while (len == 0) \
+ { \
+ extra_work; \
+ p = iov->iov_base; \
+ len = iov->iov_len; \
+ iov++; \
+ }
+
+int
+sm_fvwrite(fp, timeout, uio)
+ register SM_FILE_T *fp;
+ int timeout;
+ register struct sm_uio *uio;
+{
+ register size_t len;
+ register char *p;
+ register struct sm_iov *iov;
+ register int w, s;
+ char *nl;
+ int nlknown, nldist;
+ int fd;
+ struct timeval to;
+
+ if (uio->uio_resid == 0)
+ return 0;
+
+ /* make sure we can write */
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ iov = uio->uio_iov;
+ p = iov->iov_base;
+ len = iov->iov_len;
+ iov++;
+ if (fp->f_flags & SMNBF)
+ {
+ /* Unbuffered: write up to BUFSIZ bytes at a time. */
+ do
+ {
+ GETIOV(;);
+ errno = 0; /* needed to ensure EOF correctly found */
+ w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ));
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ else
+ {
+ p += w;
+ len -= w;
+ }
+ } while ((uio->uio_resid -= w) != 0);
+ }
+ else if ((fp->f_flags & SMLBF) == 0)
+ {
+ /*
+ ** Not SMLBF (line-buffered). Either SMFBF or SMNOW
+ ** buffered: fill partially full buffer, if any,
+ ** and then flush. If there is no partial buffer, write
+ ** one bf._size byte chunk directly (without copying).
+ **
+ ** String output is a special case: write as many bytes
+ ** as fit, but pretend we wrote everything. This makes
+ ** snprintf() return the number of bytes needed, rather
+ ** than the number used, and avoids its write function
+ ** (so that the write function can be invalid).
+ */
+
+ do
+ {
+ GETIOV(;);
+ if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR))
+ || ((fp->f_flags & SMNOW) != 0))
+ && (size_t) fp->f_w < len)
+ {
+ size_t blen = fp->f_p - fp->f_bf.smb_base;
+ unsigned char *tbase;
+ int tsize;
+
+ /* Allocate space exponentially. */
+ tsize = fp->f_bf.smb_size;
+ do
+ {
+ tsize = (tsize << 1) + 1;
+ } while ((size_t) tsize < blen + len);
+ tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base,
+ tsize + 1);
+ if (tbase == NULL)
+ {
+ errno = ENOMEM;
+ goto err; /* errno set */
+ }
+ fp->f_w += tsize - fp->f_bf.smb_size;
+ fp->f_bf.smb_base = tbase;
+ fp->f_bf.smb_size = tsize;
+ fp->f_p = tbase + blen;
+ }
+ w = fp->f_w;
+ errno = 0; /* needed to ensure EOF correctly found */
+ if (fp->f_flags & SMSTR)
+ {
+ if (len < (size_t) w)
+ w = len;
+ COPY(w); /* copy SM_MIN(fp->f_w,len), */
+ fp->f_w -= w;
+ fp->f_p += w;
+ w = len; /* but pretend copied all */
+ }
+ else if (fp->f_p > fp->f_bf.smb_base
+ && len > (size_t) w)
+ {
+ /* fill and flush */
+ COPY(w);
+ fp->f_p += w;
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else if (len >= (size_t) (w = fp->f_bf.smb_size))
+ {
+ /* write directly */
+ w = (*fp->f_write)(fp, p, w);
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ }
+ else
+ {
+ /* fill and done */
+ w = len;
+ COPY(w);
+ fp->f_w -= w;
+ fp->f_p += w;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+
+ if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else
+ {
+ /*
+ ** Line buffered: like fully buffered, but we
+ ** must check for newlines. Compute the distance
+ ** to the first newline (including the newline),
+ ** or `infinity' if there is none, then pretend
+ ** that the amount to write is SM_MIN(len,nldist).
+ */
+
+ nlknown = 0;
+ nldist = 0; /* XXX just to keep gcc happy */
+ do
+ {
+ GETIOV(nlknown = 0);
+ if (!nlknown)
+ {
+ nl = memchr((void *)p, '\n', len);
+ nldist = nl != NULL ? nl + 1 - p : len + 1;
+ nlknown = 1;
+ }
+ s = SM_MIN(len, ((size_t) nldist));
+ w = fp->f_w + fp->f_bf.smb_size;
+ errno = 0; /* needed to ensure EOF correctly found */
+ if (fp->f_p > fp->f_bf.smb_base && s > w)
+ {
+ COPY(w);
+ /* fp->f_w -= w; */
+ fp->f_p += w;
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ }
+ else if (s >= (w = fp->f_bf.smb_size))
+ {
+ w = (*fp->f_write)(fp, p, w);
+ if (w <= 0)
+ {
+ if (w == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, w, timeout))
+ goto err; /* errno set */
+
+ /* write would block */
+ SM_IO_WR_TIMEOUT(fp, fd, timeout);
+ w = 0;
+ }
+ }
+ else
+ {
+ w = s;
+ COPY(w);
+ fp->f_w -= w;
+ fp->f_p += w;
+ }
+ if ((nldist -= w) == 0)
+ {
+ /* copied the newline: flush and forget */
+ if (sm_flush(fp, &timeout))
+ goto err; /* errno set */
+ nlknown = 0;
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ }
+
+ return 0;
+
+err:
+ /* errno set before goto places us here */
+ fp->f_flags |= SMERR;
+ return SM_IO_EOF;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fvwrite.h b/gnu/usr.sbin/sendmail/libsm/fvwrite.h
new file mode 100644
index 00000000000..400818b20c8
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fvwrite.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ *
+ * $Sendmail: fvwrite.h,v 1.7 2001/03/02 00:18:19 ca Exp $
+ */
+
+/* I/O descriptors for sm_fvwrite() */
+struct sm_iov
+{
+ void *iov_base;
+ size_t iov_len;
+};
+struct sm_uio
+{
+ struct sm_iov *uio_iov;
+ int uio_iovcnt;
+ int uio_resid;
+};
+
+extern int sm_fvwrite __P((SM_FILE_T *, int, struct sm_uio *));
diff --git a/gnu/usr.sbin/sendmail/libsm/fwalk.c b/gnu/usr.sbin/sendmail/libsm/fwalk.c
new file mode 100644
index 00000000000..5f52a2cf8fa
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fwalk.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fwalk.c,v 1.19 2001/03/02 03:22:18 ca Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include "local.h"
+#include "glue.h"
+
+/*
+** SM_FWALK -- apply a function to all found-open file pointers
+**
+** Parameters:
+** function -- a function vector to be applied
+** timeout -- time to complete actions (milliseconds)
+**
+** Returns:
+** The (binary) OR'd result of each function call
+*/
+
+int
+sm_fwalk(function, timeout)
+ int (*function) __P((SM_FILE_T *, int *));
+ int *timeout;
+{
+ register SM_FILE_T *fp;
+ register int n, ret;
+ register struct sm_glue *g;
+ int fptimeout;
+
+ ret = 0;
+ for (g = &smglue; g != NULL; g = g->gl_next)
+ {
+ for (fp = g->gl_iobs, n = g->gl_niobs; --n >= 0; fp++)
+ {
+ if (fp->f_flags != 0)
+ {
+ if (*timeout == SM_TIME_DEFAULT)
+ fptimeout = fp->f_timeout;
+ else
+ fptimeout = *timeout;
+ if (fptimeout == SM_TIME_IMMEDIATE)
+ continue; /* skip it */
+ ret |= (*function)(fp, &fptimeout);
+ }
+ }
+ }
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/fwrite.c b/gnu/usr.sbin/sendmail/libsm/fwrite.c
new file mode 100644
index 00000000000..3e8ab5f5409
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/fwrite.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: fwrite.c,v 1.22 2001/04/03 01:46:40 ca Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_IO_WRITE -- write to a file pointer
+**
+** Parameters:
+** fp -- file pointer writing to
+** timeout -- time to complete the write
+** buf -- location of data to be written
+** size -- number of bytes to be written
+**
+** Result:
+** Failure: returns 0 _and_ sets errno
+** Success: returns >=0 with errno unchanged, where the
+** number returned is the number of bytes written.
+*/
+
+size_t
+sm_io_write(fp, timeout, buf, size)
+ SM_FILE_T *fp;
+ int timeout;
+ const void *buf;
+ size_t size;
+{
+ struct sm_uio uio;
+ struct sm_iov iov;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ if (fp->f_write == NULL)
+ {
+ errno = ENODEV;
+ return 0;
+ }
+
+ iov.iov_base = (void *) buf;
+ uio.uio_resid = iov.iov_len = size;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+
+ /* The usual case is success (sm_fvwrite returns 0) */
+ if (sm_fvwrite(fp, timeout, &uio) == 0)
+ return size;
+
+ /* else return number of bytes actually written */
+ return size - uio.uio_resid;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/gen.html b/gnu/usr.sbin/sendmail/libsm/gen.html
new file mode 100644
index 00000000000..7eb04fb2fba
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/gen.html
@@ -0,0 +1,43 @@
+<html>
+<head>
+ <title>libsm : General Definitions</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : General Definitions </h1>
+ <br> $Sendmail: gen.html,v 1.5 2000/12/08 21:41:42 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The header file <tt>&lt;sm/gen.h&gt;</tt>
+contains general definitions that are used by every other
+header file in <b>libsm</b>.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/gen.h&gt;
+
+#define NULL ((void*)0)
+
+typedef int bool;
+#define false 0
+#define true 1
+
+#define SM_MAX(a, b) ((a) &gt; (b) ? (a) : (b))
+#define SM_MIN(a, b) ((a) &lt; (b) ? (a) : (b))
+
+/*
+** The following types can be accessed and updated atomically.
+** This is relevant in the context of signal handlers and threads.
+*/
+typedef <i>some signed integral type</i> SM_ATOMIC_INT_T;
+typedef <i>some unsigned integral type</i> SM_ATOMIC_UINT_T;
+</pre>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/get.c b/gnu/usr.sbin/sendmail/libsm/get.c
new file mode 100644
index 00000000000..068286a6344
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/get.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: get.c,v 1.16 2001/01/28 00:29:35 ca Exp $")
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_GETC -- get a character from a file
+**
+** Parameters:
+** fp -- the file to get the character from
+** timeout -- time to complete getc
+**
+** Returns:
+** Success: the value of the character read.
+** Failure: SM_IO_EOF
+**
+** This is a function version of the macro (in <sm/io.h>).
+** It is guarded with locks (which are currently not functional)
+** for multi-threaded programs.
+*/
+
+#undef sm_io_getc
+
+int
+sm_io_getc(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ return sm_getc(fp, timeout);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/glue.h b/gnu/usr.sbin/sendmail/libsm/glue.h
new file mode 100644
index 00000000000..8f066524331
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/glue.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ *
+ * $Sendmail: glue.h,v 1.6 2001/01/22 23:09:49 ca Exp $
+ */
+
+/*
+** The first few FILEs are statically allocated; others are dynamically
+** allocated and linked in via this glue structure.
+*/
+
+extern struct sm_glue
+{
+ struct sm_glue *gl_next;
+ int gl_niobs;
+ SM_FILE_T *gl_iobs;
+} smglue;
diff --git a/gnu/usr.sbin/sendmail/libsm/heap.c b/gnu/usr.sbin/sendmail/libsm/heap.c
new file mode 100644
index 00000000000..27ab6c767e7
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/heap.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: heap.c,v 1.47 2001/09/04 22:41:27 ca Exp $")
+
+/*
+** debugging memory allocation package
+** See heap.html for documentation.
+*/
+
+#include <string.h>
+
+#include <sm/assert.h>
+#include <sm/debug.h>
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/io.h>
+#include <sm/signal.h>
+#include <sm/xtrap.h>
+
+/* undef all macro versions of the "functions" so they can be specified here */
+#undef sm_malloc
+#undef sm_malloc_x
+#undef sm_malloc_tagged
+#undef sm_malloc_tagged_x
+#undef sm_free
+#undef sm_free_tagged
+#undef sm_realloc
+#if SM_HEAP_CHECK
+# undef sm_heap_register
+# undef sm_heap_checkptr
+# undef sm_heap_report
+#endif /* SM_HEAP_CHECK */
+
+#if SM_HEAP_CHECK
+SM_DEBUG_T SmHeapCheck = SM_DEBUG_INITIALIZER("sm_check_heap",
+ "@(#)$Debug: sm_check_heap - check sm_malloc, sm_realloc, sm_free calls $");
+# define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1)
+#endif /* SM_HEAP_CHECK */
+
+const SM_EXC_TYPE_T SmHeapOutOfMemoryType =
+{
+ SmExcTypeMagic,
+ "F:sm.heap",
+ "",
+ sm_etype_printf,
+ "out of memory",
+};
+
+SM_EXC_T SmHeapOutOfMemory = SM_EXC_INITIALIZER(&SmHeapOutOfMemoryType, NULL);
+
+
+/*
+** The behaviour of malloc with size==0 is platform dependent (it
+** says so in the C standard): it can return NULL or non-NULL. We
+** don't want sm_malloc_x(0) to raise an exception on some platforms
+** but not others, so this case requires special handling. We've got
+** two choices: "size = 1" or "return NULL". We use the former in the
+** following.
+** If we had something like autoconf we could figure out the
+** behaviour of the platform and either use this hack or just
+** use size.
+*/
+
+#define MALLOC_SIZE(size) ((size) == 0 ? 1 : (size))
+
+/*
+** SM_MALLOC_X -- wrapper around malloc(), raises an exception on error.
+**
+** Parameters:
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to memory region.
+**
+** Note:
+** sm_malloc_x only gets called from source files in which heap
+** debugging is disabled at compile time. Otherwise, a call to
+** sm_malloc_x is macro expanded to a call to sm_malloc_tagged_x.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_malloc_x(size)
+ size_t size;
+{
+ void *ptr;
+
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return ptr;
+}
+
+#if !SM_HEAP_CHECK
+
+/*
+** SM_MALLOC -- wrapper around malloc()
+**
+** Parameters:
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to memory region.
+*/
+
+void *
+sm_malloc(size)
+ size_t size;
+{
+ void *ptr;
+
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return ptr;
+}
+
+/*
+** SM_REALLOC -- wrapper for realloc()
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area, NULL on failure.
+*/
+
+void *
+sm_realloc(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return newptr;
+}
+
+/*
+** SM_REALLOC_X -- wrapper for realloc()
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_realloc_x(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return newptr;
+}
+ /*
+** SM_FREE -- wrapper around free()
+**
+** Parameters:
+** ptr -- pointer to memory region.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_free(ptr)
+ void *ptr;
+{
+ if (ptr == NULL)
+ return;
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ return;
+}
+
+#else /* !SM_HEAP_CHECK */
+
+/*
+** Each allocated block is assigned a "group number".
+** By default, all blocks are assigned to group #1.
+** By convention, group #0 is for memory that is never freed.
+** You can use group numbers any way you want, in order to help make
+** sense of sm_heap_report output.
+*/
+
+int SmHeapGroup = 1;
+int SmHeapMaxGroup = 1;
+
+/*
+** Total number of bytes allocated.
+** This is only maintained if the sm_check_heap debug category is active.
+*/
+
+size_t SmHeapTotal = 0;
+
+/*
+** High water mark: the most that SmHeapTotal has ever been.
+*/
+
+size_t SmHeapMaxTotal = 0;
+
+/*
+** Maximum number of bytes that may be allocated at any one time.
+** 0 means no limit.
+** This is only honoured if sm_check_heap is active.
+*/
+
+SM_DEBUG_T SmHeapLimit = SM_DEBUG_INITIALIZER("sm_heap_limit",
+ "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $");
+
+/*
+** This is the data structure that keeps track of all currently
+** allocated blocks of memory known to the heap package.
+*/
+
+typedef struct sm_heap_item SM_HEAP_ITEM_T;
+struct sm_heap_item
+{
+ void *hi_ptr;
+ size_t hi_size;
+ char *hi_tag;
+ int hi_num;
+ int hi_group;
+ SM_HEAP_ITEM_T *hi_next;
+};
+
+#define SM_HEAP_TABLE_SIZE 256
+static SM_HEAP_ITEM_T *SmHeapTable[SM_HEAP_TABLE_SIZE];
+
+/*
+** This is a randomly generated table
+** which contains exactly one occurrence
+** of each of the numbers between 0 and 255.
+** It is used by ptrhash.
+*/
+
+static unsigned char hashtab[SM_HEAP_TABLE_SIZE] =
+{
+ 161, 71, 77,187, 15,229, 9,176,221,119,239, 21, 85,138,203, 86,
+ 102, 65, 80,199,235, 32,140, 96,224, 78,126,127,144, 0, 11,179,
+ 64, 30,120, 23,225,226, 33, 50,205,167,130,240,174, 99,206, 73,
+ 231,210,189,162, 48, 93,246, 54,213,141,135, 39, 41,192,236,193,
+ 157, 88, 95,104,188, 63,133,177,234,110,158,214,238,131,233, 91,
+ 125, 82, 94, 79, 66, 92,151, 45,252, 98, 26,183, 7,191,171,106,
+ 145,154,251,100,113, 5, 74, 62, 76,124, 14,217,200, 75,115,190,
+ 103, 28,198,196,169,219, 37,118,150, 18,152,175, 49,136, 6,142,
+ 89, 19,243,254, 47,137, 24,166,180, 10, 40,186,202, 46,184, 67,
+ 148,108,181, 81, 25,241, 13,139, 58, 38, 84,253,201, 12,116, 17,
+ 195, 22,112, 69,255, 43,147,222,111, 56,194,216,149,244, 42,173,
+ 232,220,249,105,207, 51,197,242, 72,211,208, 59,122,230,237,170,
+ 165, 44, 68,123,129,245,143,101, 8,209,215,247,185, 57,218, 53,
+ 114,121, 3,128, 4,204,212,146, 2,155, 83,250, 87, 29, 31,159,
+ 60, 27,107,156,227,182, 1, 61, 36,160,109, 97, 90, 20,168,132,
+ 223,248, 70,164, 55,172, 34, 52,163,117, 35,153,134, 16,178,228
+};
+
+/*
+** PTRHASH -- hash a pointer value
+**
+** Parameters:
+** p -- pointer.
+**
+** Returns:
+** hash value.
+**
+** ptrhash hashes a pointer value to a uniformly distributed random
+** number between 0 and 255.
+**
+** This hash algorithm is based on Peter K. Pearson,
+** "Fast Hashing of Variable-Length Text Strings",
+** in Communications of the ACM, June 1990, vol 33 no 6.
+*/
+
+static int
+ptrhash(p)
+ void *p;
+{
+ int h;
+
+ if (sizeof(void*) == 4 && sizeof(unsigned long) == 4)
+ {
+ unsigned long n = (unsigned long)p;
+
+ h = hashtab[n & 0xFF];
+ h = hashtab[h ^ ((n >> 8) & 0xFF)];
+ h = hashtab[h ^ ((n >> 16) & 0xFF)];
+ h = hashtab[h ^ ((n >> 24) & 0xFF)];
+ }
+# if 0
+ else if (sizeof(void*) == 8 && sizeof(unsigned long) == 8)
+ {
+ unsigned long n = (unsigned long)p;
+
+ h = hashtab[n & 0xFF];
+ h = hashtab[h ^ ((n >> 8) & 0xFF)];
+ h = hashtab[h ^ ((n >> 16) & 0xFF)];
+ h = hashtab[h ^ ((n >> 24) & 0xFF)];
+ h = hashtab[h ^ ((n >> 32) & 0xFF)];
+ h = hashtab[h ^ ((n >> 40) & 0xFF)];
+ h = hashtab[h ^ ((n >> 48) & 0xFF)];
+ h = hashtab[h ^ ((n >> 56) & 0xFF)];
+ }
+# endif /* 0 */
+ else
+ {
+ unsigned char *cp = (unsigned char *)&p;
+ int i;
+
+ h = 0;
+ for (i = 0; i < sizeof(void*); ++i)
+ h = hashtab[h ^ cp[i]];
+ }
+ return h;
+}
+
+/*
+** SM_MALLOC_TAGGED -- wrapper around malloc(), debugging version.
+**
+** Parameters:
+** size -- size of requested memory.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to memory region.
+*/
+
+void *
+sm_malloc_tagged(size, tag, num, group)
+ size_t size;
+ char *tag;
+ int num;
+ int group;
+{
+ void *ptr;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return ptr;
+ }
+
+ if (sm_xtrap_check())
+ return NULL;
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
+ return NULL;
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
+ {
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ ptr = NULL;
+ }
+ SmHeapTotal += size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ return ptr;
+}
+
+/*
+** SM_MALLOC_TAGGED_X -- wrapper around malloc(), debugging version.
+**
+** Parameters:
+** size -- size of requested memory.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to memory region.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_malloc_tagged_x(size, tag, num, group)
+ size_t size;
+ char *tag;
+ int num;
+ int group;
+{
+ void *ptr;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return ptr;
+ }
+
+ sm_xtrap_raise_x(&SmHeapOutOfMemory);
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
+ {
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ }
+ ENTER_CRITICAL();
+ ptr = malloc(MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
+ {
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ ptr = NULL;
+ }
+ if (ptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ SmHeapTotal += size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ return ptr;
+}
+
+/*
+** SM_HEAP_REGISTER -- register a pointer into the heap for debugging.
+**
+** Parameters:
+** ptr -- pointer to register.
+** size -- size of requested memory.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+** group -- heap group for debugging.
+**
+** Returns:
+** true iff successfully registered (not yet in table).
+*/
+
+bool
+sm_heap_register(ptr, size, tag, num, group)
+ void *ptr;
+ size_t size;
+ char *tag;
+ int num;
+ int group;
+{
+ int i;
+ SM_HEAP_ITEM_T *hi;
+
+ if (!HEAP_CHECK)
+ return true;
+ SM_REQUIRE(ptr != NULL);
+ i = ptrhash(ptr);
+# if SM_CHECK_REQUIRE
+
+ /*
+ ** We require that ptr is not already in SmHeapTable.
+ */
+
+ for (hi = SmHeapTable[i]; hi != NULL; hi = hi->hi_next)
+ {
+ if (hi->hi_ptr == ptr)
+ sm_abort("sm_heap_register: ptr %p is already registered (%s:%d)",
+ ptr, hi->hi_tag, hi->hi_num);
+ }
+# endif /* SM_CHECK_REQUIRE */
+ ENTER_CRITICAL();
+ hi = (SM_HEAP_ITEM_T *) malloc(sizeof(SM_HEAP_ITEM_T));
+ LEAVE_CRITICAL();
+ if (hi == NULL)
+ return false;
+ hi->hi_ptr = ptr;
+ hi->hi_size = size;
+ hi->hi_tag = tag;
+ hi->hi_num = num;
+ hi->hi_group = group;
+ hi->hi_next = SmHeapTable[i];
+ SmHeapTable[i] = hi;
+ return true;
+}
+ /*
+** SM_REALLOC -- wrapper for realloc(), debugging version.
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area, NULL on failure.
+*/
+
+void *
+sm_realloc(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+ SM_HEAP_ITEM_T *hi, **hp;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ return newptr;
+ }
+
+ if (ptr == NULL)
+ return sm_malloc_tagged(size, "realloc", 0, SmHeapGroup);
+
+ for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
+ {
+ if ((**hp).hi_ptr == ptr)
+ {
+ if (sm_xtrap_check())
+ return NULL;
+ hi = *hp;
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit)
+ < SmHeapTotal - hi->hi_size + size)
+ {
+ return NULL;
+ }
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ return NULL;
+ SmHeapTotal = SmHeapTotal - hi->hi_size + size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ *hp = hi->hi_next;
+ hi->hi_ptr = newptr;
+ hi->hi_size = size;
+ hp = &SmHeapTable[ptrhash(newptr)];
+ hi->hi_next = *hp;
+ *hp = hi;
+ return newptr;
+ }
+ }
+ sm_abort("sm_realloc: bad argument (%p)", ptr);
+ /* NOTREACHED */
+ return NULL; /* keep Irix compiler happy */
+}
+
+/*
+** SM_REALLOC_X -- wrapper for realloc(), debugging version.
+**
+** Parameters:
+** ptr -- pointer to old memory area.
+** size -- size of requested memory.
+**
+** Returns:
+** Pointer to new memory area.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+sm_realloc_x(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ void *newptr;
+ SM_HEAP_ITEM_T *hi, **hp;
+
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ return newptr;
+ }
+
+ if (ptr == NULL)
+ return sm_malloc_tagged_x(size, "realloc", 0, SmHeapGroup);
+
+ for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
+ {
+ if ((**hp).hi_ptr == ptr)
+ {
+ sm_xtrap_raise_x(&SmHeapOutOfMemory);
+ hi = *hp;
+ if (sm_debug_active(&SmHeapLimit, 1)
+ && sm_debug_level(&SmHeapLimit)
+ < SmHeapTotal - hi->hi_size + size)
+ {
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ }
+ ENTER_CRITICAL();
+ newptr = realloc(ptr, MALLOC_SIZE(size));
+ LEAVE_CRITICAL();
+ if (newptr == NULL)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ SmHeapTotal = SmHeapTotal - hi->hi_size + size;
+ if (SmHeapTotal > SmHeapMaxTotal)
+ SmHeapMaxTotal = SmHeapTotal;
+ *hp = hi->hi_next;
+ hi->hi_ptr = newptr;
+ hi->hi_size = size;
+ hp = &SmHeapTable[ptrhash(newptr)];
+ hi->hi_next = *hp;
+ *hp = hi;
+ return newptr;
+ }
+ }
+ sm_abort("sm_realloc_x: bad argument (%p)", ptr);
+ /* NOTREACHED */
+ return NULL; /* keep Irix compiler happy */
+}
+
+/*
+** SM_FREE_TAGGED -- wrapper around free(), debugging version.
+**
+** Parameters:
+** ptr -- pointer to memory region.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_free_tagged(ptr, tag, num)
+ void *ptr;
+ char *tag;
+ int num;
+{
+ SM_HEAP_ITEM_T **hp;
+
+ if (ptr == NULL)
+ return;
+ if (!HEAP_CHECK)
+ {
+ ENTER_CRITICAL();
+ free(ptr);
+ LEAVE_CRITICAL();
+ return;
+ }
+ for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
+ {
+ if ((**hp).hi_ptr == ptr)
+ {
+ SM_HEAP_ITEM_T *hi = *hp;
+
+ *hp = hi->hi_next;
+
+ /*
+ ** Fill the block with zeros before freeing.
+ ** This is intended to catch problems with
+ ** dangling pointers. The block is filled with
+ ** zeros, not with some non-zero value, because
+ ** it is common practice in some C code to store
+ ** a zero in a structure member before freeing the
+ ** structure, as a defense against dangling pointers.
+ */
+
+ (void) memset(ptr, 0, hi->hi_size);
+ SmHeapTotal -= hi->hi_size;
+ ENTER_CRITICAL();
+ free(ptr);
+ free(hi);
+ LEAVE_CRITICAL();
+ return;
+ }
+ }
+ sm_abort("sm_free: bad argument (%p) (%s:%d)", ptr, tag, num);
+}
+
+/*
+** SM_HEAP_CHECKPTR_TAGGED -- check whether ptr is a valid argument to sm_free
+**
+** Parameters:
+** ptr -- pointer to memory region.
+** tag -- tag for debugging.
+** num -- additional value for debugging.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** aborts if check fails.
+*/
+
+void
+sm_heap_checkptr_tagged(ptr, tag, num)
+ void *ptr;
+ char *tag;
+ int num;
+{
+ SM_HEAP_ITEM_T *hp;
+
+ if (!HEAP_CHECK)
+ return;
+ if (ptr == NULL)
+ return;
+ for (hp = SmHeapTable[ptrhash(ptr)]; hp != NULL; hp = hp->hi_next)
+ {
+ if (hp->hi_ptr == ptr)
+ return;
+ }
+ sm_abort("sm_heap_checkptr(%p): bad ptr (%s:%d)", ptr, tag, num);
+}
+
+/*
+** SM_HEAP_REPORT -- output "map" of used heap.
+**
+** Parameters:
+** stream -- the file pointer to write to.
+** verbosity -- how much info?
+**
+** Returns:
+** none.
+*/
+
+void
+sm_heap_report(stream, verbosity)
+ SM_FILE_T *stream;
+ int verbosity;
+{
+ int i;
+ unsigned long group0total, group1total, otherstotal, grandtotal;
+
+ if (!HEAP_CHECK || verbosity <= 0)
+ return;
+ group0total = group1total = otherstotal = grandtotal = 0;
+ for (i = 0; i < sizeof(SmHeapTable) / sizeof(SmHeapTable[0]); ++i)
+ {
+ SM_HEAP_ITEM_T *hi = SmHeapTable[i];
+
+ while (hi != NULL)
+ {
+ if (verbosity > 2
+ || (verbosity > 1 && hi->hi_group != 0))
+ {
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "%4d %*lx %7lu bytes",
+ hi->hi_group,
+ (int) sizeof(void *) * 2,
+ (long)hi->hi_ptr,
+ (unsigned long)hi->hi_size);
+ if (hi->hi_tag != NULL)
+ {
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ " %s",
+ hi->hi_tag);
+ if (hi->hi_num)
+ {
+ sm_io_fprintf(stream,
+ SM_TIME_DEFAULT,
+ ":%d",
+ hi->hi_num);
+ }
+ }
+ sm_io_fprintf(stream, SM_TIME_DEFAULT, "\n");
+ }
+ switch (hi->hi_group)
+ {
+ case 0:
+ group0total += hi->hi_size;
+ break;
+ case 1:
+ group1total += hi->hi_size;
+ break;
+ default:
+ otherstotal += hi->hi_size;
+ break;
+ }
+ grandtotal += hi->hi_size;
+ hi = hi->hi_next;
+ }
+ }
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "heap max=%lu, total=%lu, ",
+ (unsigned long) SmHeapMaxTotal, grandtotal);
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "group 0=%lu, group 1=%lu, others=%lu\n",
+ group0total, group1total, otherstotal);
+ if (grandtotal != SmHeapTotal)
+ {
+ sm_io_fprintf(stream, SM_TIME_DEFAULT,
+ "BUG => SmHeapTotal: got %lu, expected %lu\n",
+ (unsigned long) SmHeapTotal, grandtotal);
+ }
+}
+#endif /* !SM_HEAP_CHECK */
diff --git a/gnu/usr.sbin/sendmail/libsm/heap.html b/gnu/usr.sbin/sendmail/libsm/heap.html
new file mode 100644
index 00000000000..da14637aa4c
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/heap.html
@@ -0,0 +1,424 @@
+<html>
+<head>
+ <title>libsm : Memory Allocation</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Memory Allocation </h1>
+ <br> $Sendmail: heap.html,v 1.9 2000/12/08 21:41:42 ca Exp $
+</center>
+
+<h2> Introduction </h2>
+
+The heap package provides a layer of abstraction on top of
+<tt>malloc</tt>, <tt>realloc</tt> and <tt>free</tt>
+that provides optional error checking and memory leak detection,
+and which optionally raises an exception when an allocation request
+cannot be satisfied.
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/heap.h&gt;
+
+/*
+** Wrappers for malloc, realloc, free
+*/
+void *sm_malloc(size_t size);
+void *sm_realloc(void *ptr, size_t size);
+void sm_free(void *ptr);
+
+/*
+** Wrappers for malloc, realloc that raise an exception instead of
+** returning NULL on heap exhaustion.
+*/
+void *sm_malloc_x(size_t size);
+void *sm_realloc_x(void *ptr, size_t size);
+
+/*
+** Print a list of currently allocated blocks,
+** used to diagnose memory leaks.
+*/
+void sm_heap_report(FILE *stream, int verbosity);
+
+/*
+** Low level interfaces.
+*/
+int sm_heap_group();
+int sm_heap_setgroup(int g);
+int sm_heap_newgroup();
+void *sm_malloc_tagged(size_t size, char *file, int line, int group);
+void *sm_malloc_tagged_x(size_t size, char *file, int line, int group);
+bool sm_heap_register(void *ptr, size_t size, char *file, int line);
+</pre>
+
+<h2> How to allocate and free memory </h2>
+
+ <tt>sm_malloc</tt>, <tt>sm_realloc</tt> and <tt>sm_free</tt>
+ are portable plug in replacements
+ for <tt>malloc</tt>, <tt>realloc</tt> and <tt>free</tt> that provide
+ error checking and memory leak detection.
+ <tt>sm_malloc_x</tt> and <tt>sm_realloc_x</tt>
+ are variants of
+ <tt>sm_malloc</tt> and <tt>sm_realloc</tt>
+ that raise an exception on error.
+ To use the package effectively,
+ all calls to <tt>malloc</tt>, <tt>realloc</tt> and <tt>free</tt>
+ should be replaced by calls
+ to the corresponding <tt>sm_</tt>* routines.
+
+<dl>
+<dt>
+<tt> void *sm_malloc(size_t size) </tt>
+<dd>
+ This function is a plug-in replacement for <tt>malloc</tt>.
+ It allocates <tt>size</tt> bytes of memory on the heap
+ and returns a pointer to it,
+ or it returns <tt>NULL</tt> on failure.
+ <p>
+
+ The C standard says that <tt>malloc(0)</tt> may return
+ either <tt>NULL</tt> or a non-<tt>NULL</tt> value.
+ To ensure consistent behaviour on all platforms,
+ <tt>sm_malloc(0)</tt> is equivalent to <tt>sm_malloc(1)</tt>.
+ <p>
+
+ In addition, if heap checking is enabled, then <tt>sm_malloc</tt>
+ maintains a hash table describing all currently allocated
+ memory blocks. This table is used for argument validity
+ checking in <tt>sm_realloc</tt> and <tt>sm_free</tt>,
+ and it can be printed using <tt>sm_heap_report</tt>
+ as an aid to finding memory leaks.
+ <p>
+
+<dt>
+<tt> void *sm_malloc_x(size_t size) </tt>
+<dd>
+ This function is just like <tt>sm_malloc</tt>
+ except that it raises the <tt>SmHeapOutOfMemory</tt> exception
+ instead of returning <tt>NULL</tt> on error.
+ <p>
+
+<dt>
+<tt> void *sm_realloc(void *ptr, size_t size) </tt>
+<dd>
+ This function is a plug-in replacement for <tt>realloc</tt>.
+ If <tt>ptr</tt> is null then this call is equivalent
+ to <tt>sm_malloc(size)</tt>.
+ Otherwise, the size of the object pointed to by <tt>ptr</tt>
+ is changed to <tt>size</tt> bytes, and a pointer to the
+ (possibly moved) object is returned.
+ If the space cannot be allocated, then the object pointed to
+ by <tt>ptr</tt> is unchanged and <tt>NULL</tt> is returned.
+ <p>
+
+ If <tt>size</tt> is 0 then we pretend that <tt>size</tt> is 1.
+ This may be a mistake.
+ <p>
+
+ If ptr is not NULL and heap checking is enabled,
+ then ptr is required to be a value that was
+ previously returned by sm_malloc or sm_realloc, and which
+ has not yet been freed by sm_free. If this condition is not
+ met, then the program is aborted using sm_abort.
+ <p>
+
+<dt>
+<tt> void *sm_realloc_x(void *ptr, size_t size) </tt>
+<dd>
+ This function is just like <tt>sm_realloc</tt>
+ except that it raises the SmHeapOutOfMemory exception
+ instead of returning <tt>NULL</tt> on error.
+ <p>
+
+<dt>
+<tt> void sm_free(void *ptr) </tt>
+<dd>
+ This function is a plug-in replacement for free.
+ If heap checking is disabled, then this function is equivalent
+ to a call to free. Otherwise, the following additional semantics
+ apply.
+ <p>
+
+ If ptr is NULL, this function has no effect.
+ <p>
+
+ Otherwise, ptr is required to be a value that was
+ previously returned by sm_malloc or sm_realloc, and which
+ has not yet been freed by sm_free. If this condition is not
+ met, then the program is aborted using sm_abort.
+ <p>
+
+ Otherwise, if there is no error, then the block pointed to by ptr
+ will be set to all zeros before free() is called. This is intended
+ to assist in detecting the use of dangling pointers.
+</dl>
+
+<h2> How to control tag information </h2>
+
+When heap checking is enabled,
+the heap package maintains a hash table which associates the
+following values with each currently allocated block:
+
+<dl>
+<dt>
+<tt> size_t size </tt>
+<dd>
+ The size of the block.
+<dt>
+<tt> char *tag </tt>
+<dd>
+ By default, this is the name of the source file from which
+ the block was allocated, but you can specify an arbitrary
+ string pointer, or <tt>NULL</tt>.
+<dt>
+<tt> int num </tt>
+<dd>
+ By default, this is the line number from which the block was
+ allocated.
+<dt>
+<tt> int group </tt>
+<dd>
+ By convention, group==0 indicates that the block is permanently
+ allocated and will never be freed. The meanings of other group
+ numbers are defined by the application developer.
+ Unless you take special action, all blocks allocated by
+ <tt>sm_malloc</tt> and <tt>sm_malloc_x</tt> will be assigned
+ to group 1.
+</dl>
+
+These tag values are printed by <tt>sm_heap_report</tt>,
+and are used to help analyze memory allocation behaviour
+and to find memory leaks.
+The following functions give you precise control over the
+tag values associated with each allocated block.
+
+<dl>
+<dt>
+<tt> void *sm_malloc_tagged(size_t size, int tag, int num, int group) </tt>
+<dd>
+ Just like <tt>sm_malloc</tt>, except you directly specify
+ all of the tag values.
+ If heap checking is disabled at compile time, then a call
+ to <tt>sm_malloc_tagged</tt> is macro expanded to
+ a call to <tt>malloc</tt>.
+ <p>
+
+ Note that the expression <tt>sm_malloc(size)</tt> is macro expanded to
+
+<blockquote><pre>
+sm_malloc_tagged(size, __FILE__, __LINE__, sm_heap_group())
+</pre></blockquote>
+
+<dt>
+<tt> void *sm_malloc_tagged_x(size_t size, int tag, int num, int group) </tt>
+<dd>
+ A variant of <tt>sm_malloc_tagged</tt>
+ that raises an exception on error.
+ A call to <tt>sm_malloc_x</tt> is macro expanded
+ to a call to <tt>sm_malloc_tagged_x</tt>.
+ <p>
+
+<dt>
+<tt> int sm_heap_group() </tt>
+<dd>
+ The heap package maintains a thread-local variable containing
+ the current group number.
+ This is the group that <tt>sm_malloc</tt> and <tt>sm_malloc_x</tt>
+ will assign a newly allocated block to.
+ The initial value of this variable is 1.
+ The current value of this variable is returned by
+ <tt>sm_heap_group()</tt>.
+ <p>
+
+<dt>
+<tt> int sm_heap_setgroup(int g) </tt>
+<dd>
+ Set the current group to the specified value.
+</dl>
+
+Here are two examples of how you might use these interfaces.
+
+<ol>
+<li>
+One way to detect memory leaks is to turn on heap checking
+and call <tt>sm_heap_report(stdout,2)</tt>
+when the program exits.
+This prints a list of all allocated blocks that do not belong to group 0.
+(Blocks in group 0 are assumed to be permanently allocated,
+and so their existence at program exit does not indicate a leak.)
+If you want to allocate a block and assign it to group 0,
+you have two choices:
+
+<blockquote><pre>
+int g = sm_heap_group();
+sm_heap_setgroup(0);
+p = sm_malloc_x(size);
+sm_heap_setgroup(g);
+</pre></blockquote>
+
+or
+
+<blockquote><pre>
+p = sm_malloc_tagged_x(size, __FILE__, __LINE__, 0);
+</pre></blockquote>
+
+<li>
+Suppose you have a utility function foo_alloc which allocates
+and initializes a 'foo' object. When sm_heap_report is called,
+all unfreed 'foo' objects will be reported to have the same
+source code file name and line number.
+That might make it difficult to determine where a memory leak is.
+<p>
+
+Here is how you can arrange for more precise reporting for
+unfreed foo objects:
+
+<blockquote><pre>
+#include &lt;sm/heap.h&gt;
+
+#if SM_HEAP_CHECK
+# define foo_alloc_x() foo_alloc_tagged_x(__FILE__,__LINE)
+ FOO *foo_alloc_tagged_x(char *, int);
+#else
+ FOO *foo_alloc_x(void);
+# define foo_alloc_tagged_x(file,line) foo_alloc_x()
+#endif
+
+...
+
+#if SM_HEAP_CHECK
+FOO *
+foo_alloc_tagged_x(char *file, int line)
+#else
+FOO *
+foo_alloc_x(void)
+#endif
+{
+ FOO *p;
+
+ p = sm_malloc_tagged_x(sizeof(FOO), file, line, sm_heap_group());
+ ...
+ return p;
+}
+</pre></blockquote>
+</ol>
+
+<h2> How to dump the block list </h2>
+
+To perform memory leak detection, you need to arrange for your
+program to call sm_heap_report at appropriate times.
+
+<dl>
+<dt>
+<tt> void sm_heap_report(FILE *stream, int verbosity) </tt>
+<dd>
+ If heap checking is disabled, this function does nothing.
+ If verbosity &lt;= 0, this function does nothing.
+ <p>
+
+ If verbosity &gt;= 1, then sm_heap_report prints a single line
+ to stream giving the total number of bytes currently allocated.
+ If you call sm_heap_report each time the program has reached a
+ "ground state", and the reported amount of heap storage is
+ monotonically increasing, that indicates a leak.
+ <p>
+
+ If verbosity &gt;= 2, then sm_heap_report additionally prints one line
+ for each block of memory currently allocated, providing that
+ the group != 0.
+ (Such blocks are assumed to be permanently allocated storage, and
+ are not reported to cut down the level of noise.)
+ <p>
+
+ If verbosity &gt;= 3, then sm_heap_report prints one line for each
+ allocated block, regardless of the group.
+</dl>
+
+<h2> How to enable heap checking </h2>
+
+The overhead of using the package can be made as small as you want.
+You have three options:
+
+<ol>
+<li>
+ If you compile your software with -DSM_HEAP_CHECK=0 then
+ sm_malloc, sm_realloc and sm_free will be redefined
+ as macros that call malloc, realloc, and free. In this case,
+ there is zero overhead.
+<li>
+ If you do not define -DSM_HEAP_CHECK=0, and you do not explicitly
+ turn on heap checking at run time, then your program will run
+ without error checking and memory leak detection, and the additional
+ cost of calling sm_malloc, sm_realloc and sm_free is a
+ function call and test. That overhead is sufficiently low that
+ the checking code can be left compiled in a production environment.
+<li>
+ If you do not define -DSM_HEAP_CHECK=0, and you explicitly turn on
+ heap checking at run time, then the additional cost of calling
+ sm_malloc, sm_realloc and sm_free is a hash table lookup.
+</ol>
+
+ Here's how to modify your application to use the heap package.
+ First, change all calls to malloc, realloc and free to sm_malloc,
+ sm_realloc and sm_free.
+ Make sure that there is a -d command line option that
+ uses the libsm debug package to enable named debug options.
+ Add the following code to your program just before it calls exit,
+ or register an atexit handler function containing the following code:
+
+<blockquote><pre>
+#if SM_HEAP_CHECK
+ /* dump the heap, if we are checking for memory leaks */
+ if (sm_debug_active(&SmHeapCheck, 2))
+ sm_heap_report(stdout, sm_debug_level(&SmHeapCheck) - 1);
+#endif
+</pre></blockquote>
+
+ To turn on heap checking, use the command line option "-dsm_check_heap.1".
+ This will cause a table of all currently allocated blocks to be
+ maintained. The table is used by sm_realloc and sm_free to perform
+ validity checking on the first argument.
+
+ <p>
+ The command line option "-dsm_check_heap.2" will cause your application
+ to invoke sm_heap_report with verbosity=1 just before exit.
+ That will print a single line reporting total storage allocation.
+
+ <p>
+ The command line option "-dsm_check_heap.3" will cause your application
+ to invoke sm_heap_report with verbosity=2 just before exit.
+ This will print a list of all leaked blocks.
+
+ <p>
+ The command line option "-dsm_check_heap.4" will cause your application
+ to invoke sm_heap_report with verbosity=3 just before exit.
+ This will print a list of all allocated blocks.
+
+<h2> Using sm_heap_register </h2>
+
+ Suppose you call a library routine foo that allocates a block of storage
+ for you using malloc, and expects you to free the block later using
+ free. Because the storage was not allocated using sm_malloc, you
+ will normally get an abort if you try to pass the pointer to
+ sm_free. The way to fix this problem is to 'register' the pointer
+ returned by foo with the heap package, by calling sm_heap_register:
+
+<blockquote><pre>
+bool sm_heap_register(ptr, size, file, line, group)
+</pre></blockquote>
+
+ The 'ptr' argument is the pointer returned by foo. The 'size' argument
+ can be smaller than the actual size of the allocated block, but it must
+ not be larger. The file and line arguments indicate at which line of
+ source code the block was allocated, and is printed by sm_heap_report.
+ For group, you probably want to pass sm_heap_group().
+ <p>
+ This function returns <tt>true</tt> on success,
+ or <tt>false</tt> if it failed due to heap exhaustion.
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/index.html b/gnu/usr.sbin/sendmail/libsm/index.html
new file mode 100644
index 00000000000..6753546dfde
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/index.html
@@ -0,0 +1,174 @@
+<html>
+<head>
+ <title>libsm Overview</title>
+</head>
+<body>
+
+<center>
+ <h1> libsm Overview </h1>
+ <br> $Sendmail: index.html,v 1.14 2001/02/13 21:21:25 gshapiro Exp $
+</center>
+
+<h2> Introduction </h2>
+
+Libsm is a library of generally useful C abstractions.
+Libsm stands alone; it depends on no other sendmail libraries,
+and the only sendmail header files it depends on are its own,
+which reside in <tt>../include/sm</tt>.
+
+<h2> Contents </h2>
+
+Here is the current set of packages:
+<blockquote>
+ <a href="gen.html"> gen: general definitions </a><br>
+ <a href="debug.html"> debug: debugging and tracing </a><br>
+ <a href="assert.html"> assert: assertion handling and aborts </a><br>
+ <a href="heap.html"> heap: memory allocation </a><br>
+ <a href="exc.html"> exc: exception handling </a><br>
+ <a href="rpool.html"> rpool: resource pools </a><br>
+ <a href="cdefs.html"> cdefs: C language portability macros </a><br>
+ <a href="io.html"> io: buffered i/o </a><br>
+</blockquote>
+
+<h2> Naming Conventions </h2>
+
+ Some of the symbols defined by libsm
+ come from widely used defacto or dejure standards.
+ Examples include <tt>size_t</tt> (from the C 89 standard),
+ <tt>bool</tt> (from the C 99 standard),
+ <tt>strerror</tt> (from Posix),
+ and <tt>__P</tt> (from BSD and Linux).
+ In these cases, we use the standard name rather than
+ inventing a new name.
+ We import the name from the appropriate header file when possible,
+ or define it ourselves when necessary.
+ When you are using one of these abstractions, you must include
+ the appropriate libsm header file.
+ For example, when you are using <tt>strerror</tt>, you must
+ include <tt>&lt;sm/string.h&gt;</tt> instead of <tt>&lt;string.h&gt;</tt>.
+
+ <p>
+ When we aren't implementing a standard interface,
+ we use a naming convention that attempts to maximize portability
+ across platforms, and minimize conflicts with other libraries.
+ Except for a few seemingly benign exceptions,
+ all names begin with <tt>SM_</tt>, <tt>Sm</tt> or <tt>sm_</tt>.
+
+ <p>
+ The ISO C, Posix and Unix standards forbid applications
+ from using names beginning with <tt>__</tt> or <tt>_[A-Z]</tt>,
+ and place restrictions on what sorts of names can begin
+ with <tt>_[a-z]</tt>. Such names are reserved for the compiler and
+ the standard libraries.
+ For this reason, we avoid defining any names that begin
+ with <tt>_</tt>.
+ For example, all libsm header file idempotency macros have the form
+ <tt>SM_FOO_H</tt> (no leading <tt>_</tt>).
+
+ <p>
+ Type names begin with <tt>SM_</tt> and end with <tt>_T</tt>.
+ Note that the Posix standard reserves all identifiers ending
+ with <tt>_t</tt>.
+
+ <p>
+ All functions that are capable of raising an exception
+ have names ending in <tt>_x</tt>, and developers are
+ encouraged to use this convention when writing new code.
+ This naming convention may seem unnecessary at first,
+ but it becomes extremely useful during maintenance,
+ when you are attempting to reason about the correctness
+ of a block of code,
+ and when you are trying to track down exception-related bugs
+ in existing code.
+
+<h2> Coding Conventions </h2>
+
+The official style for function prototypes in libsm header files is
+
+<blockquote><pre>
+extern int
+foo __P((
+ int _firstarg,
+ int _secondarg));
+</pre></blockquote>
+
+The <tt>extern</tt> is useless, but required for stylistic reasons.
+The parameter names are optional; if present they are lowercase
+and begin with _ to avoid namespace conflicts.
+Each parameter is written on its own line to avoid very long lines.
+
+<p>
+For each structure <tt>struct sm_foo</tt> defined by libsm,
+there is a typedef:
+
+<blockquote><pre>
+typedef struct sm_foo SM_FOO_T;
+</pre></blockquote>
+
+and there is a global variable which is defined as follows:
+
+<blockquote><pre>
+const char SmFooMagic[] = "sm_foo";
+</pre></blockquote>
+
+The first member of each structure defined by libsm is
+
+<blockquote><pre>
+const char *sm_magic;
+</pre></blockquote>
+
+For all instances of <tt>struct sm_foo</tt>,
+<tt>sm_magic</tt> contains <tt>SmFooMagic</tt>,
+which points to a unique character string naming the type.
+It is used for debugging and run time type checking.
+
+<p>
+Each function with a parameter declared <tt>SM_FOO_T *foo</tt>
+contains the following assertion:
+
+<blockquote><pre>
+SM_REQUIRE_ISA(foo, SmFooMagic);
+</pre></blockquote>
+
+which is equivalent to
+
+<blockquote><pre>
+SM_REQUIRE(foo != NULL && foo-&gt;sm_magic == SmFooMagic);
+</pre></blockquote>
+
+When an object of type <tt>SM_FOO_T</tt> is deallocated,
+the member <tt>sm_magic</tt> is set to <tt>NULL</tt>.
+That will cause the above assertion to fail if a dangling pointer is used.
+
+<h2> Additional Design Goals </h2>
+
+Here are some of my design goals:
+<ul>
+ <p>
+<li>The sm library is self contained; it does not depend on any other
+ sendmail libraries or header files.
+ <p>
+<li>The sm library must be compatible with shared libraries,
+ even on platforms with weird implementation restrictions.
+ I assume that a shared library can export global variables;
+ the debug package relies on this assumption.
+ I do not assume that if an application redefines a function defined
+ in a shared library, the shared library will use the version of the
+ function defined in the application in preference to the version
+ that it defines.
+ For this reason, I provide interfaces for registering handler functions
+ in cases where an application might need to override standard behaviour.
+ <p>
+<li>The sm library must be compatible with threads.
+ The debug package presents a small problem: I don't want
+ sm_debug_active to acquire and release a lock.
+ So I assume that
+ there exists an integral type <tt>SM_ATOMIC_INT_T</tt>
+ (see <a href="gen.html"><tt>&lt;sm/gen.h&gt;</tt></a>)
+ that can be accessed and updated atomically.
+ I assume that locking must be used to guard updates and accesses to
+ any other type, and I have designed the interfaces accordingly.
+</ul>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/io.html b/gnu/usr.sbin/sendmail/libsm/io.html
new file mode 100644
index 00000000000..c075ad04511
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/io.html
@@ -0,0 +1,745 @@
+<html>
+<head>
+<title>libsm sm_io general overview</title>
+</head>
+<body>
+<a href="index.html">Back to libsm overview</a>
+<center>
+<h1>libsm sm_io general overview</h1>
+<br> $Sendmail: io.html,v 1.3 2001/03/17 03:22:50 gshapiro Exp $
+</center>
+<h2> Introduction </h2>
+<p>
+The <i>sm_io</i> portion of the <i>libsm</i> library is similar to
+the <i>stdio</i> library. It is derived from the Chris Torek version
+of the <i>stdio</i> library (BSD). There are some key differences
+described below between <i>sm_io</i> and <i>stdio</i> but many
+similarities will be noticed.
+</p>
+<p>
+A key difference between <i>stdio</i> and <i>sm_io</i> is that the
+functional code that does the open, close, read, write, etc. on a file
+can be different for different files. For example, with <i>stdio</i>
+the functional code (read, write) is either the default supplied in the
+library or a "programmer specified" set of functions set via
+<i>sm_io_open()</i>. Whichever set of functions are specified <b>all</b>
+open's, read's, write's, etc use the same set of functions. In contrast, with
+<i>sm_io</i> a different set of functions can be specified with each
+active file for read's, write's, etc. These different function sets
+are identified as <b>file types</b> (see <tt>sm_io_open()</tt>). Each function
+set can handle the actions directly, pass the action request to
+another function set or do some work before passing it on to another function
+set. The setting of a function set for a file type can be done for
+a file type at any time (even after the type is open).
+</p>
+<p>
+A second difference is the use of <a href="rpool.html"><b>rpools</b></a>.
+An <b>rpool</b> is specified with the opening of a file
+(<tt>sm_io_open()</tt>).
+This allows of a file to be associated with an rpool so that when the
+rpool is released the open file will be closed; the <tt>sm_io_open()</tt>
+registers that <tt>sm_io_close()</tt> should be called when the rpool is
+released.
+</p>
+<p>
+A third difference is that the I/O functions take a <i>timeout</i>
+argument. This allows the setting of a maximum amount of time allowable
+for the I/O to be completed. This means the calling program does not need
+to setup it's own timeout mechanism. NOTE: SIGALRM's should not be
+active in the calling program when an I/O function with a <i>timeout</i>
+is used.
+</p>
+<p>
+When converting source code from <i>stdio</i> to <i>sm_io</i> be
+very careful to NOTE: the arguments to functions have been rationalized.
+That is, unlike <i>stdio</i>, all <i>sm_io</i> functions that
+take a file pointer (SM_FILE_T *) argument have the file pointer
+as the first argument. Also not all functions with <i>stdio</i> have
+an identical matching <i>sm_io</i> API: the API list has been thinned
+since a number of <i>stdio</i> API's overlapped in functionality.
+Remember many functions also have a <i>timeout</i> argument added.
+</p>
+<p>
+When a file is going to be opened, the file type is included with
+<tt>sm_io_open()</tt>.
+A file type is either one automatically included with the <i>sm_io</i>
+library or one created by the program at runtime.
+File types can be either buffered or unbuffered. When buffered the buffering
+is either the builtin <i>sm_io</i> buffering or as done by the file type.
+File types can be disk files, strings, TCP/IP connections or whatever
+your imagination can come up with that can be read and/or written to.
+</p>
+<p>
+Information about a particular file type or pointer can be obtained or set with
+the <i>sm_io</i> "info" functions.
+The <tt>sm_io_setinfo()</tt> and <tt>sm_io_getinfo()</tt> functions work on
+an active file pointer.
+</p>
+<h2>Include files</h2>
+<p>
+There is one main include file for use with sm_io: <i>io.h</i>. Since the
+use of <b>rpools</b> is specified with <tt>sm_io_open()</tt> an
+<b>rpool</b> may
+be created and thus <i>rpool.h</i> may need to be included as well
+(before io.h).
+</p>
+<pre>
+#include &lt;rpool.h&gt;
+#include &lt;io.h&gt;
+</pre>
+
+<h2>Functions/API's</h2>
+<p>
+Below is a list of the functions for <i>sm_io</i> listed in
+alphabetical order. Currently these functions return error codes
+and set errno when appropriate. These (may?/will?) change to
+raising exceptions later.
+</p>
+<pre>
+<a href="#sm_io_autoflush">SM_FILE_T *sm_io_autoflush(SM_FILE_T *fp, SM_FILE_T *)</a>
+
+<a href="#sm_io_automode">void sm_io_automode(SM_FILE_T *fp, SM_FILE_T *)</a>
+
+<a href="#defaultapi">void sm_io_clearerr(SM_FILE_T *fp)</a>
+
+<a href="#sm_io_close">int sm_io_close(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#defaultapi">int sm_io_dup(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_eof(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_error(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">char * sm_io_fgets(SM_FILE_T *fp, int timeout, char *buf, int n)</a>
+
+<a href="#defaultapi">int sm_io_flush(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#sm_io_fopen">int sm_io_fopen(char *pathname, int flags [, MODE_T mode])</a>
+
+<a href="#defaultapi">int sm_io_fprintf(SM_FILE_T *fp, int timeout, const char *fmt, ...)</a>
+
+<a href="#defaultapi">int sm_io_fputs(s, int, SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_fscanf(SM_FILE_T *fp, int timeout, char const *fmt, ...) </a>
+
+<a href="#defaultapi">int sm_io_getc(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#sm_io_getinfo">void sm_io_getinfo(SM_FILE_T *sfp, int what, void *valp)</a>
+
+<a href="#sm_io_open">SM_FILE_T * sm_io_open(SM_FILE_T type, int timeout, void *info, int flags, void *rpool)</a>
+
+<a href="#defaultapi">int sm_io_purge(SM_FILE_T *fp)</a>
+
+<a href="#defaultapi">int sm_io_putc(SM_FILE_T *fp, int timeout, int c)</a>
+
+<a href="#defaultapi">size_t sm_io_read(SM_FILE_T *fp, int timeout, char *buf, size_t size)</a>
+
+<a href="#sm_io_reopen">SM_FILE_T * sm_io_open(SM_FILE_T type, int timeout, void *info, int flags, void *rpool)</a>
+
+<a href="#defaultapi">void sm_io_rewind(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#defaultapi">int sm_io_seek(SM_FILE_T *fp, off_t offset, int timeout, int whence)</a>
+
+<a href="#sm_io_setinfo">void sm_io_setinfo(SM_FILE_T *sfp, int what, void *valp)</a>
+
+<a href="#defaultapi">int sm_io_setvbuf(SM_FILE_T *fp, int timeout, char *buf, int mode, size_t size)</a>
+
+<a href="#defaultapi">int sm_io_sscanf(const char *str, char const *fmt, ...)</a>
+
+<a href="#defaultapi">long sm_io_tell(SM_FILE_T *fp, int timeout)</a>
+
+<a href="#defaultapi">int sm_io_ungetc(SM_FILE_T *fp, int timeout, int c)</a>
+
+<a href="#defaultapi">size_t sm_io_write(SM_FILE_T *fp, int timeout, char *buf, size_t size)</a>
+
+<a href="#defaultapi">int sm_snprintf(char *str, size_t n, char const *fmt, ...)</a>
+
+</pre>
+<a name="timeouts">
+<h2>Timeouts</h2>
+<p>
+For many of the functions a <i>timeout</i> argument is given. This limits
+the amount of time allowed for the function to complete. There are three
+pre-defined values:
+<menu>
+<li>
+SM_TIME_DEFAULT - timeout using the default setting for this file type
+</li>
+<li>
+SM_TIME_FOREVER - timeout will take forever; blocks until task completed
+</li>
+<li>
+SM_TIME_IMMEDIATE - timeout (virtually) now
+</li>
+</menu>
+</p>
+<p>
+A function caller can also specify a positive integer value in milliseconds.
+A function will return with <i>errno</i> set to EINVAL if a bad value
+is given for <i>timeout</i>.
+When a function times out the function returns in error with <i>errno</i>
+set to <b>EAGAIN</b>. In the future this may change to an exception being
+thrown.
+</p>
+<h2>Function Descriptions</h2>
+<dl>
+<!-- SM_IO_FOPEN -->
+<p></p>
+<dt><tt><a name="sm_io_fopen">
+SM_FILE_T *
+<br>
+sm_io_fopen(char *pathname, int flags)
+<br>
+SM_FILE_T *
+<br>
+sm_io_fopen(char *pathname, int flags, MODE_T mode)
+</a></tt></dt>
+<dd>
+Open the file named by <tt>pathname</tt>, and associate a stream with it.
+The arguments are the same as for the <tt>open(2)</tt> system call.
+<br>
+If memory could not be allocated, an exception is raised.
+If successful, an <tt>SM_FILE_T</tt> pointer is returned.
+Otherwise, <tt>NULL</tt> is returned and <tt>errno</tt> is set.
+<!-- SM_IO_OPEN -->
+<p></p>
+<dt><tt><a name="sm_io_open">
+SM_FILE_T *
+<br>
+sm_io_open(const SM_FILE_T *type, int timeout, const void *info, int flags, void *rpool)
+</a></tt></dt>
+<dd>
+Opens a file by <i>type</i> directed by <i>info</i>. <i>Type</i> is a filled-in
+SM_FILE_T structure from the following builtin list
+(<a href="#builtins"><b>descriptions below</b></a>)
+or one specified by the program.
+<menu>
+<li>
+SmFtString
+</li>
+<li>
+SmFtStdio
+</li>
+<li>
+SmFtStdiofd
+</li>
+<li>
+smioin <b>*</b>
+</li>
+<li>
+smioout <b>*</b>
+</li>
+<li>
+smioerr <b>*</b>
+</li>
+<li>
+smiostdin <b>*</b>
+</li>
+<li>
+smiostdout <b>*</b>
+</li>
+<li>
+smiostderr <b>*</b>
+</li>
+<li>
+SmFtSyslog
+</li>
+</menu>
+<br>
+The above list of file types are already appropriately filled in. Those marked
+with a "<b>*</b>" are already open and may be used directly and immediately.
+For program specified types, to set the <i>type</i> argument easily and with minimal error the macro
+<b>SM_IO_SET_TYPE</b> should be used. The SM_FILE_T structure is fairly
+large, but only a small portion of it need to be initialized for a new
+type.
+See also <a href="#writefunctions">"Writing Functions for a File Type"</a>.
+<menu>
+<pre>
+SM_IO_SET_TYPE(type, name, open, close, read, write, seek, get, set, timeout)
+</pre>
+</menu>
+<br>
+<i>Timeout</i> is set as described in the <a href="#timeouts"><b>Timeouts</b></a>
+section.
+<br>
+<i>Info</i> is information that describes for the file type what is
+to be opened and any associated information.
+For a disk file this would be a file path; with a TCP
+connection this could be an a structure containing an IP address and port.
+<br><i>Flags</i> is a
+set of sm_io flags that describes how the file is to be interacted with:
+<menu>
+<li>
+SM_IO_RDWR - read and write
+</li>
+<li>
+SM_IO_RDONLY - read only
+</li>
+<li>
+SM_IO_WRONLY - write only
+</li>
+<li>
+SM_IO_APPEND - allow write to EOF only
+</li>
+<li>
+SM_IO_APPENDRW - allow read-write from EOF only
+</li>
+<li>
+SM_IO_RDWRTR - read and write with truncation of file first
+</li>
+</menu>
+<i>Rpool</i> is the address of the rpool that this open is to be associated
+with. When the rpool is released then the close function for this
+file type will be automatically called to close the file for cleanup.
+If NULL is specified for <i>rpool</i> then the close function is not
+associated (attached) to an rpool.
+<br>
+On cannot allocate memory, an exception is raised.
+If the <i>type</i> is invalid, <tt>sm_io_open</tt> will abort the process.
+On success an SM_FILE_T * pointer is returned.
+On failure the NULL pointer is returned and errno is set.
+</dd>
+<!-- SM_IO_SETINFO -->
+<p></p>
+<dt><tt><a name="sm_io_setinfo">
+int
+<br>
+sm_io_setinfo(SM_FILE_T *sfp, int what, void *valp)
+</a></tt></dt>
+<dd>
+For the open file <i>sfp</i> set the indicated information (<i>what</i>)
+to the new value <i>(valp</i>).
+This will make the change for this SM_FILE_T only. The file
+type that <i>sfp</i> originally belonged to will still be
+configured the same way (this is to prevent side-effect
+to other open's of the same file type, particularly with threads).
+The value of <i>what</i> will be file-type dependant since this function
+is one of the per file type setable functions.
+One value for <i>what</i> that is valid for all file types is
+SM_WHAT_VECTORS. This sets the currently open file with a new function
+vector set for open, close, etc. The new values are taken from <i>valp</i>
+a SM_FILE_T filled in by the used via the macro SM_IO_SET_TYPE
+(see and <a href="#writefunctions">
+"Writing Functions for a File Type"</a> for more information).
+<br>
+On success 0 (zero) is returned. On failure -1 is returned and errno is set.
+</dd>
+<!-- SM_IO_GETINFO -->
+<p></p>
+<dt><tt><a name="sm_io_getinfo">
+int
+<br>
+sm_io_getinfo(SM_FILE_T *sfp, int what, void *valp)
+</a></tt></dt>
+<dd>
+For the open file <i>sfp</i> get the indicated information (<i>what</i>)
+and place the result in <i>(valp</i>).
+This will obtain information for SM_FILE_T only and may be different than
+the information for the file type it was originally opened as.
+The value of <i>what</i> will be file type dependant since this function
+is one of the per file type setable functions.
+One value for <i>what</i> that is valid for all file types is
+SM_WHAT_VECTORS. This gets from the currently open file a copy of
+the function vectors and stores them in <i>valp</i> a SM_FILE_T
+(see <a href="#writefunctions">
+"Writing Functions for a File Type"</a> for more information).
+<br>
+On success 0 (zero) is returned. On failure -1 is returned and errno is set.
+</dd>
+<!-- SM_IO_AUTOFLUSH -->
+<p></p>
+<dt><tt><a name="sm_io_autoflush">
+void
+<br>
+sm_io_autoflush(SM_FILE_T *fp1, *SM_FILE_T fp2)
+</a></tt></dt>
+<dd>
+Associate a read of <i>fp1</i> with a data flush for <i>fp2</i>. If a read
+of <i>fp1</i> discovers that there is no data available to be read, then
+<i>fp2</i> will have it's data buffer flushed for writable data. It is
+assumed that <i>fp1</i> is open for reading and <i>fp2</i> is open
+for writing.
+<br>
+On return the old file pointer associated with <i>fp1</i> for flushing
+is returned. A return of NULL is no an error; this merely indicates no
+previous association.
+</dd>
+<!-- SM_IO_AUTOMODE -->
+<p></p>
+<dt><tt><a name="sm_io_automode">
+void
+<br>
+sm_io_automode(SM_FILE_T *fp1, *SM_FILE_T fp2)
+<dt><tt><a name="sm_io_automode">
+</a></tt></dt>
+<dd>
+Associate the two file pointers for blocking/non-blocking mode changes.
+In the handling of timeouts <i>sm_io</i> may need to switch the mode of
+a file between blocking and non-blocking. If the underlying file descriptor
+has been duplicated with <tt>dup(2)</tt> and these descriptors are used
+by <i>sm_io</i> (for example with an SmFtStdiofd file type), then this API
+should be called to associate them. Otherwise odd behavior (i.e. errors)
+may result that is not consistently reproducable nor easily identifiable.
+</dd>
+<!-- SM_IO_CLOSE -->
+<p></p>
+<dt><tt><a name="sm_io_close">
+int
+<br>
+sm_io_close(SM_FILE_T *sfp, int timeout)
+</a></tt></dt>
+<dd>
+Release all resources (file handles, memory, etc.) associated with
+the open SM_FILE_T <i>sfp</i>. If buffering is active then the
+buffer is flushed before any resources are released.
+<i>Timeout</i> is set as described in the <a href="#timeouts"><b>Timeouts</b></a>
+section.
+The first resources released after buffer flushing will be the
+buffer itself. Then the <b>close</b> function specified in the
+file type at open will be called. It is the responsibility
+of the <b>close</b> function to release any file type
+specific resources allocated and to call <tt>sm_io_close()</tt>
+for the next file type layer(s) that the current file type uses (if any).
+<br>
+On success 0 (zero) is returned. On failure SM_IO_EOF is returned and
+errno is set.
+</dd>
+</dl>
+<h2>
+<a name="builtins">Description of Builtin File Types</a>
+</h2>
+<p>
+There are several builtin file types as mentioned in <tt>sm_io_open()</tt>.
+More file types may be added later.
+</p>
+<dl>
+<p></p>
+<dt><tt>SmFtString</tt></dt>
+<dd>
+Operates on a character string. <i>SmFtString</i> is a file type only.
+The string starts at the location 0 (zero)
+and ends at the last character. A read will obtain the requested
+number of characters if available; else as many as possible. A read
+will not terminate the read characters with a NULL ('\0'). A write
+will place the number of requested characters at the current location.
+To append to a string either the pointer must currently be at the end
+of the string or a seek done to position the pointer. The file type
+handles the space needed for the string. Thus space needed for the
+string will be grown automagically without the user worrying about
+space management.
+</dd>
+<dt><tt>SmFtStdio</tt></dt>
+<dd>
+A predefined SM_FILE_T structure with function vectors pointing to
+functions that result in the file-type behaving as the system stdio
+normally does. The <i>info</i> portion of the <tt>sm_io_open</tt>
+is the path of the file to be opened. Note that this file type
+does not interact with the system's stdio. Thus a program mixing system
+stdio and sm_io stdio (SmFtStdio) will result in uncoordinated input
+and output.
+</dd>
+<dt><tt>SmFtStdiofd</tt></dt>
+<dd>
+A predefined SM_FILE_T structure with function vectors pointing to
+functions that result in the file-type behaving as the system stdio
+normally does. The <i>info</i> portion of the <tt>sm_io_open</tt>
+is a file descriptor (the value returned by open(2)). Note that this file type
+does not interact with the system's stdio. Thus a program mixing system
+stdio and sm_io stdio (SmFtStdio) will result in uncoordinated input
+and output.
+</dd>
+<dt><tt>smioin</tt></dt>
+<dt><tt>smioout</tt></dt>
+<dt><tt>smioerr</tt></dt>
+<dd>
+The three types <i>smioin</i>, <i>smioout</i> and <i>smioerr</i> are grouped
+together. These three types
+perform in the same manner as <b>stdio</b>'s <i>stdin</i>, <i>stdout</i>
+and <i>stderr</i>. These types are both the names and the file pointers.
+They are already open when a program starts (unless the parent explictly
+closed file descriptors 0, 1 and 2).
+Thus <tt>sm_io_open()</tt> should never be called for these types:
+the named file pointers should be used directly.
+<i>Smioin</i> and <i>smioout</i> are buffered
+by default. <i>Smioerr</i> is not buffered by default. Calls to <b>stdio</b>
+are safe to make when using these three<b>sm_io</b> file pointers.
+There is no interaction between <b>sm_io</b> and <b>stdio</b>. Hence,
+due to buffering, the sequence of input and output data from both <b>sm_io</b>
+and <b>stdio</b> at the same time may appear unordered. For
+coordination between <b>sm_io</b> and <b>stdio</b> use the three
+file pointers below (<i>smiostdin, smiostdout, smiostderr</i>).
+</dd>
+<dt><tt>smiostdin</tt></dt>
+<dt><tt>smiostdout</tt></dt>
+<dt><tt>smiostderr</tt></dt>
+<dd>
+The three types <i>smiostdin</i>, <i>smioostdut</i> and <i>smiostderr</i>
+are grouped together. These three types
+perform in the same manner as <b>stdio</b>'s <i>stdin</i>, <i>stdout</i>
+and <i>stderr</i>. These types are both the names and file pointers.
+They are already open when a program starts (unless the parent explictly
+close file descriptors 0, 1 and 2).
+Thus <tt>sm_io_open()</tt> should
+never be called: the named file pointers should be used directly.
+Calls to <b>stdio</b> are safe to make when using these three<b>sm_io</b>
+file pointers though no code is shared between the two libaries.
+However, the input and output between <i>sm_io</i> and <i>stdio</i> is
+coordinated for these three file pointers: <i>smiostdin</i>,
+<i>smiostdout</i> and <i>smiostderr</i> are layered on-top-of
+the system's <i>stdio</i>.
+<i>Smiostdin</i>, <i>smiostdout</i>
+and <i>Smiostderr</i> are not buffered by default.
+Hence, due to buffering in <i>stdio</i> only, the sequence of input and
+output data from both <b>sm_io</b> and <b>stdio</b> at the same time will
+appear ordered. If <i>sm_io</i> buffering is turned on then the
+input and output can appear unordered or lost.
+</dd>
+<dt><tt>SmFtSyslog</tt></dt>
+<dd>
+This opens the channel to the system log. Reads are not allowed. Writes
+cannot be undone once they have left the <i>sm_io</i> buffer.
+The man pages for <tt>syslog(3)</tt> should be read for information
+on syslog.
+</dd>
+</dl>
+<p></p>
+<hr>
+<p></p>
+<h2>
+<a name="writefunctions">
+Writing Functions for a File Type
+</a>
+</h2>
+<p>
+When writing functions to create a file type a function needs to
+be created for each function vector in the SM_FILE_T structure
+that will be passed to <tt>sm_io_open()</tt> or <tt>sm_io_setinfo()</tt>.
+Otherwise the setting will be rejected and <i>errno</i> set to EINVAL.
+Each function should accept and handle the number and types of arguments as
+described in the portion of the SM_FILE_T structure shown below:
+</p>
+<pre>
+ int (*open) __P((SM_FILE_T *fp, const void *, int flags,
+ const void *rpool));
+ int (*close) __P((SM_FILE_T *fp));
+ int (*read) __P((SM_FILE_T *fp, char *buf, size_t size));
+ int (*write) __P((SM_FILE_T *fp, const char *buf, size_t size));
+ off_t (*seek) __P((SM_FILE_T *fp, off_t offset, int whence));
+ int (*getinfo) __P((SM_FILE_T *fp, int what, void *valp));
+ int (*setinfo) __P((SM_FILE_T *fp, int what, void *valp));
+</pre>
+<p>
+The macro SM_IO_SET_TYPE should be used to initialized an SM_FILE_T as a file
+type for an <tt>sm_io_open()</tt>:
+<menu>
+<pre>
+SM_IO_SET_TYPE(type, name, open, close, read, write, seek, get, set, timeout)
+</pre>
+<br>
+where:
+<menu>
+<li>
+type - is the SM_FILE_T being filled-in
+</li>
+<li>
+name - a human readable character string for human identification purposes
+</li>
+<li>
+open - the vector to the open function
+</li>
+<li>
+close - the vector to the close function
+</li>
+<li>
+read - the vector to the read function
+</li>
+<li>
+write - the vector to the write function
+</li>
+<li>
+seek - the vector to the seek function
+</li>
+<li>
+set - the vector to the set function
+</li>
+<li>
+get - the vector to the get function
+</li>
+<li>
+timeout - the default to be used for a timeout when SM_TIME_DEFAULT specified
+</li>
+</menu>
+</menu>
+You should avoid trying to change or use the other structure members of the
+SM_FILE_T. The file pointer content (internal structure members) of an active
+file should only be set and observed with the "info" functions.
+The two exceptions to the above statement are the structure members
+<i>cookie</i> and <i>ival</i>. <i>Cookie</i> is of type <tt>void *</tt>
+while <i>ival</i> is of type <tt>int</tt>. These two structure members exist
+specificly for your created file type to use. The <i>sm_io</i> functions
+will not change or set these two structure members; only specific file type
+will change or set these variables.
+</p>
+<p>
+For maintaining information privately about status for a file type the
+information should be encapsulated in a <i>cookie</i>. A <i>cookie</i>
+is an opaque type that contains information that is only known to
+the file type layer itself. The <i>sm_io</i> package will know
+nothing about the contents of the <i>cookie</i>; <i>sm_io</i> only
+maintains the location of the <i>cookie</i> so that it may be passed
+to the functions of a file type. It is up to the file type to
+determine what to do with the <i>cookie</i>. It is the responsibility
+of the file type's open to create the cookie and point the SM_FILE_T's
+<i>cookie</i> at the address of the cookie.
+It is the responsibility of close to clean up
+any resources that the cookie and instance of the file type have used.
+</p>
+<p>
+For the <i>cookie</i> to be passed to all members of a function type
+cleanly the location of the cookie must assigned during
+the call to open. The file type functions should not attempt to
+maintain the <i>cookie</i> internally since the file type may have
+serveral instances (file pointers).
+</p>
+<p>
+The SM_FILE_T's member <i>ival</i> may be used in a manner similar to
+<i>cookie</i>. It is not to be used for maintaining the file's offset
+or access status (other members do that). It is intended as a "light"
+reference.
+</p>
+<p>
+The file type vector functions are called by the <tt>sm_io_*()</tt>
+functions after <i>sm_io</i> processing has occurred. The <i>sm_io</i>
+processing validates SM_FILE_T's and may then handle the call entirely
+itself or pass the request to the file type vector functions.
+</p>
+<p>
+All of the "int" functions should return -1 (minus one) on failure
+and 0 (zero) or greater on success. <i>Errno</i> should be set to
+provide diagnostic information to the caller if it has not already
+been set by another function the file type function used.
+</p>
+<p>
+Examples are a wonderful manner of clarifying details. Below is an example
+of an open function.
+</p>
+<p>
+This shows the setup.
+<menu>
+<pre>
+SM_FILE_T *fp;
+SM_FILE_T SM_IO_SET_TYPE(vector, "my_type", myopen, myclose, myread, mywrite,
+ myseek, myget, myset, SM_TIME_FOREVER);
+
+fp = sm_io_open(&vector, 1000, "data", SM_IO_RDONLY, NULL);
+
+if (fp == NULL)
+ return(-1);
+</pre>
+The above code open's a file of type "my_type". The <i>info</i> is set
+to a string "data". "data" may be the name of a file or have some special
+meaning to the file type. For sake of the example, we will have it be
+the name of a file in the home directory of the user running the program.
+Now the only file type function that is dependent on this information
+will be the open function.
+<br>
+We have also specified read-only access (SM_IO_RDONLY) and that no <i>rpool</i>
+will be used. The <i>timeout</i> has been set to 1000 milliseconds which
+directs that the file and all associated setup should be done within
+1000 milliseconds or return that the function erred (with errno==EAGAIN).
+<pre>
+int myopen(fp, info, flags, rpools)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ void *rpool;
+{
+ /*
+ ** now we could do the open raw (i.e with read(2)), but we will
+ ** use file layering instead. We will use the <i>stdio</i> file
+ ** type (different than the system's stdio).
+ */
+ struct passwd *pw;
+ char path[PATH_MAX];
+
+ pw = getpwuid(getuid());
+ sm_io_snprintf(path, PATH_MAX, "%s/%s", pw->pw_dir, info);
+
+ /*
+ ** Okay. Now the path pass-in has been prefixed with the
+ ** user's HOME directory. We'll call the regular stdio (SmFtStdio)
+ ** now to handle the rest of the open.
+ */
+ fp->cookie = sm_io_open(SmFtStdio, path, flags, rpools);
+ if (fp->cookie == NULL)
+ return(-1) /* errno set by sm_io_open call */
+ else
+ return(0);
+}
+</pre>
+Later on when a write is performed the function <tt>mywrite</tt> will
+be invoked. To match the above <tt>myopen</tt>, <tt>mywrite</tt> could
+be written as:
+<pre>
+int mywrite(fp, buf, size)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t size;
+{
+ /*
+ ** As an example, we can change, modify, refuse, filter, etc.
+ ** the content being passed through before we ask the SmFtStdio
+ ** to do the actual write.
+ ** This example is very simple and contrived, but this keeps it
+ ** clear.
+ */
+ if (size == 0)
+ return(0); /* why waste the cycles? */
+ if (*buf == 'X')
+ *buf = 'Y';
+
+ /*
+ ** Note that the file pointer passed to the next level is the
+ ** one that was stored in the cookie during the open.
+ */
+ return(sm_io_write(fp->cookie, buf, size));
+}
+</pre>
+As a thought-exercise for the fair reader: how would you modify the
+above two functions to make a "tee". That is the program will call
+<tt>sm_io_open</tt> or <tt>sm_io_write</tt> and two or more files will
+be opened and written to. (Hint: create a cookie to hold two or more
+file pointers).
+</menu>
+</p>
+<p></p>
+<hr>
+<br>
+<hr>
+<p></p>
+<center>
+<h1>
+<a name="defaultapi">
+libsm sm_io default API definition
+</a>
+</h1>
+</center>
+<h2> Introduction </h2>
+<p>
+A number of <i>sm_io</i> API's perform similar to their <i>stdio</i>
+counterparts (same name as when the "sm_io_" is removed).
+One difference between <i>sm_io</i> and <i>stdio</i> functions is that
+if a "file pointer" (FILE/SM_FILE_T)
+is one of the arguments for the function, then it is now the first
+argument. <i>Sm_io</i> is standardized so that when a file pointer is
+one of the arguments to function then it will always be the first
+arguement. Many of the <i>sm_io</i> function take a <i>timeout</i>
+argument (see <a href="#timeouts"><b>Timeouts</b></a>).
+</p>
+<p>
+The API you have selected is one of these. Please consult the
+appropriate <i>stdio</i> man page for now.
+</p>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/ldap.c b/gnu/usr.sbin/sendmail/libsm/ldap.c
new file mode 100644
index 00000000000..2c92bce45ee
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/ldap.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: ldap.c,v 1.8 2001/06/06 00:09:47 gshapiro Exp $")
+
+#if LDAPMAP
+# include <sys/types.h>
+# include <errno.h>
+# include <setjmp.h>
+# include <stdlib.h>
+# include <unistd.h>
+
+# include <sm/bitops.h>
+# include <sm/clock.h>
+# include <sm/conf.h>
+# include <sm/debug.h>
+# include <sm/errstring.h>
+# include <sm/ldap.h>
+# include <sm/string.h>
+
+SM_DEBUG_T SmLDAPTrace = SM_DEBUG_INITIALIZER("sm_trace_ldap",
+ "@(#)$Debug: sm_trace_ldap - trace LDAP operations $");
+
+static void ldaptimeout __P((int));
+
+/*
+** SM_LDAP_CLEAR -- set default values for SM_LDAP_STRUCT
+**
+** Parameters:
+** lmap -- pointer to SM_LDAP_STRUCT to clear
+**
+** Returns:
+** None.
+**
+*/
+
+void
+sm_ldap_clear(lmap)
+ SM_LDAP_STRUCT *lmap;
+{
+ if (lmap == NULL)
+ return;
+
+ lmap->ldap_host = NULL;
+ lmap->ldap_port = LDAP_PORT;
+ lmap->ldap_deref = LDAP_DEREF_NEVER;
+ lmap->ldap_timelimit = LDAP_NO_LIMIT;
+ lmap->ldap_sizelimit = LDAP_NO_LIMIT;
+# ifdef LDAP_REFERRALS
+ lmap->ldap_options = LDAP_OPT_REFERRALS;
+# else /* LDAP_REFERRALS */
+ lmap->ldap_options = 0;
+# endif /* LDAP_REFERRALS */
+ lmap->ldap_attrsep = '\0';
+ lmap->ldap_binddn = NULL;
+ lmap->ldap_secret = NULL;
+ lmap->ldap_method = LDAP_AUTH_SIMPLE;
+ lmap->ldap_base = NULL;
+ lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
+ lmap->ldap_attrsonly = LDAPMAP_FALSE;
+ lmap->ldap_timeout.tv_sec = 0;
+ lmap->ldap_timeout.tv_usec = 0;
+ lmap->ldap_ld = NULL;
+ lmap->ldap_filter = NULL;
+ lmap->ldap_attr[0] = NULL;
+ lmap->ldap_res = NULL;
+ lmap->ldap_next = NULL;
+ lmap->ldap_pid = 0;
+}
+
+/*
+** SM_LDAP_START -- actually connect to an LDAP server
+**
+** Parameters:
+** name -- name of map for debug output.
+** lmap -- the LDAP map being opened.
+**
+** Returns:
+** true if connection is successful, false otherwise.
+**
+** Side Effects:
+** Populates lmap->ldap_ld.
+*/
+
+static jmp_buf LDAPTimeout;
+
+#define SM_LDAP_SETTIMEOUT(to) \
+do \
+{ \
+ if (to != 0) \
+ { \
+ if (setjmp(LDAPTimeout) != 0) \
+ { \
+ errno = ETIMEDOUT; \
+ return false; \
+ } \
+ ev = sm_setevent(to, ldaptimeout, 0); \
+ } \
+} while (0)
+
+#define SM_LDAP_CLEARTIMEOUT() \
+do \
+{ \
+ if (ev != NULL) \
+ sm_clrevent(ev); \
+} while (0)
+
+bool
+sm_ldap_start(name, lmap)
+ char *name;
+ SM_LDAP_STRUCT *lmap;
+{
+ int bind_result;
+ int save_errno;
+ SM_EVENT *ev = NULL;
+ LDAP *ld;
+
+ if (sm_debug_active(&SmLDAPTrace, 2))
+ sm_dprintf("ldapmap_start(%s)\n", name == NULL ? "" : name);
+
+ if (sm_debug_active(&SmLDAPTrace, 9))
+ sm_dprintf("ldapmap_start(%s, %d)\n",
+ lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
+ lmap->ldap_port);
+
+# if USE_LDAP_INIT
+ ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
+ save_errno = errno;
+# else /* USE_LDAP_INIT */
+ /*
+ ** If using ldap_open(), the actual connection to the server
+ ** happens now so we need the timeout here. For ldap_init(),
+ ** the connection happens at bind time.
+ */
+
+ SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
+ ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
+ save_errno = errno;
+
+ /* clear the event if it has not sprung */
+ SM_LDAP_CLEARTIMEOUT();
+# endif /* USE_LDAP_INIT */
+
+ errno = save_errno;
+ if (ld == NULL)
+ return false;
+
+ sm_ldap_setopts(ld, lmap);
+
+# if USE_LDAP_INIT
+ /*
+ ** If using ldap_init(), the actual connection to the server
+ ** happens at ldap_bind_s() so we need the timeout here.
+ */
+
+ SM_LDAP_SETTIMEOUT(lmap->ldap_timeout.tv_sec);
+# endif /* USE_LDAP_INIT */
+
+# ifdef LDAP_AUTH_KRBV4
+ if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
+ lmap->ldap_secret != NULL)
+ {
+ /*
+ ** Need to put ticket in environment here instead of
+ ** during parseargs as there may be different tickets
+ ** for different LDAP connections.
+ */
+
+ (void) putenv(lmap->ldap_secret);
+ }
+# endif /* LDAP_AUTH_KRBV4 */
+
+ bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
+ lmap->ldap_secret, lmap->ldap_method);
+
+# if USE_LDAP_INIT
+ /* clear the event if it has not sprung */
+ SM_LDAP_CLEARTIMEOUT();
+# endif /* USE_LDAP_INIT */
+
+ if (bind_result != LDAP_SUCCESS)
+ {
+ errno = bind_result + E_LDAPBASE;
+ return false;
+ }
+
+ /* Save PID to make sure only this PID closes the LDAP connection */
+ lmap->ldap_pid = getpid();
+ lmap->ldap_ld = ld;
+ return true;
+}
+
+/* ARGSUSED */
+static void
+ldaptimeout(unused)
+ int unused;
+{
+ /*
+ ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+ ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+ ** DOING.
+ */
+
+ errno = ETIMEDOUT;
+ longjmp(LDAPTimeout, 1);
+}
+
+/*
+** SM_LDAP_SEARCH -- iniate LDAP search
+**
+** Initiate an LDAP search, return the msgid.
+** The calling function must collect the results.
+**
+** Parameters:
+** lmap -- LDAP map information
+** key -- key to substitute in LDAP filter
+**
+** Returns:
+** -1 on failure, msgid on success
+**
+*/
+
+int
+sm_ldap_search(lmap, key)
+ SM_LDAP_STRUCT *lmap;
+ char *key;
+{
+ int msgid;
+ char *fp, *p, *q;
+ char filter[LDAPMAP_MAX_FILTER + 1];
+
+ /* substitute key into filter, perhaps multiple times */
+ memset(filter, '\0', sizeof filter);
+ fp = filter;
+ p = lmap->ldap_filter;
+ while ((q = strchr(p, '%')) != NULL)
+ {
+ if (q[1] == 's')
+ {
+ (void) sm_snprintf(fp, SPACELEFT(filter, fp),
+ "%.*s%s", (int) (q - p), p, key);
+ fp += strlen(fp);
+ p = q + 2;
+ }
+ else if (q[1] == '0')
+ {
+ char *k = key;
+
+ (void) sm_snprintf(fp, SPACELEFT(filter, fp),
+ "%.*s", (int) (q - p), p);
+ fp += strlen(fp);
+ p = q + 2;
+
+ /* Properly escape LDAP special characters */
+ while (SPACELEFT(filter, fp) > 0 &&
+ *k != '\0')
+ {
+ if (*k == '*' || *k == '(' ||
+ *k == ')' || *k == '\\')
+ {
+ (void) sm_strlcat(fp,
+ (*k == '*' ? "\\2A" :
+ (*k == '(' ? "\\28" :
+ (*k == ')' ? "\\29" :
+ (*k == '\\' ? "\\5C" :
+ "\00")))),
+ SPACELEFT(filter, fp));
+ fp += strlen(fp);
+ k++;
+ }
+ else
+ *fp++ = *k++;
+ }
+ }
+ else
+ {
+ (void) sm_snprintf(fp, SPACELEFT(filter, fp),
+ "%.*s", (int) (q - p + 1), p);
+ p = q + (q[1] == '%' ? 2 : 1);
+ fp += strlen(fp);
+ }
+ }
+ (void) sm_strlcpy(fp, p, SPACELEFT(filter, fp));
+ if (sm_debug_active(&SmLDAPTrace, 20))
+ sm_dprintf("ldap search filter=%s\n", filter);
+
+ lmap->ldap_res = NULL;
+ msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
+ filter,
+ (lmap->ldap_attr[0] == NULL ? NULL :
+ lmap->ldap_attr),
+ lmap->ldap_attrsonly);
+ return msgid;
+}
+
+/*
+** SM_LDAP_CLOSE -- close LDAP connection
+**
+** Parameters:
+** lmap -- LDAP map information
+**
+** Returns:
+** None.
+**
+*/
+
+void
+sm_ldap_close(lmap)
+ SM_LDAP_STRUCT *lmap;
+{
+ if (lmap->ldap_ld == NULL)
+ return;
+
+ if (lmap->ldap_pid == getpid())
+ ldap_unbind(lmap->ldap_ld);
+ lmap->ldap_ld = NULL;
+ lmap->ldap_pid = 0;
+}
+
+/*
+** SM_LDAP_SETOPTS -- set LDAP options
+**
+** Parameters:
+** ld -- LDAP session handle
+** lmap -- LDAP map information
+**
+** Returns:
+** None.
+**
+*/
+
+void
+sm_ldap_setopts(ld, lmap)
+ LDAP *ld;
+ SM_LDAP_STRUCT *lmap;
+{
+# if USE_LDAP_SET_OPTION
+ ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
+ if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
+ ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
+ else
+ ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+ ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
+ ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
+# else /* USE_LDAP_SET_OPTION */
+ /* From here on in we can use ldap internal timelimits */
+ ld->ld_deref = lmap->ldap_deref;
+ ld->ld_options = lmap->ldap_options;
+ ld->ld_sizelimit = lmap->ldap_sizelimit;
+ ld->ld_timelimit = lmap->ldap_timelimit;
+# endif /* USE_LDAP_SET_OPTION */
+}
+
+/*
+** SM_LDAP_GETERRNO -- get ldap errno value
+**
+** Parameters:
+** ld -- LDAP session handle
+**
+** Returns:
+** LDAP errno.
+**
+*/
+
+int
+sm_ldap_geterrno(ld)
+ LDAP *ld;
+{
+ int err = LDAP_SUCCESS;
+
+# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
+ (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
+# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
+# ifdef LDAP_OPT_SIZELIMIT
+ err = ldap_get_lderrno(ld, NULL, NULL);
+# else /* LDAP_OPT_SIZELIMIT */
+ err = ld->ld_errno;
+
+ /*
+ ** Reset value to prevent lingering LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see above)
+ */
+
+ ld->ld_errno = LDAP_SUCCESS;
+# endif /* LDAP_OPT_SIZELIMIT */
+# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
+ return err;
+}
+# endif /* LDAPMAP */
diff --git a/gnu/usr.sbin/sendmail/libsm/local.h b/gnu/usr.sbin/sendmail/libsm/local.h
new file mode 100644
index 00000000000..47afd0cf251
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/local.h
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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.
+ *
+ * $Sendmail: local.h,v 1.48 2001/05/14 20:42:29 gshapiro Exp $
+ */
+
+/*
+** Information local to this implementation of stdio,
+** in particular, macros and private variables.
+*/
+
+#include <sys/time.h>
+#if !SM_CONF_MEMCHR
+# include <memory.h>
+#endif /* !SM_CONF_MEMCHR */
+#include <sm/heap.h>
+
+int sm_flush __P((SM_FILE_T *, int *));
+SM_FILE_T *smfp __P((void));
+int sm_refill __P((SM_FILE_T *, int));
+void sm_init __P((void));
+void sm_cleanup __P((void));
+void sm_makebuf __P((SM_FILE_T *));
+int sm_whatbuf __P((SM_FILE_T *, size_t *, int *));
+int sm_fwalk __P((int (*)(SM_FILE_T *, int *), int *));
+int sm_wsetup __P((SM_FILE_T *));
+int sm_flags __P((int));
+SM_FILE_T *sm_fp __P((const SM_FILE_T *, const int, SM_FILE_T *));
+int sm_vprintf __P((int, char const *, va_list));
+int sm_vfscanf __P((SM_FILE_T *, int, char const *, va_list));
+
+/* std io functions */
+ssize_t sm_stdread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_stdwrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_stdseek __P((SM_FILE_T *, off_t, int));
+int sm_stdclose __P((SM_FILE_T *));
+int sm_stdopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_stdfdopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_stdsetinfo __P((SM_FILE_T *, int , void *));
+int sm_stdgetinfo __P((SM_FILE_T *, int , void *));
+
+/* stdio io functions */
+ssize_t sm_stdioread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_stdiowrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_stdioseek __P((SM_FILE_T *, off_t, int));
+int sm_stdioclose __P((SM_FILE_T *));
+int sm_stdioopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_stdiosetinfo __P((SM_FILE_T *, int , void *));
+int sm_stdiogetinfo __P((SM_FILE_T *, int , void *));
+
+/* string io functions */
+ssize_t sm_strread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_strwrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_strseek __P((SM_FILE_T *, off_t, int));
+int sm_strclose __P((SM_FILE_T *));
+int sm_stropen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_strsetinfo __P((SM_FILE_T *, int , void *));
+int sm_strgetinfo __P((SM_FILE_T *, int , void *));
+
+/* syslog io functions */
+ssize_t sm_syslogread __P((SM_FILE_T *, char *, size_t));
+ssize_t sm_syslogwrite __P((SM_FILE_T *, char const *, size_t));
+off_t sm_syslogseek __P((SM_FILE_T *, off_t, int));
+int sm_syslogclose __P((SM_FILE_T *));
+int sm_syslogopen __P((SM_FILE_T *, const void *, int, const void *));
+int sm_syslogsetinfo __P((SM_FILE_T *, int , void *));
+int sm_sysloggetinfo __P((SM_FILE_T *, int , void *));
+
+/* should be defined in sys/time.h */
+#ifndef timersub
+# define timersub(tvp, uvp, vvp) \
+ do \
+ { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) \
+ { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* !timersub */
+
+#ifndef timeradd
+# define timeradd(tvp, uvp, vvp) \
+ do \
+ { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) \
+ { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#endif /* !timeradd */
+
+#ifndef timercmp
+# define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#endif /* !timercmp */
+
+extern bool Sm_IO_DidInit;
+
+/* Return true iff the given SM_FILE_T cannot be written now. */
+#define cantwrite(fp) \
+ ((((fp)->f_flags & SMWR) == 0 || (fp)->f_bf.smb_base == NULL) && \
+ sm_wsetup(fp))
+
+/*
+** Test whether the given stdio file has an active ungetc buffer;
+** release such a buffer, without restoring ordinary unread data.
+*/
+
+#define HASUB(fp) ((fp)->f_ub.smb_base != NULL)
+#define FREEUB(fp) \
+{ \
+ if ((fp)->f_ub.smb_base != (fp)->f_ubuf) \
+ sm_free((char *)(fp)->f_ub.smb_base); \
+ (fp)->f_ub.smb_base = NULL; \
+}
+
+/* Test for an fgetln() buffer. */
+#define HASLB(fp) ((fp)->f_lb.smb_base != NULL)
+#define FREELB(fp) \
+{ \
+ sm_free((char *)(fp)->f_lb.smb_base); \
+ (fp)->f_lb.smb_base = NULL; \
+}
+
+struct sm_io_obj
+{
+ int file;
+};
+
+extern const char SmFileMagic[];
+
+#ifndef ALIGNBYTES
+# define ALIGNBYTES (sizeof(long) - 1)
+# define ALIGN(p) (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES)
+#endif /* ALIGNBYTES */
+
+#define sm_io_flockfile(fp) ((void) 0)
+#define sm_io_funlockfile(fp) ((void) 0)
+
+#ifndef FDSET_CAST
+# define FDSET_CAST /* empty cast for fd_set arg to select */
+#endif
+
+/*
+** SM_CONVERT_TIME -- convert the API timeout flag for select() usage.
+**
+** This takes a 'fp' (a file type pointer) and obtains the "raw"
+** file descriptor (fd) if possible. The 'fd' is needed to possibly
+** switch the mode of the file (blocking/non-blocking) to match
+** the type of timeout. If timeout is SM_TIME_FOREVER then the
+** timeout using select won't be needed and the file is best placed
+** in blocking mode. If there is to be a finite timeout then the file
+** is best placed in non-blocking mode. Then, if not enough can be
+** written, select() can be used to test when something can be written
+** yet still timeout if the wait is too long.
+** If the mode is already in the correct state we don't change it.
+** Iff (yes "iff") the 'fd' is "-1" in value then the mode change
+** will not happen. This situation arises when a late-binding-to-disk
+** file type is in use. An example of this is the sendmail buffered
+** file type (in sendmail/bf.c).
+**
+** Parameters
+** fp -- the file pointer the timeout is for
+** fd -- to become the file descriptor value from 'fp'
+** val -- the timeout value to be converted
+** time -- a struct timeval holding the converted value
+**
+** Returns
+** nothing, this is flow-through code
+**
+** Side Effects:
+** May or may not change the mode of a currently open file.
+** The file mode may be changed to O_NONBLOCK or ~O_NONBLOCK
+** (meaning block). This is done to best match the type of
+** timeout and for (possible) use with select().
+*/
+
+# define SM_CONVERT_TIME(fp, fd, val, time) { \
+ if (((fd) = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1) \
+ { \
+ /* can't get an fd, likely internal 'fake' fp */ \
+ errno = 0; \
+ } \
+ if ((val) == SM_TIME_DEFAULT) \
+ (val) = (fp)->f_timeout; \
+ if ((val) == SM_TIME_IMMEDIATE || (val) == SM_TIME_FOREVER) \
+ { \
+ (time)->tv_sec = 0; \
+ (time)->tv_usec = 0; \
+ } \
+ else \
+ { \
+ (time)->tv_sec = (val) / 1000; \
+ (time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 10; \
+ } \
+ if ((val) == SM_TIME_FOREVER) \
+ { \
+ if ((fp)->f_timeoutstate == SM_TIME_NONBLOCK && (fd) != -1) \
+ { \
+ int ret; \
+ ret = fcntl((fd), F_GETFL, 0); \
+ if (ret == -1 || fcntl((fd), F_SETFL, \
+ ret & ~O_NONBLOCK) == -1) \
+ { \
+ /* errno should be set */ \
+ return SM_IO_EOF; \
+ } \
+ (fp)->f_timeoutstate = SM_TIME_BLOCK; \
+ if ((fp)->f_modefp != NULL) \
+ (fp)->f_modefp->f_timeoutstate = SM_TIME_BLOCK; \
+ } \
+ } \
+ else { \
+ if ((fp)->f_timeoutstate == SM_TIME_BLOCK && (fd) != -1) \
+ { \
+ int ret; \
+ ret = fcntl((fd), F_GETFL, 0); \
+ if (ret == -1 || fcntl((fd), F_SETFL, \
+ ret | O_NONBLOCK) == -1) \
+ { \
+ /* errno should be set */ \
+ return SM_IO_EOF; \
+ } \
+ (fp)->f_timeoutstate = SM_TIME_NONBLOCK; \
+ if ((fp)->f_modefp != NULL) \
+ (fp)->f_modefp->f_timeoutstate = SM_TIME_NONBLOCK; \
+ } \
+ } \
+}
+
+/*
+** SM_IO_WR_TIMEOUT -- setup the timeout for the write
+**
+** This #define uses a select() to wait for the 'fd' to become writable.
+** The select() can be active for up to 'to' time. The select may not
+** use all of the the 'to' time. Hence, the amount of "wall-clock" time is
+** measured to decide how much to subtract from 'to' to update it. On some
+** BSD-based/like systems the timeout for a select is updated for the
+** amount of time used. On many/most systems this does not happen. Therefore
+** the updating of 'to' must be done ourselves; a copy of 'to' is passed
+** since a BSD-like system will have updated it and we don't want to
+** double the time used!
+** Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
+** sendmail buffered file type in sendmail/bf.c; see fvwrite.c).
+**
+** Parameters
+** fd -- a file descriptor for doing select() with
+** timeout -- the original user set value.
+**
+** Returns
+** nothing, this is flow through code
+**
+** Side Effects:
+** adjusts 'timeout' for time used
+*/
+
+#define SM_IO_WR_TIMEOUT(fp, fd, to) { \
+ struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \
+ struct timeval sm_io_to; \
+ int sm_io_to_sel; \
+ fd_set sm_io_to_mask, sm_io_x_mask; \
+ errno = 0; \
+ if ((to) == SM_TIME_DEFAULT) \
+ (to) = (fp)->f_timeout; \
+ if ((to) == SM_TIME_IMMEDIATE) \
+ { \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ else if ((to) == SM_TIME_FOREVER) \
+ { \
+ errno = EINVAL; \
+ return SM_IO_EOF; \
+ } \
+ else \
+ { \
+ sm_io_to.tv_sec = (to) / 1000; \
+ sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 10; \
+ } \
+ FD_ZERO(&sm_io_to_mask); \
+ FD_SET((fd), &sm_io_to_mask); \
+ FD_ZERO(&sm_io_x_mask); \
+ FD_SET((fd), &sm_io_x_mask); \
+ if (gettimeofday(&sm_io_to_before, NULL) < 0) \
+ return SM_IO_EOF; \
+ sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, &sm_io_x_mask, \
+ &sm_io_to); \
+ if (sm_io_to_sel < 0) \
+ { \
+ /* something went wrong, errno set */ \
+ return SM_IO_EOF; \
+ } \
+ else if (sm_io_to_sel == 0) \
+ { \
+ /* timeout */ \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ /* else loop again */ \
+ if (gettimeofday(&sm_io_to_after, NULL) < 0) \
+ return SM_IO_EOF; \
+ timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \
+ timersub(&sm_io_to, &sm_io_to_diff, &sm_io_to); \
+ (to) -= (sm_io_to.tv_sec * 1000); \
+ (to) -= (sm_io_to.tv_usec / 10); \
+ if ((to) < 0) \
+ (to) = 0; \
+}
+
+/*
+** If there is no 'fd' just error (we can't timeout). If the timeout
+** is SM_TIME_FOREVER then there is no need to do a timeout with
+** select since this will be a real error. If the error is not
+** EAGAIN/EWOULDBLOCK (from a nonblocking) then it's a real error.
+** Specify the condition here as macro so it can be used in several places.
+*/
+
+#define IS_IO_ERROR(fd, ret, to) \
+ ((fd) < 0 || \
+ ((ret) < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || \
+ (to) == SM_TIME_FOREVER)
+
diff --git a/gnu/usr.sbin/sendmail/libsm/makebuf.c b/gnu/usr.sbin/sendmail/libsm/makebuf.c
new file mode 100644
index 00000000000..958cb21ebb6
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/makebuf.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: makebuf.c,v 1.21 2001/08/27 13:03:48 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** SM_MAKEBUF -- make a buffer for the file
+**
+** Parameters:
+** fp -- the file to be buffered
+**
+** Returns:
+** nothing
+**
+** Allocate a file buffer, or switch to unbuffered I/O.
+** By default tty devices default to line buffered.
+*/
+
+void
+sm_makebuf(fp)
+ register SM_FILE_T *fp;
+{
+ register void *p;
+ register int flags;
+ size_t size;
+ int couldbetty;
+
+ if (fp->f_flags & SMNBF)
+ {
+ fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
+ fp->f_bf.smb_size = 1;
+ return;
+ }
+ flags = sm_whatbuf(fp, &size, &couldbetty);
+ if ((p = sm_malloc(size)) == NULL)
+ {
+ fp->f_flags |= SMNBF;
+ fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
+ fp->f_bf.smb_size = 1;
+ return;
+ }
+ if (!Sm_IO_DidInit)
+ sm_init();
+ flags |= SMMBF;
+ fp->f_bf.smb_base = fp->f_p = p;
+ fp->f_bf.smb_size = size;
+ if (couldbetty && isatty(fp->f_file))
+ flags |= SMLBF;
+ fp->f_flags |= flags;
+}
+
+/*
+** SM_WHATBUF -- determine proper buffer for a file (internal)
+**
+** Plus it fills in 'bufsize' for recommended buffer size and
+** fills in flag to indicate if 'fp' could be a tty (nothing
+** to do with "betty" :-) ).
+**
+** Parameters:
+** fp -- file pointer to be buffered
+** bufsize -- new buffer size (a return)
+** couldbetty -- could be a tty (returns)
+**
+** Returns:
+** Success:
+** on error:
+** SMNPT -- not seek opimized
+** SMOPT -- seek opimized
+*/
+
+int
+sm_whatbuf(fp, bufsize, couldbetty)
+ register SM_FILE_T *fp;
+ size_t *bufsize;
+ int *couldbetty;
+{
+ struct stat st;
+
+ if (fp->f_file < 0 || fstat(fp->f_file, &st) < 0)
+ {
+ *couldbetty = 0;
+ *bufsize = SM_IO_BUFSIZ;
+ return SMNPT;
+ }
+
+ /* could be a tty iff it is a character device */
+ *couldbetty = S_ISCHR(st.st_mode);
+ if (st.st_blksize == 0)
+ {
+ *bufsize = SM_IO_BUFSIZ;
+ return SMNPT;
+ }
+
+ /*
+ ** Optimise fseek() only if it is a regular file. (The test for
+ ** sm_std_seek is mainly paranoia.) It is safe to set _blksize
+ ** unconditionally; it will only be used if SMOPT is also set.
+ */
+
+ if ((fp->f_flags & SMSTR) == 0)
+ {
+ *bufsize = st.st_blksize;
+ fp->f_blksize = st.st_blksize;
+ }
+ else
+ *bufsize = SM_IO_BUFSIZ;
+ if ((st.st_mode & S_IFMT) == S_IFREG &&
+ fp->f_seek == sm_stdseek)
+ return SMOPT;
+ else
+ return SMNPT;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/match.c b/gnu/usr.sbin/sendmail/libsm/match.c
new file mode 100644
index 00000000000..e195476f5b6
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/match.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: match.c,v 1.8 2001/03/02 19:57:08 ca Exp $")
+
+#include <sm/string.h>
+
+/*
+** SM_MATCH -- Match a character string against a glob pattern.
+**
+** Parameters:
+** str -- string.
+** par -- pattern to find in str.
+**
+** Returns:
+** true on match, false on non-match.
+**
+** A pattern consists of normal characters, which match themselves,
+** and meta-sequences. A * matches any sequence of characters.
+** A ? matches any single character. A [ introduces a character class.
+** A ] marks the end of a character class; if the ] is missing then
+** the [ matches itself rather than introducing a character class.
+** A character class matches any of the characters between the brackets.
+** The range of characters from X to Y inclusive is written X-Y.
+** If the first character after the [ is ! then the character class is
+** complemented.
+**
+** To include a ] in a character class, make it the first character
+** listed (after the !, if any). To include a -, make it the first
+** character listed (after the !, if any) or the last character.
+** It is impossible for a ] to be the final character in a range.
+** For glob patterns that literally match "*", "?" or "[",
+** use [*], [?] or [[].
+*/
+
+bool
+sm_match(str, pat)
+ const char *str;
+ const char *pat;
+{
+ bool ccnot, ccmatch, ccfirst;
+ const char *ccstart;
+ char c, c2;
+
+ for (;;)
+ {
+ switch (*pat)
+ {
+ case '\0':
+ return *str == '\0';
+ case '?':
+ if (*str == '\0')
+ return false;
+ ++pat;
+ ++str;
+ continue;
+ case '*':
+ ++pat;
+ if (*pat == '\0')
+ {
+ /* optimize case of trailing '*' */
+ return true;
+ }
+ for (;;)
+ {
+ if (sm_match(pat, str))
+ return true;
+ if (*str == '\0')
+ return false;
+ ++str;
+ }
+ /* NOTREACHED */
+ case '[':
+ ccstart = pat++;
+ ccnot = false;
+ if (*pat == '!')
+ {
+ ccnot = true;
+ ++pat;
+ }
+ ccmatch = false;
+ ccfirst = true;
+ for (;;)
+ {
+ if (*pat == '\0')
+ {
+ pat = ccstart;
+ goto defl;
+ }
+ if (*pat == ']' && !ccfirst)
+ break;
+ c = *pat++;
+ ccfirst = false;
+ if (*pat == '-' && pat[1] != ']')
+ {
+ ++pat;
+ if (*pat == '\0')
+ {
+ pat = ccstart;
+ goto defl;
+ }
+ c2 = *pat++;
+ if (*str >= c && *str <= c2)
+ ccmatch = true;
+ }
+ else
+ {
+ if (*str == c)
+ ccmatch = true;
+ }
+ }
+ if (ccmatch ^ ccnot)
+ {
+ ++pat;
+ ++str;
+ }
+ else
+ return false;
+ continue;
+ default:
+ defl:
+ if (*pat != *str)
+ return false;
+ ++pat;
+ ++str;
+ continue;
+ }
+ }
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/mbdb.c b/gnu/usr.sbin/sendmail/libsm/mbdb.c
new file mode 100644
index 00000000000..24e2135e320
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/mbdb.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: mbdb.c,v 1.21 2001/03/16 00:38:43 gshapiro Exp $")
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#include <sm/limits.h>
+#include <sm/conf.h>
+#include <sm/assert.h>
+#include <sm/bitops.h>
+#include <sm/errstring.h>
+#include <sm/heap.h>
+#include <sm/mbdb.h>
+#include <sm/string.h>
+#include <sm/sysexits.h>
+
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+# include <sm/ldap.h>
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
+
+typedef struct
+{
+ char *mbdb_typename;
+ int (*mbdb_initialize) __P((char *));
+ int (*mbdb_lookup) __P((char *name, SM_MBDB_T *user));
+ void (*mbdb_terminate) __P((void));
+} SM_MBDB_TYPE_T;
+
+static int mbdb_pw_initialize __P((char *));
+static int mbdb_pw_lookup __P((char *name, SM_MBDB_T *user));
+static void mbdb_pw_terminate __P((void));
+
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+static struct sm_ldap_struct LDAPLMAP;
+static int mbdb_ldap_initialize __P((char *));
+static int mbdb_ldap_lookup __P((char *name, SM_MBDB_T *user));
+static void mbdb_ldap_terminate __P((void));
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
+
+static SM_MBDB_TYPE_T SmMbdbTypes[] =
+{
+ { "pw", mbdb_pw_initialize, mbdb_pw_lookup, mbdb_pw_terminate },
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+ { "ldap", mbdb_ldap_initialize, mbdb_ldap_lookup, mbdb_ldap_terminate },
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
+ { NULL, NULL, NULL, NULL }
+};
+
+static SM_MBDB_TYPE_T *SmMbdbType = &SmMbdbTypes[0];
+
+/*
+** SM_MBDB_INITIALIZE -- specify which mailbox database to use
+**
+** If this function is not called, then the "pw" implementation
+** is used by default; this implementation uses getpwnam().
+**
+** Parameters:
+** mbdb -- Which mailbox database to use.
+** The argument has the form "name" or "name.arg".
+** "pw" means use getpwnam().
+**
+** Results:
+** EX_OK on success, or an EX_* code on failure.
+*/
+
+int
+sm_mbdb_initialize(mbdb)
+ char *mbdb;
+{
+ size_t namelen;
+ int err;
+ char *name;
+ char *arg;
+ SM_MBDB_TYPE_T *t;
+
+ SM_REQUIRE(mbdb != NULL);
+
+ name = mbdb;
+ arg = strchr(mbdb, '.');
+ if (arg == NULL)
+ namelen = strlen(name);
+ else
+ {
+ namelen = arg - name;
+ ++arg;
+ }
+
+ for (t = SmMbdbTypes; t->mbdb_typename != NULL; ++t)
+ {
+ if (strlen(t->mbdb_typename) == namelen &&
+ strncmp(name, t->mbdb_typename, namelen) == 0)
+ {
+ err = t->mbdb_initialize(arg);
+ if (err == EX_OK)
+ SmMbdbType = t;
+ return err;
+ }
+ }
+ return EX_UNAVAILABLE;
+}
+
+/*
+** SM_MBDB_TERMINATE -- terminate connection to the mailbox database
+**
+** Because this function closes any cached file descriptors that
+** are being held open for the connection to the mailbox database,
+** it should be called for security reasons prior to dropping privileges
+** and execing another process.
+**
+** Parameters:
+** none.
+**
+** Results:
+** none.
+*/
+
+void
+sm_mbdb_terminate()
+{
+ SmMbdbType->mbdb_terminate();
+}
+
+/*
+** SM_MBDB_LOOKUP -- look up a local mail recipient, given name
+**
+** Parameters:
+** name -- name of local mail recipient
+** user -- pointer to structure to fill in on success
+**
+** Results:
+** On success, fill in *user and return EX_OK.
+** If the user does not exist, return EX_NOUSER.
+** If a temporary failure (eg, a network failure) occurred,
+** return EX_TEMPFAIL. Otherwise return EX_OSERR.
+*/
+
+int
+sm_mbdb_lookup(name, user)
+ char *name;
+ SM_MBDB_T *user;
+{
+ return SmMbdbType->mbdb_lookup(name, user);
+}
+
+/*
+** SM_MBDB_FROMPW -- copy from struct pw to SM_MBDB_T
+**
+** Parameters:
+** user -- destination user information structure
+** pw -- source passwd structure
+**
+** Results:
+** none.
+*/
+
+void
+sm_mbdb_frompw(user, pw)
+ SM_MBDB_T *user;
+ struct passwd *pw;
+{
+ SM_REQUIRE(user != NULL);
+ (void) sm_strlcpy(user->mbdb_name, pw->pw_name,
+ sizeof(user->mbdb_name));
+ user->mbdb_uid = pw->pw_uid;
+ user->mbdb_gid = pw->pw_gid;
+ sm_pwfullname(pw->pw_gecos, pw->pw_name, user->mbdb_fullname,
+ sizeof(user->mbdb_fullname));
+ (void) sm_strlcpy(user->mbdb_homedir, pw->pw_dir,
+ sizeof(user->mbdb_homedir));
+ (void) sm_strlcpy(user->mbdb_shell, pw->pw_shell,
+ sizeof(user->mbdb_shell));
+}
+
+/*
+** SM_PWFULLNAME -- build full name of user from pw_gecos field.
+**
+** This routine interprets the strange entry that would appear
+** in the GECOS field of the password file.
+**
+** Parameters:
+** gecos -- name to build.
+** user -- the login name of this user (for &).
+** buf -- place to put the result.
+** buflen -- length of buf.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_pwfullname(gecos, user, buf, buflen)
+ register char *gecos;
+ char *user;
+ char *buf;
+ size_t buflen;
+{
+ register char *p;
+ register char *bp = buf;
+
+ if (*gecos == '*')
+ gecos++;
+
+ /* copy gecos, interpolating & to be full name */
+ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
+ {
+ if (bp >= &buf[buflen - 1])
+ {
+ /* buffer overflow -- just use login name */
+ (void) sm_strlcpy(buf, user, buflen);
+ return;
+ }
+ if (*p == '&')
+ {
+ /* interpolate full name */
+ (void) sm_strlcpy(bp, user, buflen - (bp - buf));
+ *bp = toupper(*bp);
+ bp += strlen(bp);
+ }
+ else
+ *bp++ = *p;
+ }
+ *bp = '\0';
+}
+
+/*
+** /etc/passwd implementation.
+*/
+
+/*
+** MBDB_PW_INITIALIZE -- initialize getpwnam() version
+**
+** Parameters:
+** arg -- unused.
+**
+** Results:
+** EX_OK.
+*/
+
+/* ARGSUSED0 */
+static int
+mbdb_pw_initialize(arg)
+ char *arg;
+{
+ return EX_OK;
+}
+
+/*
+** MBDB_PW_LOOKUP -- look up a local mail recipient, given name
+**
+** Parameters:
+** name -- name of local mail recipient
+** user -- pointer to structure to fill in on success
+**
+** Results:
+** On success, fill in *user and return EX_OK.
+** Failure: EX_NOUSER.
+*/
+
+static int
+mbdb_pw_lookup(name, user)
+ char *name;
+ SM_MBDB_T *user;
+{
+ struct passwd *pw;
+
+#ifdef HESIOD
+ /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */
+ {
+ char *p;
+
+ for (p = name; *p != '\0'; p++)
+ if (!isascii(*p) || !isdigit(*p))
+ break;
+ if (*p == '\0')
+ return EX_NOUSER;
+ }
+#endif /* HESIOD */
+
+ errno = 0;
+ pw = getpwnam(name);
+ if (pw == NULL)
+ {
+#if 0
+ /*
+ ** getpwnam() isn't advertised as setting errno.
+ ** In fact, under FreeBSD, non-root getpwnam() on
+ ** non-existant users returns NULL with errno = EPERM.
+ ** This test won't work.
+ */
+ switch (errno)
+ {
+ case 0:
+ return EX_NOUSER;
+ case EIO:
+ return EX_OSERR;
+ default:
+ return EX_TEMPFAIL;
+ }
+#endif /* 0 */
+ return EX_NOUSER;
+ }
+
+ sm_mbdb_frompw(user, pw);
+ return EX_OK;
+}
+
+/*
+** MBDB_PW_TERMINATE -- terminate connection to the mailbox database
+**
+** Parameters:
+** none.
+**
+** Results:
+** none.
+*/
+
+static void
+mbdb_pw_terminate()
+{
+ endpwent();
+}
+
+#if LDAPMAP
+# if _LDAP_EXAMPLE_
+/*
+** LDAP example implementation based on RFC 2307, "An Approach for Using
+** LDAP as a Network Information Service":
+**
+** ( nisSchema.1.0 NAME 'uidNumber'
+** DESC 'An integer uniquely identifying a user in an
+** administrative domain'
+** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )
+**
+** ( nisSchema.1.1 NAME 'gidNumber'
+** DESC 'An integer uniquely identifying a group in an
+** administrative domain'
+** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE )
+**
+** ( nisSchema.1.2 NAME 'gecos'
+** DESC 'The GECOS field; the common name'
+** EQUALITY caseIgnoreIA5Match
+** SUBSTRINGS caseIgnoreIA5SubstringsMatch
+** SYNTAX 'IA5String' SINGLE-VALUE )
+**
+** ( nisSchema.1.3 NAME 'homeDirectory'
+** DESC 'The absolute path to the home directory'
+** EQUALITY caseExactIA5Match
+** SYNTAX 'IA5String' SINGLE-VALUE )
+**
+** ( nisSchema.1.4 NAME 'loginShell'
+** DESC 'The path to the login shell'
+** EQUALITY caseExactIA5Match
+** SYNTAX 'IA5String' SINGLE-VALUE )
+**
+** ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
+** DESC 'Abstraction of an account with POSIX attributes'
+** MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+** MAY ( userPassword $ loginShell $ gecos $ description ) )
+**
+*/
+
+# define MBDB_LDAP_LABEL "MailboxDatabase"
+
+# ifndef MBDB_LDAP_FILTER
+# define MBDB_LDAP_FILTER "(&(objectClass=posixAccount)(uid=%0))"
+# endif /* MBDB_LDAP_FILTER */
+
+# ifndef MBDB_DEFAULT_LDAP_BASEDN
+# define MBDB_DEFAULT_LDAP_BASEDN NULL
+# endif /* MBDB_DEFAULT_LDAP_BASEDN */
+
+# ifndef MBDB_DEFAULT_LDAP_SERVER
+# define MBDB_DEFAULT_LDAP_SERVER NULL
+# endif /* MBDB_DEFAULT_LDAP_SERVER */
+
+/*
+** MBDB_LDAP_INITIALIZE -- initialize LDAP version
+**
+** Parameters:
+** arg -- LDAP specification
+**
+** Results:
+** EX_OK on success, or an EX_* code on failure.
+*/
+
+static int
+mbdb_ldap_initialize(arg)
+ char *arg;
+{
+ sm_ldap_clear(&LDAPLMAP);
+ LDAPLMAP.ldap_base = MBDB_DEFAULT_LDAP_BASEDN;
+ LDAPLMAP.ldap_host = MBDB_DEFAULT_LDAP_SERVER;
+ LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER;
+
+ /* Only want one match */
+ LDAPLMAP.ldap_sizelimit = 1;
+
+ /* interpolate new ldap_base and ldap_host from arg if given */
+ if (arg != NULL && *arg != '\0')
+ {
+ char *new;
+ char *sep;
+ size_t len;
+
+ len = strlen(arg) + 1;
+ new = sm_malloc(len);
+ if (new == NULL)
+ return EX_TEMPFAIL;
+ (void) sm_strlcpy(new, arg, len);
+ sep = strrchr(new, '@');
+ if (sep != NULL)
+ {
+ *sep++ = '\0';
+ LDAPLMAP.ldap_host = sep;
+ }
+ LDAPLMAP.ldap_base = new;
+ }
+
+ /* No connection yet, connect */
+ if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP))
+ return EX_UNAVAILABLE;
+ return EX_OK;
+}
+
+
+/*
+** MBDB_LDAP_LOOKUP -- look up a local mail recipient, given name
+**
+** Parameters:
+** name -- name of local mail recipient
+** user -- pointer to structure to fill in on success
+**
+** Results:
+** On success, fill in *user and return EX_OK.
+** Failure: EX_NOUSER.
+*/
+
+#define NEED_FULLNAME 0x01
+#define NEED_HOMEDIR 0x02
+#define NEED_SHELL 0x04
+#define NEED_UID 0x08
+#define NEED_GID 0x10
+
+static int
+mbdb_ldap_lookup(name, user)
+ char *name;
+ SM_MBDB_T *user;
+{
+ int msgid;
+ int need;
+ int ret;
+ int save_errno;
+ LDAPMessage *entry;
+ BerElement *ber;
+ char *attr = NULL;
+
+ if (strlen(name) >= sizeof(user->mbdb_name))
+ {
+ errno = EINVAL;
+ return EX_NOUSER;
+ }
+
+ if (LDAPLMAP.ldap_filter == NULL)
+ {
+ /* map not initialized, but don't have arg here */
+ errno = EFAULT;
+ return EX_TEMPFAIL;
+ }
+
+ if (LDAPLMAP.ldap_ld == NULL)
+ {
+ /* map not open, try to open now */
+ if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP))
+ return EX_TEMPFAIL;
+ }
+
+ sm_ldap_setopts(LDAPLMAP.ldap_ld, &LDAPLMAP);
+ msgid = sm_ldap_search(&LDAPLMAP, name);
+ if (msgid == -1)
+ {
+ save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld) + E_LDAPBASE;
+# ifdef LDAP_SERVER_DOWN
+ if (errno == LDAP_SERVER_DOWN)
+ {
+ /* server disappeared, try reopen on next search */
+ sm_ldap_close(&LDAPLMAP);
+ }
+# endif /* LDAP_SERVER_DOWN */
+ errno = save_errno;
+ return EX_TEMPFAIL;
+ }
+
+ /* Get results (all if MF_NOREWRITE, otherwise one by one) */
+ ret = ldap_result(LDAPLMAP.ldap_ld, msgid, 1,
+ (LDAPLMAP.ldap_timeout.tv_sec == 0 ? NULL :
+ &(LDAPLMAP.ldap_timeout)),
+ &(LDAPLMAP.ldap_res));
+
+ if (ret != LDAP_RES_SEARCH_RESULT &&
+ ret != LDAP_RES_SEARCH_ENTRY)
+ {
+ if (ret == 0)
+ errno = ETIMEDOUT;
+ else
+ errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+ ret = EX_TEMPFAIL;
+ goto abort;
+ }
+
+ entry = ldap_first_entry(LDAPLMAP.ldap_ld, LDAPLMAP.ldap_res);
+ if (entry == NULL)
+ {
+ save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+ if (save_errno == LDAP_SUCCESS)
+ {
+ errno = ENOENT;
+ ret = EX_NOUSER;
+ }
+ else
+ {
+ errno = save_errno;
+ ret = EX_TEMPFAIL;
+ }
+ goto abort;
+ }
+
+# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+ /*
+ ** Reset value to prevent lingering
+ ** LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see below)
+ */
+
+ LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS;
+# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+
+ ret = EX_OK;
+ need = NEED_FULLNAME|NEED_HOMEDIR|NEED_SHELL|NEED_UID|NEED_GID;
+ for (attr = ldap_first_attribute(LDAPLMAP.ldap_ld, entry, &ber);
+ attr != NULL;
+ attr = ldap_next_attribute(LDAPLMAP.ldap_ld, entry, ber))
+ {
+ char **vals;
+
+ vals = ldap_get_values(LDAPLMAP.ldap_ld, entry, attr);
+ if (vals == NULL)
+ {
+ errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+ if (errno == LDAP_SUCCESS)
+ continue;
+
+ /* Must be an error */
+ errno += E_LDAPBASE;
+ ret = EX_TEMPFAIL;
+ goto abort;
+ }
+
+# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
+ /*
+ ** Reset value to prevent lingering
+ ** LDAP_DECODING_ERROR due to
+ ** OpenLDAP 1.X's hack (see below)
+ */
+
+ LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS;
+# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
+
+ if (vals[0] == NULL || vals[0][0] == '\0')
+ goto skip;
+
+ if (strcasecmp(attr, "gecos") == 0)
+ {
+ if (!bitset(NEED_FULLNAME, need) ||
+ strlen(vals[0]) >= sizeof(user->mbdb_fullname))
+ goto skip;
+
+ sm_pwfullname(vals[0], name, user->mbdb_fullname,
+ sizeof(user->mbdb_fullname));
+ need &= ~NEED_FULLNAME;
+ }
+ else if (strcasecmp(attr, "homeDirectory") == 0)
+ {
+ if (!bitset(NEED_HOMEDIR, need) ||
+ strlen(vals[0]) >= sizeof(user->mbdb_homedir))
+ goto skip;
+
+ (void) sm_strlcpy(user->mbdb_homedir, vals[0],
+ sizeof(user->mbdb_homedir));
+ need &= ~NEED_HOMEDIR;
+ }
+ else if (strcasecmp(attr, "loginShell") == 0)
+ {
+ if (!bitset(NEED_SHELL, need) ||
+ strlen(vals[0]) >= sizeof(user->mbdb_shell))
+ goto skip;
+
+ (void) sm_strlcpy(user->mbdb_shell, vals[0],
+ sizeof(user->mbdb_shell));
+ need &= ~NEED_SHELL;
+ }
+ else if (strcasecmp(attr, "uidNumber") == 0)
+ {
+ char *p;
+
+ if (!bitset(NEED_UID, need))
+ goto skip;
+
+ for (p = vals[0]; *p != '\0'; p++)
+ {
+ /* allow negative numbers */
+ if (p == vals[0] && *p == '-')
+ {
+ /* but not simply '-' */
+ if (*(p + 1) == '\0')
+ goto skip;
+ }
+ else if (!isascii(*p) || !isdigit(*p))
+ goto skip;
+ }
+ user->mbdb_uid = atoi(vals[0]);
+ need &= ~NEED_UID;
+ }
+ else if (strcasecmp(attr, "gidNumber") == 0)
+ {
+ char *p;
+
+ if (!bitset(NEED_GID, need))
+ goto skip;
+
+ for (p = vals[0]; *p != '\0'; p++)
+ {
+ /* allow negative numbers */
+ if (p == vals[0] && *p == '-')
+ {
+ /* but not simply '-' */
+ if (*(p + 1) == '\0')
+ goto skip;
+ }
+ else if (!isascii(*p) || !isdigit(*p))
+ goto skip;
+ }
+ user->mbdb_gid = atoi(vals[0]);
+ need &= ~NEED_GID;
+ }
+
+skip:
+ ldap_value_free(vals);
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ }
+
+ errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld);
+
+ /*
+ ** We check errno != LDAP_DECODING_ERROR since
+ ** OpenLDAP 1.X has a very ugly *undocumented*
+ ** hack of returning this error code from
+ ** ldap_next_attribute() if the library freed the
+ ** ber attribute. See:
+ ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
+ */
+
+ if (errno != LDAP_SUCCESS &&
+ errno != LDAP_DECODING_ERROR)
+ {
+ /* Must be an error */
+ errno += E_LDAPBASE;
+ ret = EX_TEMPFAIL;
+ goto abort;
+ }
+
+ abort:
+ save_errno = errno;
+ if (attr != NULL)
+ {
+# if USING_NETSCAPE_LDAP
+ ldap_memfree(attr);
+# endif /* USING_NETSCAPE_LDAP */
+ attr = NULL;
+ }
+ if (LDAPLMAP.ldap_res != NULL)
+ {
+ ldap_msgfree(LDAPLMAP.ldap_res);
+ LDAPLMAP.ldap_res = NULL;
+ }
+ if (ret == EX_OK)
+ {
+ if (need == 0)
+ {
+ (void) sm_strlcpy(user->mbdb_name, name,
+ sizeof(user->mbdb_name));
+ save_errno = 0;
+ }
+ else
+ {
+ ret = EX_NOUSER;
+ save_errno = EINVAL;
+ }
+ }
+ errno = save_errno;
+ return ret;
+}
+
+/*
+** MBDB_LDAP_TERMINATE -- terminate connection to the mailbox database
+**
+** Parameters:
+** none.
+**
+** Results:
+** none.
+*/
+
+static void
+mbdb_ldap_terminate()
+{
+ sm_ldap_close(&LDAPLMAP);
+ if (LDAPLMAP.ldap_base != MBDB_DEFAULT_LDAP_BASEDN)
+ {
+ if (LDAPLMAP.ldap_host != MBDB_DEFAULT_LDAP_SERVER)
+ LDAPLMAP.ldap_host = NULL;
+ sm_free(LDAPLMAP.ldap_base);
+ LDAPLMAP.ldap_base = NULL;
+ }
+}
+# endif /* _LDAP_EXAMPLE_ */
+#endif /* LDAPMAP */
diff --git a/gnu/usr.sbin/sendmail/libsm/niprop.c b/gnu/usr.sbin/sendmail/libsm/niprop.c
new file mode 100644
index 00000000000..68fc707d9ba
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/niprop.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: niprop.c,v 1.6 2001/09/04 22:41:27 ca Exp $")
+
+#if NETINFO
+#include <ctype.h>
+#include <stdlib.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/debug.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+#include <sm/heap.h>
+
+/*
+** NI_PROPVAL -- NetInfo property value lookup routine
+**
+** Parameters:
+** keydir -- the NetInfo directory name in which to search
+** for the key.
+** keyprop -- the name of the property in which to find the
+** property we are interested. Defaults to "name".
+** keyval -- the value for which we are really searching.
+** valprop -- the property name for the value in which we
+** are interested.
+** sepchar -- if non-nil, this can be multiple-valued, and
+** we should return a string separated by this
+** character.
+**
+** Returns:
+** NULL -- if:
+** 1. the directory is not found
+** 2. the property name is not found
+** 3. the property contains multiple values
+** 4. some error occurred
+** else -- the value of the lookup.
+**
+** Example:
+** To search for an alias value, use:
+** ni_propval("/aliases", "name", aliasname, "members", ',')
+**
+** Notes:
+** Caller should free the return value of ni_proval
+*/
+
+# include <netinfo/ni.h>
+
+# define LOCAL_NETINFO_DOMAIN "."
+# define PARENT_NETINFO_DOMAIN ".."
+# define MAX_NI_LEVELS 256
+
+char *
+ni_propval(keydir, keyprop, keyval, valprop, sepchar)
+ char *keydir;
+ char *keyprop;
+ char *keyval;
+ char *valprop;
+ int sepchar;
+{
+ char *propval = NULL;
+ int i;
+ int j, alen, l;
+ void *ni = NULL;
+ void *lastni = NULL;
+ ni_status nis;
+ ni_id nid;
+ ni_namelist ninl;
+ register char *p;
+ char keybuf[1024];
+
+ /*
+ ** Create the full key from the two parts.
+ **
+ ** Note that directory can end with, e.g., "name=" to specify
+ ** an alternate search property.
+ */
+
+ i = strlen(keydir) + strlen(keyval) + 2;
+ if (keyprop != NULL)
+ i += strlen(keyprop) + 1;
+ if (i >= sizeof keybuf)
+ return NULL;
+ (void) sm_strlcpyn(keybuf, sizeof keybuf, 2, keydir, "/");
+ if (keyprop != NULL)
+ {
+ (void) sm_strlcat2(keybuf, keyprop, "=", sizeof keybuf);
+ }
+ (void) sm_strlcat(keybuf, keyval, sizeof keybuf);
+
+#if 0
+ if (tTd(38, 21))
+ sm_dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
+ keydir, keyprop, keyval, valprop, sepchar, keybuf);
+#endif /* 0 */
+
+ /*
+ ** If the passed directory and property name are found
+ ** in one of netinfo domains we need to search (starting
+ ** from the local domain moving all the way back to the
+ ** root domain) set propval to the property's value
+ ** and return it.
+ */
+
+ for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
+ {
+ if (i == 0)
+ {
+ nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_open(LOCAL) = %d\n", nis);
+#endif /* 0 */
+ }
+ else
+ {
+ if (lastni != NULL)
+ ni_free(lastni);
+ lastni = ni;
+ nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_open(PARENT) = %d\n", nis);
+#endif /* 0 */
+ }
+
+ /*
+ ** Don't bother if we didn't get a handle on a
+ ** proper domain. This is not necessarily an error.
+ ** We would get a positive ni_status if, for instance
+ ** we never found the directory or property and tried
+ ** to open the parent of the root domain!
+ */
+
+ if (nis != 0)
+ break;
+
+ /*
+ ** Find the path to the server information.
+ */
+
+ if (ni_pathsearch(ni, &nid, keybuf) != 0)
+ continue;
+
+ /*
+ ** Find associated value information.
+ */
+
+ if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
+ continue;
+
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_lookupprop: len=%d\n",
+ ninl.ni_namelist_len);
+#endif /* 0 */
+
+ /*
+ ** See if we have an acceptable number of values.
+ */
+
+ if (ninl.ni_namelist_len <= 0)
+ continue;
+
+ if (sepchar == '\0' && ninl.ni_namelist_len > 1)
+ {
+ ni_namelist_free(&ninl);
+ continue;
+ }
+
+ /*
+ ** Calculate number of bytes needed and build result
+ */
+
+ alen = 1;
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ alen += strlen(ninl.ni_namelist_val[j]) + 1;
+ propval = p = sm_malloc(alen);
+ if (propval == NULL)
+ goto cleanup;
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ {
+ (void) sm_strlcpy(p, ninl.ni_namelist_val[j], alen);
+ l = strlen(p);
+ p += l;
+ *p++ = sepchar;
+ alen -= l + 1;
+ }
+ *--p = '\0';
+
+ ni_namelist_free(&ninl);
+ }
+
+ cleanup:
+ if (ni != NULL)
+ ni_free(ni);
+ if (lastni != NULL && ni != lastni)
+ ni_free(lastni);
+#if 0
+ if (tTd(38, 20))
+ sm_dprintf("ni_propval returns: '%s'\n", propval);
+#endif /* 0 */
+
+ return propval;
+}
+#endif /* NETINFO */
diff --git a/gnu/usr.sbin/sendmail/libsm/path.c b/gnu/usr.sbin/sendmail/libsm/path.c
new file mode 100644
index 00000000000..6f0f3eff7bb
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/path.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: path.c,v 1.7 2001/08/28 16:06:59 gshapiro Exp $")
+
+#include <sm/path.h>
+#include <sm/string.h>
+
diff --git a/gnu/usr.sbin/sendmail/libsm/put.c b/gnu/usr.sbin/sendmail/libsm/put.c
new file mode 100644
index 00000000000..debdb0c8e48
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/put.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: put.c,v 1.24 2001/03/05 03:22:41 ca Exp $")
+#include <string.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include <sm/errstring.h>
+#include <sm/string.h>
+#include "local.h"
+#include "fvwrite.h"
+
+/*
+** SM_IO_PUTC -- output a character to the file
+**
+** Function version of the macro sm_io_putc (in <sm/io.h>).
+**
+** Parameters:
+** fp -- file to output to
+** timeout -- time to complete putc
+** c -- int value of character to output
+**
+** Returns:
+** Failure: returns SM_IO_EOF _and_ sets errno
+** Success: returns sm_putc() value.
+**
+*/
+
+#undef sm_io_putc
+
+int
+sm_io_putc(fp, timeout, c)
+ SM_FILE_T *fp;
+ int timeout;
+ int c;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ return sm_putc(fp, timeout, c);
+}
+
+
+/*
+** SM_PERROR -- print system error messages to smioerr
+**
+** Parameters:
+** s -- message to print
+**
+** Returns:
+** none
+*/
+
+void
+sm_perror(s)
+ const char *s;
+{
+ if (s != NULL && *s != '\0')
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s: ", s);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n",
+ sm_errstring(errno));
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/refill.c b/gnu/usr.sbin/sendmail/libsm/refill.c
new file mode 100644
index 00000000000..0cfd64d47ac
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/refill.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: refill.c,v 1.47 2001/06/06 00:22:56 gshapiro Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sm/io.h>
+#include <sm/conf.h>
+#include <sm/assert.h>
+#include "local.h"
+
+static int sm_lflush __P((SM_FILE_T *, int *));
+
+/*
+** SM_IO_RD_TIMEOUT -- measured timeout for reads
+**
+** This #define uses a select() to wait for the 'fd' to become readable.
+** The select() can be active for up to 'To' time. The select() may not
+** use all of the the 'To' time. Hence, the amount of "wall-clock" time is
+** measured to decide how much to subtract from 'To' to update it. On some
+** BSD-based/like systems the timeout for a select() is updated for the
+** amount of time used. On many/most systems this does not happen. Therefore
+** the updating of 'To' must be done ourselves; a copy of 'To' is passed
+** since a BSD-like system will have updated it and we don't want to
+** double the time used!
+** Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
+** sendmail buffered file type in sendmail/bf.c; see use below).
+**
+** Parameters
+** fp -- the file pointer for the active file
+** fd -- raw file descriptor (from 'fp') to use for select()
+** to -- struct timeval of the timeout
+** timeout -- the original timeout value
+** sel_ret -- the return value from the select()
+**
+** Returns:
+** nothing, flow through code
+*/
+
+#define SM_IO_RD_TIMEOUT(fp, fd, to, timeout, sel_ret) \
+{ \
+ struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \
+ fd_set sm_io_to_mask, sm_io_x_mask; \
+ errno = 0; \
+ if (timeout == SM_TIME_IMMEDIATE) \
+ { \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ FD_ZERO(&sm_io_to_mask); \
+ FD_SET((fd), &sm_io_to_mask); \
+ FD_ZERO(&sm_io_x_mask); \
+ FD_SET((fd), &sm_io_x_mask); \
+ if (gettimeofday(&sm_io_to_before, NULL) < 0) \
+ return SM_IO_EOF; \
+ (sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL, \
+ &sm_io_x_mask, (to)); \
+ if ((sel_ret) < 0) \
+ { \
+ /* something went wrong, errno set */ \
+ fp->f_r = 0; \
+ fp->f_flags |= SMERR; \
+ return SM_IO_EOF; \
+ } \
+ else if ((sel_ret) == 0) \
+ { \
+ /* timeout */ \
+ errno = EAGAIN; \
+ return SM_IO_EOF; \
+ } \
+ /* calulate wall-clock time used */ \
+ if (gettimeofday(&sm_io_to_after, NULL) < 0) \
+ return SM_IO_EOF; \
+ timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \
+ timersub((to), &sm_io_to_diff, (to)); \
+}
+
+/*
+** SM_LFLUSH -- flush a file if it is line buffered and writable
+**
+** Parameters:
+** fp -- file pointer to flush
+** timeout -- original timeout value (in milliseconds)
+**
+** Returns:
+** Failure: returns SM_IO_EOF and sets errno
+** Success: returns 0
+*/
+
+static int
+sm_lflush(fp, timeout)
+ SM_FILE_T *fp;
+ int *timeout;
+{
+
+ if ((fp->f_flags & (SMLBF|SMWR)) == (SMLBF|SMWR))
+ return sm_flush(fp, timeout);
+ return 0;
+}
+
+/*
+** SM_REFILL -- refill a buffer
+**
+** Parameters:
+** fp -- file pointer for buffer refill
+** timeout -- time to complete filling the buffer in milliseconds
+**
+** Returns:
+** Success: returns 0
+** Failure: returns SM_IO_EOF
+*/
+
+int
+sm_refill(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ int ret, r;
+ struct timeval to;
+ int fd;
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. And we're not EOF or ERR really.
+ ** So... the failure is we couldn't do it in time.
+ */
+
+ errno = EAGAIN;
+ fp->f_r = 0; /* just to be sure */
+ return 0;
+ }
+
+ /* make sure stdio is set up */
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ fp->f_r = 0; /* largely a convenience for callers */
+
+ if (fp->f_flags & SMFEOF)
+ return SM_IO_EOF;
+
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+
+ /* if not already reading, have to be reading and writing */
+ if ((fp->f_flags & SMRD) == 0)
+ {
+ if ((fp->f_flags & SMRW) == 0)
+ {
+ errno = EBADF;
+ fp->f_flags |= SMERR;
+ return SM_IO_EOF;
+ }
+
+ /* switch to reading */
+ if (fp->f_flags & SMWR)
+ {
+ if (sm_flush(fp, &timeout))
+ return SM_IO_EOF;
+ fp->f_flags &= ~SMWR;
+ fp->f_w = 0;
+ fp->f_lbfsize = 0;
+ }
+ fp->f_flags |= SMRD;
+ }
+ else
+ {
+ /*
+ ** We were reading. If there is an ungetc buffer,
+ ** we must have been reading from that. Drop it,
+ ** restoring the previous buffer (if any). If there
+ ** is anything in that buffer, return.
+ */
+
+ if (HASUB(fp))
+ {
+ FREEUB(fp);
+ if ((fp->f_r = fp->f_ur) != 0)
+ {
+ fp->f_p = fp->f_up;
+
+ /* revert blocking state */
+ return 0;
+ }
+ }
+ }
+
+ if (fp->f_bf.smb_base == NULL)
+ sm_makebuf(fp);
+
+ /*
+ ** Before reading from a line buffered or unbuffered file,
+ ** flush all line buffered output files, per the ANSI C standard.
+ */
+
+ if (fp->f_flags & (SMLBF|SMNBF))
+ (void) sm_fwalk(sm_lflush, &timeout);
+
+ /*
+ ** If this file is linked to another, and we are going to hang
+ ** on the read, flush the linked file before continuing.
+ */
+
+ if (fp->f_flushfp != NULL &&
+ (*fp->f_getinfo)(fp, SM_IO_IS_READABLE, NULL) <= 0)
+ sm_flush(fp->f_flushfp, &timeout);
+
+ fp->f_p = fp->f_bf.smb_base;
+
+ /*
+ ** The do-while loop stops trying to read when something is read
+ ** or it appears that the timeout has expired before finding
+ ** something available to be read (via select()).
+ */
+
+ ret = 0;
+ do
+ {
+ errno = 0; /* needed to ensure EOF correctly found */
+ r = (*fp->f_read)(fp, (char *)fp->f_p, fp->f_bf.smb_size);
+ if (r <= 0)
+ {
+ if (r == 0 && errno == 0)
+ break; /* EOF found */
+ if (IS_IO_ERROR(fd, r, timeout))
+ goto err; /* errno set */
+
+ /* read would block */
+ SM_IO_RD_TIMEOUT(fp, fd, &to, timeout, ret);
+ }
+ } while (r <= 0 && ret > 0);
+
+err:
+ if (r <= 0)
+ {
+ if (r == 0)
+ fp->f_flags |= SMFEOF;
+ else
+ fp->f_flags |= SMERR;
+ fp->f_r = 0;
+ return SM_IO_EOF;
+ }
+ fp->f_r = r;
+ return 0;
+}
+
+/*
+** SM_RGET -- refills buffer and returns first character
+**
+** Handle sm_getc() when the buffer ran out:
+** Refill, then return the first character in the newly-filled buffer.
+**
+** Parameters:
+** fp -- file pointer to work on
+** timeout -- time to complete refill
+**
+** Returns:
+** Success: first character in refilled buffer as an int
+** Failure: SM_IO_EOF
+*/
+
+int
+sm_rget(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ if (sm_refill(fp, timeout) == 0)
+ {
+ fp->f_r--;
+ return *fp->f_p++;
+ }
+ return SM_IO_EOF;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/rewind.c b/gnu/usr.sbin/sendmail/libsm/rewind.c
new file mode 100644
index 00000000000..915d908205b
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/rewind.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: rewind.c,v 1.16 2001/04/03 01:46:40 ca Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/assert.h>
+#include "local.h"
+
+/*
+** SM_IO_REWIND -- rewind the file
+**
+** Seeks the file to the begining and clears any outstanding errors.
+**
+** Parameters:
+** fp -- the flie pointer for rewind
+** timeout -- time to complete the rewind
+**
+** Returns:
+** none.
+*/
+
+void
+sm_io_rewind(fp, timeout)
+ register SM_FILE_T *fp;
+ int timeout;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ (void) sm_io_seek(fp, timeout, 0L, SM_IO_SEEK_SET);
+ (void) sm_io_clearerr(fp);
+ errno = 0; /* not required, but seems reasonable */
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/rpool.c b/gnu/usr.sbin/sendmail/libsm/rpool.c
new file mode 100644
index 00000000000..b620e8886d1
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/rpool.c
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: rpool.c,v 1.21 2001/09/04 22:41:27 ca Exp $")
+
+/*
+** resource pools
+** For documentation, see rpool.html
+*/
+
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/rpool.h>
+#include <sm/varargs.h>
+#include <sm/conf.h>
+#if _FFR_PERF_RPOOL
+# include <syslog.h>
+#endif /* _FFR_PERF_RPOOL */
+
+const char SmRpoolMagic[] = "sm_rpool";
+
+typedef union
+{
+ SM_POOLLINK_T link;
+ char align[SM_ALIGN_SIZE];
+} SM_POOLHDR_T;
+
+/*
+** Tune this later
+*/
+
+#define POOLSIZE 4096
+#define BIG_OBJECT_RATIO 10
+
+/*
+** SM_RPOOL_ALLOCBLOCK_X -- allocate a new block for an rpool.
+**
+** Parameters:
+** rpool -- rpool to which the block should be added.
+** size -- size of block.
+**
+** Returns:
+** Pointer to block.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+static char *
+sm_rpool_allocblock_x(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+{
+ SM_POOLLINK_T *p;
+
+ p = sm_malloc_x(sizeof(SM_POOLHDR_T) + size);
+ p->sm_pnext = rpool->sm_pools;
+ rpool->sm_pools = p;
+ return (char*) p + sizeof(SM_POOLHDR_T);
+}
+
+/*
+** SM_RPOOL_ALLOCBLOCK -- allocate a new block for an rpool.
+**
+** Parameters:
+** rpool -- rpool to which the block should be added.
+** size -- size of block.
+**
+** Returns:
+** Pointer to block, NULL on failure.
+*/
+
+static char *
+sm_rpool_allocblock(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+{
+ SM_POOLLINK_T *p;
+
+ p = sm_malloc(sizeof(SM_POOLHDR_T) + size);
+ if (p == NULL)
+ return NULL;
+ p->sm_pnext = rpool->sm_pools;
+ rpool->sm_pools = p;
+ return (char*) p + sizeof(SM_POOLHDR_T);
+}
+
+/*
+** SM_RPOOL_MALLOC_TAGGED_X -- allocate memory from rpool
+**
+** Parameters:
+** rpool -- rpool from which memory should be allocated;
+** can be NULL, use sm_malloc() then.
+** size -- size of block.
+** file -- filename.
+** line -- line number in file.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to block.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+void *
+#if SM_HEAP_CHECK
+sm_rpool_malloc_tagged_x(rpool, size, file, line, group)
+ SM_RPOOL_T *rpool;
+ size_t size;
+ char *file;
+ int line;
+ int group;
+#else /* SM_HEAP_CHECK */
+sm_rpool_malloc_x(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+#endif /* SM_HEAP_CHECK */
+{
+ char *ptr;
+
+ if (rpool == NULL)
+ return sm_malloc_tagged_x(size, file, line, group);
+
+ /* Ensure that size is properly aligned. */
+ if (size & SM_ALIGN_BITS)
+ size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
+
+ /* The common case. This is optimized for speed. */
+ if (size <= rpool->sm_poolavail)
+ {
+ ptr = rpool->sm_poolptr;
+ rpool->sm_poolptr += size;
+ rpool->sm_poolavail -= size;
+ return ptr;
+ }
+
+ /*
+ ** The slow case: we need to call malloc.
+ ** The SM_REQUIRE assertion is deferred until now, for speed.
+ ** That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
+ ** so the common case code won't be triggered on a dangling pointer.
+ */
+
+ SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
+
+ /*
+ ** If size > sm_poolsize, then malloc a new block especially for
+ ** this request. Future requests will be allocated from the
+ ** current pool.
+ **
+ ** What if the current pool is mostly unallocated, and the current
+ ** request is larger than the available space, but < sm_poolsize?
+ ** If we discard the current pool, and start allocating from a new
+ ** pool, then we will be wasting a lot of space. For this reason,
+ ** we malloc a block just for the current request if size >
+ ** sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
+ ** Thus, the most space that we will waste at the end of a pool
+ ** is sm_bigobjectsize - 1.
+ */
+
+ if (size > rpool->sm_bigobjectsize)
+ {
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_nbigblocks;
+#endif /* _FFR_PERF_RPOOL */
+ return sm_rpool_allocblock_x(rpool, size);
+ }
+ SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
+ ptr = sm_rpool_allocblock_x(rpool, rpool->sm_poolsize);
+ rpool->sm_poolptr = ptr + size;
+ rpool->sm_poolavail = rpool->sm_poolsize - size;
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_npools;
+#endif /* _FFR_PERF_RPOOL */
+ return ptr;
+}
+
+/*
+** SM_RPOOL_MALLOC_TAGGED -- allocate memory from rpool
+**
+** Parameters:
+** rpool -- rpool from which memory should be allocated;
+** can be NULL, use sm_malloc() then.
+** size -- size of block.
+** file -- filename.
+** line -- line number in file.
+** group -- heap group for debugging.
+**
+** Returns:
+** Pointer to block, NULL on failure.
+*/
+
+void *
+#if SM_HEAP_CHECK
+sm_rpool_malloc_tagged(rpool, size, file, line, group)
+ SM_RPOOL_T *rpool;
+ size_t size;
+ char *file;
+ int line;
+ int group;
+#else /* SM_HEAP_CHECK */
+sm_rpool_malloc(rpool, size)
+ SM_RPOOL_T *rpool;
+ size_t size;
+#endif /* SM_HEAP_CHECK */
+{
+ char *ptr;
+
+ if (rpool == NULL)
+ return sm_malloc_tagged(size, file, line, group);
+
+ /* Ensure that size is properly aligned. */
+ if (size & SM_ALIGN_BITS)
+ size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
+
+ /* The common case. This is optimized for speed. */
+ if (size <= rpool->sm_poolavail)
+ {
+ ptr = rpool->sm_poolptr;
+ rpool->sm_poolptr += size;
+ rpool->sm_poolavail -= size;
+ return ptr;
+ }
+
+ /*
+ ** The slow case: we need to call malloc.
+ ** The SM_REQUIRE assertion is deferred until now, for speed.
+ ** That's okay: we set rpool->sm_poolavail to 0 when we free an rpool,
+ ** so the common case code won't be triggered on a dangling pointer.
+ */
+
+ SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
+
+ /*
+ ** If size > sm_poolsize, then malloc a new block especially for
+ ** this request. Future requests will be allocated from the
+ ** current pool.
+ **
+ ** What if the current pool is mostly unallocated, and the current
+ ** request is larger than the available space, but < sm_poolsize?
+ ** If we discard the current pool, and start allocating from a new
+ ** pool, then we will be wasting a lot of space. For this reason,
+ ** we malloc a block just for the current request if size >
+ ** sm_bigobjectsize, where sm_bigobjectsize <= sm_poolsize.
+ ** Thus, the most space that we will waste at the end of a pool
+ ** is sm_bigobjectsize - 1.
+ */
+
+ if (size > rpool->sm_bigobjectsize)
+ {
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_nbigblocks;
+#endif /* _FFR_PERF_RPOOL */
+ return sm_rpool_allocblock(rpool, size);
+ }
+ SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
+ ptr = sm_rpool_allocblock(rpool, rpool->sm_poolsize);
+ if (ptr == NULL)
+ return NULL;
+ rpool->sm_poolptr = ptr + size;
+ rpool->sm_poolavail = rpool->sm_poolsize - size;
+#if _FFR_PERF_RPOOL
+ ++rpool->sm_npools;
+#endif /* _FFR_PERF_RPOOL */
+ return ptr;
+}
+
+/*
+** SM_RPOOL_NEW_X -- create a new rpool.
+**
+** Parameters:
+** parent -- pointer to parent rpool, can be NULL.
+**
+** Returns:
+** Pointer to new rpool.
+*/
+
+SM_RPOOL_T *
+sm_rpool_new_x(parent)
+ SM_RPOOL_T *parent;
+{
+ SM_RPOOL_T *rpool;
+
+ rpool = sm_malloc_x(sizeof(SM_RPOOL_T));
+ if (parent == NULL)
+ rpool->sm_parentlink = NULL;
+ else
+ {
+ SM_TRY
+ rpool->sm_parentlink = sm_rpool_attach_x(parent,
+ (SM_RPOOL_RFREE_T) sm_rpool_free,
+ (void *) rpool);
+ SM_EXCEPT(exc, "*")
+ sm_free(rpool);
+ sm_exc_raise_x(exc);
+ SM_END_TRY
+ }
+ rpool->sm_magic = SmRpoolMagic;
+
+ rpool->sm_poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
+ rpool->sm_bigobjectsize = rpool->sm_poolsize / BIG_OBJECT_RATIO;
+ rpool->sm_poolptr = NULL;
+ rpool->sm_poolavail = 0;
+ rpool->sm_pools = NULL;
+
+ rpool->sm_rptr = NULL;
+ rpool->sm_ravail = 0;
+ rpool->sm_rlists = NULL;
+#if _FFR_PERF_RPOOL
+ rpool->sm_nbigblocks = 0;
+ rpool->sm_npools = 0;
+#endif /* _FFR_PERF_RPOOL */
+
+ return rpool;
+}
+
+/*
+** SM_RPOOL_SETSIZES -- set sizes for rpool.
+**
+** Parameters:
+** poolsize -- size of a single rpool block.
+** bigobjectsize -- if this size is exceeded, an individual
+** block is allocated (must be less or equal poolsize).
+**
+** Returns:
+** none.
+*/
+
+void
+sm_rpool_setsizes(rpool, poolsize, bigobjectsize)
+ SM_RPOOL_T *rpool;
+ size_t poolsize;
+ size_t bigobjectsize;
+{
+ SM_REQUIRE(poolsize >= bigobjectsize);
+ if (poolsize == 0)
+ poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
+ if (bigobjectsize == 0)
+ bigobjectsize = poolsize / BIG_OBJECT_RATIO;
+ rpool->sm_poolsize = poolsize;
+ rpool->sm_bigobjectsize = bigobjectsize;
+}
+
+/*
+** SM_RPOOL_FREE -- free an rpool and release all of its resources.
+**
+** Parameters:
+** rpool -- rpool to free.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_rpool_free(rpool)
+ SM_RPOOL_T *rpool;
+{
+ SM_RLIST_T *rl, *rnext;
+ SM_RESOURCE_T *r, *rmax;
+ SM_POOLLINK_T *pp, *pnext;
+
+ if (rpool == NULL)
+ return;
+
+ /*
+ ** It's important to free the resources before the memory pools,
+ ** because the resource free functions might modify the contents
+ ** of the memory pools.
+ */
+
+ rl = rpool->sm_rlists;
+ if (rl != NULL)
+ {
+ rmax = rpool->sm_rptr;
+ for (;;)
+ {
+ for (r = rl->sm_rvec; r < rmax; ++r)
+ {
+ if (r->sm_rfree != NULL)
+ r->sm_rfree(r->sm_rcontext);
+ }
+ rnext = rl->sm_rnext;
+ sm_free(rl);
+ if (rnext == NULL)
+ break;
+ rl = rnext;
+ rmax = &rl->sm_rvec[SM_RLIST_MAX];
+ }
+ }
+
+ /*
+ ** Now free the memory pools.
+ */
+
+ for (pp = rpool->sm_pools; pp != NULL; pp = pnext)
+ {
+ pnext = pp->sm_pnext;
+ sm_free(pp);
+ }
+
+ /*
+ ** Disconnect rpool from its parent.
+ */
+
+ if (rpool->sm_parentlink != NULL)
+ *rpool->sm_parentlink = NULL;
+
+ /*
+ ** Setting these fields to zero means that any future to attempt
+ ** to use the rpool after it is freed will cause an assertion failure.
+ */
+
+ rpool->sm_magic = NULL;
+ rpool->sm_poolavail = 0;
+ rpool->sm_ravail = 0;
+
+#if _FFR_PERF_RPOOL
+ if (rpool->sm_nbigblocks > 0 || rpool->sm_npools > 1)
+ syslog(LOG_NOTICE,
+ "perf: rpool=%lx, sm_nbigblocks=%d, sm_npools=%d",
+ (long) rpool, rpool->sm_nbigblocks, rpool->sm_npools);
+ rpool->sm_nbigblocks = 0;
+ rpool->sm_npools = 0;
+#endif /* _FFR_PERF_RPOOL */
+ sm_free(rpool);
+}
+
+/*
+** SM_RPOOL_ATTACH_X -- attach a resource to an rpool.
+**
+** Parameters:
+** rpool -- rpool to which resource should be attached.
+** rfree -- function to call when rpool is freed.
+** rcontext -- argument for function to call when rpool is freed.
+**
+** Returns:
+** Pointer to allocated function.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+SM_RPOOL_ATTACH_T
+sm_rpool_attach_x(rpool, rfree, rcontext)
+ SM_RPOOL_T *rpool;
+ SM_RPOOL_RFREE_T rfree;
+ void *rcontext;
+{
+ SM_RLIST_T *rl;
+ SM_RPOOL_ATTACH_T a;
+
+ SM_REQUIRE_ISA(rpool, SmRpoolMagic);
+
+ if (rpool->sm_ravail == 0)
+ {
+ rl = sm_malloc_x(sizeof(SM_RLIST_T));
+ rl->sm_rnext = rpool->sm_rlists;
+ rpool->sm_rlists = rl;
+ rpool->sm_rptr = rl->sm_rvec;
+ rpool->sm_ravail = SM_RLIST_MAX;
+ }
+
+ a = &rpool->sm_rptr->sm_rfree;
+ rpool->sm_rptr->sm_rfree = rfree;
+ rpool->sm_rptr->sm_rcontext = rcontext;
+ ++rpool->sm_rptr;
+ --rpool->sm_ravail;
+ return a;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/rpool.html b/gnu/usr.sbin/sendmail/libsm/rpool.html
new file mode 100644
index 00000000000..4b06fe32e20
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/rpool.html
@@ -0,0 +1,187 @@
+<html>
+<head>
+ <title>libsm : Resource Pools</title>
+</head>
+<body>
+
+<a href="index.html">Back to libsm overview</a>
+
+<center>
+ <h1> libsm : Resource Pools </h1>
+ <br> $Sendmail: rpool.html,v 1.4 2000/12/07 17:33:09 dmoen Exp $
+</center>
+
+<h2> Introduction </h2>
+
+A resource pool is an object that owns a collection of objects
+that can be freed all at once.
+
+<p>
+Resource pools simplify storage management.
+
+<p>
+Resource pools also speed up memory management.
+For example, here are some memory allocation statistics from a
+run of <tt>`sendmail -q`</tt> that delivered 3 messages:
+<blockquote><pre>
+ 18 1 82 12 87 24 7 42 2 84
+ 3046 2 18 13 6 25 89 44 2 88
+ 728 3 15 14 2 26 14 48 1 91
+ 31 4 9 15 3 27 104 52 3 92
+ 103 5 394 16 80 28 8 56 2 96
+ 125 6 16 17 1 31 2 60 1 100
+ 45 7 14 18 59 32 10 64 9 108
+ 130 8 6 19 1 33 6 68 3 135
+ 40 9 111 20 7 34 1 72 10 140
+ 37 10 7 21 54 36 10 76
+ 34 11 4 22 38 40 5 80
+</pre></blockquote>
+The second number in each pair is the size of a memory block; the first
+number is the number of blocks of that size. We can see that sendmail
+allocates large numbers of 2 byte blocks. These memory blocks can be
+allocated and freed more quickly using resource pools, because:
+<ul>
+<li>
+ When you allocate a small block from a resource pool, the rpool
+ implementation carves off a chunk of a large preallocated block,
+ and hands you a pointer to it.
+<li>
+ When you free a resource pool, only a small number of large
+ blocks need to be freed.
+</ul>
+
+<h2> Synopsis </h2>
+
+<pre>
+#include &lt;sm/rpool.h&gt;
+
+typedef void (*SM_RPOOL_RFREE_T)(void *rcontext);
+typedef struct sm_rpool SM_RPOOL_T;
+typedef ... SM_RPOOL_ATTACH_T;
+
+SM_RPOOL_T *
+sm_rpool_new_x(
+ SM_RPOOL_T *parent);
+
+void
+sm_rpool_free(
+ SM_RPOOL_T *rpool);
+
+void *
+sm_rpool_malloc_x(
+ SM_RPOOL_T *rpool,
+ size_t size);
+
+SM_RPOOL_ATTACH_T
+sm_rpool_attach_x(
+ SM_RPOOL_T *rpool,
+ SM_RPOOL_RFREE_T rfree,
+ void *rcontext);
+
+void
+sm_rpool_detach(
+ SM_RPOOL_ATTACH_T);
+
+void
+sm_rpool_setsizes(
+ SM_RPOOL_T *rpool,
+ size_t poolsize,
+ size_t bigobjectsize);
+</pre>
+
+<h2> Description </h2>
+
+<dl>
+<dt>
+<tt> SM_RPOOL_T *sm_rpool_new_x(SM_RPOOL_T *parent) </tt>
+<dd>
+ Create a new resource pool object.
+ Raise an exception if there is insufficient heap space.
+ Initially, no memory is allocated for memory pools or resource lists.
+ <p>
+ If parent != NULL then the new rpool will be added as a resource
+ to the specified parent rpool, so that when the parent is freed,
+ the child is also freed. However, even if a parent is specified,
+ you can free the rpool at any time, and it will be automatically
+ disconnected from the parent.
+ <p>
+<dt>
+<tt> void *sm_rpool_malloc_x(SM_RPOOL_T *rpool, size_t size) </tt>
+<dd>
+ Allocate a block of memory from a memory pool owned by the rpool.
+ Raise an exception if there is insufficient heap space.
+ A series of small allocation requests can be satisfied allocating
+ them from the same memory pool, which reduces the number of calls
+ to malloc.
+ All of the memory allocated by sm_rpool_malloc_x is freed when
+ the rpool is freed, and not before then.
+ <p>
+<dt>
+<tt> void sm_rpool_setsizes(SM_RPOOL_T *rpool, size_t poolsize, size_t bigobjectsize) </tt>
+<dd>
+ Set memory pool parameters.
+ You can safely call this function at any time, but an especially
+ good time to call it is immediately after creating the rpool,
+ before any pooled objects have been allocated using sm_rpool_malloc_x.
+ <p>
+ <tt>poolsize</tt> is the number of bytes of pool memory
+ that will be available in the next pool object to be allocated.
+ If you happen to know the total number of bytes of memory that
+ you will allocate from an rpool using sm_rpool_malloc_x
+ (including alignment padding), then you can pass that value
+ as the poolsize, and only a single pool will be allocated
+ during the lifetime of the rpool.
+ <tt>poolsize</tt> is an optimization, not a hard limit:
+ if you allocate more than this number of bytes from the rpool,
+ then more than one memory pool may be allocated by the rpool
+ to satisfy your requests.
+ <p>
+ <tt>bigobjectsize</tt> is a value &lt;= <tt>poolsize</tt>.
+ It is used when an <tt>sm_rpool_malloc_x</tt> request exceeds
+ the number of bytes available in the current pool.
+ If the request is &gt; <tt>bigobjectsize</tt> then the request
+ will be satisfied by allocating a new block just for this specific
+ request, and the current pool is not affected.
+ If the request is &lt;= <tt>bigobjectsize</tt> then the current
+ pool is closed and a new memory pool is allocated, from which the
+ request is satisfied.
+ Consequently, no more than <tt>bigobjectsize-1</tt> bytes will
+ ever be wasted at the end of a given pool.
+ <p>
+ If poolsize or bigobjectsize are 0, then suitable default values
+ are chosen.
+ <p>
+<dt>
+<tt> SM_RPOOL_ATTACH_T sm_rpool_attach_x(SM_RPOOL_T *rpool, SM_RPOOL_RFREE_T rfree, void *rcontext) </tt>
+<dd>
+ Attach an object to a resource pool, along with its free function.
+ When the rpool is freed, the specified object will also be freed.
+ Raise an exception if there is insufficient heap space.
+ <p>
+ The return value is a magic cookie which, if passed to
+ sm_rpool_detach, disconnects the object from the resource pool,
+ which prevents the object's free function from being called when
+ the rpool is freed.
+ <p>
+<dt>
+<tt> void sm_rpool_detach(SM_RPOOL_ATTACH_T a) </tt>
+<dd>
+ The argument is a magic cookie returned by <tt>sm_rpool_attach_t</tt>,
+ and refers to the object that was attached to an rpool by a specific
+ call to <tt>sm_rpool_attach_t</tt>.
+ Disconnect the object from the resource pool,
+ which prevents the object's free function from being called when
+ the rpool is freed.
+ <p>
+<dt>
+<tt> void sm_rpool_free(SM_RPOOL_T *rpool) </tt>
+<dd>
+ Free an rpool object.
+ All memory allocated using sm_rpool_malloc_x
+ and all objects attached using sm_rpool_attach_x
+ are freed at this time.
+ If the rpool has a parent rpool, it is detached from its parent.
+</dl>
+
+</body>
+</html>
diff --git a/gnu/usr.sbin/sendmail/libsm/setvbuf.c b/gnu/usr.sbin/sendmail/libsm/setvbuf.c
new file mode 100644
index 00000000000..1ae2b209ee0
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/setvbuf.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: setvbuf.c,v 1.30 2001/02/28 20:25:18 rodney Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/assert.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** SM_IO_SETVBUF -- set the buffering type for a file
+**
+** Set one of the different kinds of buffering, optionally including
+** a buffer.
+** If 'size' is == 0 then an "optimal" size will be selected.
+** If 'buf' is == NULL then space will be allocated at 'size'.
+**
+** Parameters:
+** fp -- the file that buffering is to be changed for
+** timeout -- time allowed for completing the function
+** buf -- buffer to use
+** mode -- buffering method to use
+** size -- size of 'buf'
+**
+** Returns:
+** Failure: SM_IO_EOF
+** Success: 0 (zero)
+*/
+
+int
+sm_io_setvbuf(fp, timeout, buf, mode, size)
+ SM_FILE_T *fp;
+ int timeout;
+ char *buf;
+ int mode;
+ size_t size;
+{
+ int ret, flags;
+ size_t iosize;
+ int ttyflag;
+ int fd;
+ struct timeval to;
+
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+
+ /*
+ ** Verify arguments. The `int' limit on `size' is due to this
+ ** particular implementation. Note, buf and size are ignored
+ ** when setting SM_IO_NBF.
+ */
+
+ if (mode != SM_IO_NBF)
+ if ((mode != SM_IO_FBF && mode != SM_IO_LBF &&
+ mode != SM_IO_NOW) || (int) size < 0)
+ return SM_IO_EOF;
+
+ /*
+ ** Write current buffer, if any. Discard unread input (including
+ ** ungetc data), cancel line buffering, and free old buffer if
+ ** malloc()ed. We also clear any eof condition, as if this were
+ ** a seek.
+ */
+
+ ret = 0;
+ SM_CONVERT_TIME(fp, fd, timeout, &to);
+ (void) sm_flush(fp, &timeout);
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_r = fp->f_lbfsize = 0;
+ flags = fp->f_flags;
+ if (flags & SMMBF)
+ {
+ sm_free((void *) fp->f_bf.smb_base);
+ fp->f_bf.smb_base = NULL;
+ }
+ flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW |
+ SMFBF);
+
+ /* If setting unbuffered mode, skip all the hard work. */
+ if (mode == SM_IO_NBF)
+ goto nbf;
+
+ /*
+ ** Find optimal I/O size for seek optimization. This also returns
+ ** a `tty flag' to suggest that we check isatty(fd), but we do not
+ ** care since our caller told us how to buffer.
+ */
+
+ flags |= sm_whatbuf(fp, &iosize, &ttyflag);
+ if (size == 0)
+ {
+ buf = NULL; /* force local allocation */
+ size = iosize;
+ }
+
+ /* Allocate buffer if needed. */
+ if (buf == NULL)
+ {
+ if ((buf = sm_malloc(size)) == NULL)
+ {
+ /*
+ ** Unable to honor user's request. We will return
+ ** failure, but try again with file system size.
+ */
+
+ ret = SM_IO_EOF;
+ if (size != iosize)
+ {
+ size = iosize;
+ buf = sm_malloc(size);
+ }
+ }
+ if (buf == NULL)
+ {
+ /* No luck; switch to unbuffered I/O. */
+nbf:
+ fp->f_flags = flags | SMNBF;
+ fp->f_w = 0;
+ fp->f_bf.smb_base = fp->f_p = fp->f_nbuf;
+ fp->f_bf.smb_size = 1;
+ return ret;
+ }
+ flags |= SMMBF;
+ }
+
+ /*
+ ** Kill any seek optimization if the buffer is not the
+ ** right size.
+ **
+ ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)?
+ */
+
+ if (size != iosize)
+ flags |= SMNPT;
+
+ /*
+ ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on
+ ** exit (since we are buffered in some way).
+ */
+
+ if (mode == SM_IO_LBF)
+ flags |= SMLBF;
+ else if (mode == SM_IO_NOW)
+ flags |= SMNOW;
+ else if (mode == SM_IO_FBF)
+ flags |= SMFBF;
+ fp->f_flags = flags;
+ fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf;
+ fp->f_bf.smb_size = size;
+ /* fp->f_lbfsize is still 0 */
+ if (flags & SMWR)
+ {
+ /*
+ ** Begin or continue writing: see sm_wsetup(). Note
+ ** that SMNBF is impossible (it was handled earlier).
+ */
+
+ if (flags & SMLBF)
+ {
+ fp->f_w = 0;
+ fp->f_lbfsize = -fp->f_bf.smb_size;
+ }
+ else
+ fp->f_w = size;
+ }
+ else
+ {
+ /* begin/continue reading, or stay in intermediate state */
+ fp->f_w = 0;
+ }
+
+ atexit(sm_cleanup);
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/shm.c b/gnu/usr.sbin/sendmail/libsm/shm.c
new file mode 100644
index 00000000000..d368a9cddb6
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/shm.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: shm.c,v 1.6 2001/02/14 04:39:47 gshapiro Exp $")
+
+#if SM_CONF_SHM
+# include <stdlib.h>
+# include <unistd.h>
+# include <errno.h>
+# include <sm/shm.h>
+
+/*
+** SM_SHMSTART -- initialize shared memory segment.
+**
+** Parameters:
+** key -- key for shared memory.
+** size -- size of segment.
+** shmflag -- initial flags.
+** shmid -- pointer to return id.
+** owner -- create segment.
+**
+** Returns:
+** pointer to shared memory segment,
+** NULL on failure.
+**
+** Side Effects:
+** attaches shared memory segment.
+*/
+
+void *
+sm_shmstart(key, size, shmflg, shmid, owner)
+ key_t key;
+ int size;
+ int shmflg;
+ int *shmid;
+ bool owner;
+{
+ int save_errno;
+ void *shm = SM_SHM_NULL;
+
+ /* default: user/group accessible */
+ if (shmflg == 0)
+ shmflg = SHM_R|SHM_W|(SHM_R>>3)|(SHM_W>>3);
+ if (owner)
+ shmflg |= IPC_CREAT|IPC_EXCL;
+ *shmid = shmget(key, size, shmflg);
+ if (*shmid < 0)
+ goto error;
+
+ shmflg = SHM_RND;
+ shm = shmat(*shmid, (void *) 0, shmflg);
+ if (shm == SM_SHM_NULL)
+ goto error;
+
+ return shm;
+
+ error:
+ save_errno = errno;
+ if (shm != SM_SHM_NULL || *shmid >= 0)
+ sm_shmstop(shm, *shmid, owner);
+ *shmid = SM_SHM_NO_ID;
+ errno = save_errno;
+ return (void *) 0;
+}
+
+/*
+** SM_SHMSTOP -- stop using shared memory segment.
+**
+** Parameters:
+** shm -- pointer to shared memory.
+** shmid -- id.
+** owner -- delete segment.
+**
+** Returns:
+** 0 on success.
+** < 0 on failure.
+**
+** Side Effects:
+** detaches (and maybe removes) shared memory segment.
+*/
+
+int
+sm_shmstop(shm, shmid, owner)
+ void *shm;
+ int shmid;
+ bool owner;
+{
+ int r;
+
+ if (shm != SM_SHM_NULL && (r = shmdt(shm)) < 0)
+ return r;
+ if (owner && shmid >= 0 && (r = shmctl(shmid, IPC_RMID, NULL)) < 0)
+ return r;
+ return 0;
+}
+#endif /* SM_CONF_SHM */
diff --git a/gnu/usr.sbin/sendmail/libsm/signal.c b/gnu/usr.sbin/sendmail/libsm/signal.c
new file mode 100644
index 00000000000..47fa703e0b8
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/signal.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: signal.c,v 1.13 2001/08/14 16:05:47 ca Exp $")
+
+#if SM_CONF_SETITIMER
+# include <sys/time.h>
+#endif /* SM_CONF_SETITIMER */
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sm/clock.h>
+#include <sm/signal.h>
+#include <signal.h>
+#include <sm/string.h>
+
+unsigned int volatile InCriticalSection; /* >0 if inside critical section */
+int volatile PendingSignal; /* pending signal to resend */
+
+ /*
+** SM_SIGNAL -- set a signal handler
+**
+** This is essentially old BSD "signal(3)".
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+sigfunc_t
+sm_signal(sig, handler)
+ int sig;
+ sigfunc_t handler;
+{
+# if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
+ struct sigaction n, o;
+# endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
+
+ /*
+ ** First, try for modern signal calls
+ ** and restartable syscalls
+ */
+
+# ifdef SA_RESTART
+ (void) memset(&n, '\0', sizeof n);
+# if USE_SA_SIGACTION
+ n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
+ n.sa_flags = SA_RESTART|SA_SIGINFO;
+# else /* USE_SA_SIGACTION */
+ n.sa_handler = handler;
+ n.sa_flags = SA_RESTART;
+# endif /* USE_SA_SIGACTION */
+ if (sigaction(sig, &n, &o) < 0)
+ return SIG_ERR;
+ return o.sa_handler;
+# else /* SA_RESTART */
+
+ /*
+ ** Else check for SYS5SIGNALS or
+ ** BSD4_3 signals
+ */
+
+# if defined(SYS5SIGNALS) || defined(BSD4_3)
+# ifdef BSD4_3
+ return signal(sig, handler);
+# else /* BSD4_3 */
+ return sigset(sig, handler);
+# endif /* BSD4_3 */
+# else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
+
+ /*
+ ** Finally, if nothing else is available,
+ ** go for a default
+ */
+
+ (void) memset(&n, '\0', sizeof n);
+ n.sa_handler = handler;
+ if (sigaction(sig, &n, &o) < 0)
+ return SIG_ERR;
+ return o.sa_handler;
+# endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
+# endif /* SA_RESTART */
+}
+ /*
+** SM_BLOCKSIGNAL -- hold a signal to prevent delivery
+**
+** Parameters:
+** sig -- the signal to block.
+**
+** Returns:
+** 1 signal was previously blocked
+** 0 signal was not previously blocked
+** -1 on failure.
+*/
+
+int
+sm_blocksignal(sig)
+ int sig;
+{
+# ifdef BSD4_3
+# ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+# endif /* ! sigmask */
+ return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
+# else /* BSD4_3 */
+# ifdef ALTOS_SYSTEM_V
+ sigfunc_t handler;
+
+ handler = sigset(sig, SIG_HOLD);
+ if (handler == SIG_ERR)
+ return -1;
+ else
+ return handler == SIG_HOLD;
+# else /* ALTOS_SYSTEM_V */
+ sigset_t sset, oset;
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, sig);
+ if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
+ return -1;
+ else
+ return sigismember(&oset, sig);
+# endif /* ALTOS_SYSTEM_V */
+# endif /* BSD4_3 */
+}
+ /*
+** SM_RELEASESIGNAL -- release a held signal
+**
+** Parameters:
+** sig -- the signal to release.
+**
+** Returns:
+** 1 signal was previously blocked
+** 0 signal was not previously blocked
+** -1 on failure.
+*/
+
+int
+sm_releasesignal(sig)
+ int sig;
+{
+# ifdef BSD4_3
+ return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
+# else /* BSD4_3 */
+# ifdef ALTOS_SYSTEM_V
+ sigfunc_t handler;
+
+ handler = sigset(sig, SIG_HOLD);
+ if (sigrelse(sig) < 0)
+ return -1;
+ else
+ return handler == SIG_HOLD;
+# else /* ALTOS_SYSTEM_V */
+ sigset_t sset, oset;
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, sig);
+ if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
+ return -1;
+ else
+ return sigismember(&oset, sig);
+# endif /* ALTOS_SYSTEM_V */
+# endif /* BSD4_3 */
+}
+ /*
+** PEND_SIGNAL -- Add a signal to the pending signal list
+**
+** Parameters:
+** sig -- signal to add
+**
+** Returns:
+** none.
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+void
+pend_signal(sig)
+ int sig;
+{
+ int sigbit;
+ int save_errno = errno;
+#if SM_CONF_SETITIMER
+ struct itimerval clr;
+#endif /* SM_CONF_SETITIMER */
+
+ /*
+ ** Don't want to interrupt something critical, hence delay
+ ** the alarm for one second. Hopefully, by then we
+ ** will be out of the critical section. If not, then
+ ** we will just delay again. The events to be run will
+ ** still all be run, maybe just a little bit late.
+ */
+
+ switch (sig)
+ {
+ case SIGHUP:
+ sigbit = PEND_SIGHUP;
+ break;
+
+ case SIGINT:
+ sigbit = PEND_SIGINT;
+ break;
+
+ case SIGTERM:
+ sigbit = PEND_SIGTERM;
+ break;
+
+ case SIGUSR1:
+ sigbit = PEND_SIGUSR1;
+ break;
+
+ case SIGALRM:
+ /* don't have to pend these */
+ sigbit = 0;
+ break;
+
+ default:
+ /* If we get here, we are in trouble */
+ abort();
+
+ /* NOTREACHED */
+ /* shut up stupid compiler warning on HP-UX 11 */
+ sigbit = 0;
+ break;
+ }
+
+ if (sigbit != 0)
+ PendingSignal |= sigbit;
+ (void) sm_signal(SIGALRM, sm_tick);
+#if SM_CONF_SETITIMER
+ clr.it_interval.tv_sec = 0;
+ clr.it_interval.tv_usec = 0;
+ clr.it_value.tv_sec = 1;
+ clr.it_value.tv_usec = 0;
+ (void) setitimer(ITIMER_REAL, &clr, NULL);
+#else /* SM_CONF_SETITIMER */
+ (void) alarm(1);
+#endif /* SM_CONF_SETITIMER */
+ errno = save_errno;
+}
+ /*
+** SM_ALLSIGNALS -- act on all signals
+**
+** Parameters:
+** block -- whether to block or release all signals.
+**
+** Returns:
+** none.
+*/
+
+void
+sm_allsignals(block)
+ bool block;
+{
+# ifdef BSD4_3
+# ifndef sigmask
+# define sigmask(s) (1 << ((s) - 1))
+# endif /* ! sigmask */
+ if (block)
+ {
+ int mask = 0;
+
+ mask |= sigmask(SIGALRM);
+ mask |= sigmask(SIGCHLD);
+ mask |= sigmask(SIGHUP);
+ mask |= sigmask(SIGINT);
+ mask |= sigmask(SIGTERM);
+ mask |= sigmask(SIGUSR1);
+
+ (void) sigblock(mask);
+ }
+ else
+ sigsetmask(0);
+# else /* BSD4_3 */
+# ifdef ALTOS_SYSTEM_V
+ if (block)
+ {
+ (void) sigset(SIGALRM, SIG_HOLD);
+ (void) sigset(SIGCHLD, SIG_HOLD);
+ (void) sigset(SIGHUP, SIG_HOLD);
+ (void) sigset(SIGINT, SIG_HOLD);
+ (void) sigset(SIGTERM, SIG_HOLD);
+ (void) sigset(SIGUSR1, SIG_HOLD);
+ }
+ else
+ {
+ (void) sigset(SIGALRM, SIG_DFL);
+ (void) sigset(SIGCHLD, SIG_DFL);
+ (void) sigset(SIGHUP, SIG_DFL);
+ (void) sigset(SIGINT, SIG_DFL);
+ (void) sigset(SIGTERM, SIG_DFL);
+ (void) sigset(SIGUSR1, SIG_DFL);
+ }
+# else /* ALTOS_SYSTEM_V */
+ sigset_t sset;
+
+ (void) sigemptyset(&sset);
+ (void) sigaddset(&sset, SIGALRM);
+ (void) sigaddset(&sset, SIGCHLD);
+ (void) sigaddset(&sset, SIGHUP);
+ (void) sigaddset(&sset, SIGINT);
+ (void) sigaddset(&sset, SIGTERM);
+ (void) sigaddset(&sset, SIGUSR1);
+ (void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
+# endif /* ALTOS_SYSTEM_V */
+# endif /* BSD4_3 */
+}
+ /*
+** SM_SIGNAL_NOOP -- A signal no-op function
+**
+** Parameters:
+** sig -- signal received
+**
+** Returns:
+** SIGFUNC_RETURN
+*/
+
+/* ARGSUSED */
+SIGFUNC_DECL
+sm_signal_noop(sig)
+ int sig;
+{
+ int save_errno = errno;
+
+ FIX_SYSV_SIGNAL(sig, sm_signal_noop);
+ errno = save_errno;
+ return SIGFUNC_RETURN;
+}
+
diff --git a/gnu/usr.sbin/sendmail/libsm/smstdio.c b/gnu/usr.sbin/sendmail/libsm/smstdio.c
new file mode 100644
index 00000000000..a182599c293
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/smstdio.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: smstdio.c,v 1.27 2001/03/05 03:22:41 ca Exp $")
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sm/assert.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include "local.h"
+
+/*
+** Overall:
+** This is a file type which implements a layer on top of the system
+** stdio. fp->f_cookie is the FILE* of stdio. The cookie may be
+** "bound late" because of the manner which Linux implements stdio.
+** When binding late (when fp->f_cookie==NULL) then the value of
+** fp->f_ival is used (0, 1 or 2) to map to stdio's stdin, stdout or
+** stderr.
+*/
+
+/*
+** SM_STDIOOPEN -- open a file to system stdio implementation
+**
+** Parameters:
+** fp -- file pointer assign for this open
+** info -- info about file to open
+** flags -- indicating method of opening
+** rpool -- ignored
+**
+** Returns:
+** Failure: -1
+** Success: 0 (zero)
+*/
+
+/* ARGSUSED3 */
+int
+sm_stdioopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ register FILE *s;
+ char *stdiomode;
+
+ switch (flags)
+ {
+ case SM_IO_RDONLY:
+ stdiomode = "r";
+ break;
+ case SM_IO_WRONLY:
+ stdiomode = "w";
+ break;
+ case SM_IO_APPEND:
+ stdiomode = "a";
+ break;
+ case SM_IO_APPENDRW:
+ stdiomode = "a+";
+ break;
+ case SM_IO_RDWR:
+ default:
+ stdiomode = "r+";
+ break;
+ }
+
+ if ((s = fopen((char *)info, stdiomode)) == NULL)
+ return -1;
+ fp->f_cookie = s;
+ return 0;
+}
+
+/*
+** SETUP -- assign file type cookie when not already assigned
+**
+** Parameters:
+** fp - the file pointer to get the cookie assigned
+**
+** Return:
+** none.
+*/
+
+static void
+setup(fp)
+ SM_FILE_T *fp;
+{
+ if (fp->f_cookie == NULL)
+ {
+ switch (fp->f_ival)
+ {
+ case 0:
+ fp->f_cookie = stdin;
+ break;
+ case 1:
+ fp->f_cookie = stdout;
+ break;
+ case 2:
+ fp->f_cookie = stderr;
+ break;
+ default:
+ sm_abort("fp->f_ival=%d: out of range (0...2)", fp->f_ival);
+ break;
+ }
+ }
+}
+
+/*
+** SM_STDIOREAD -- read from the file
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location to place the read data
+** n - number of bytes to read
+**
+** Returns:
+** result from fread().
+*/
+
+ssize_t
+sm_stdioread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fread(buf, 1, n, s);
+}
+
+/*
+** SM_STDIOWRITE -- write to the file
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location of data to write
+** n - number of bytes to write
+**
+** Returns:
+** result from fwrite().
+*/
+
+ssize_t
+sm_stdiowrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fwrite(buf, 1, n, s);
+}
+
+/*
+** SM_STDIOSEEK -- set position within file
+**
+** Parameters:
+** fp -- the file pointer
+** offset -- new location based on 'whence'
+** whence -- indicates "base" for 'offset'
+**
+** Returns:
+** result from fseek().
+*/
+
+off_t
+sm_stdioseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fseek(s, offset, whence);
+}
+
+/*
+** SM_STDIOCLOSE -- close the file
+**
+** Parameters:
+** fp -- close file pointer
+**
+** Return:
+** status from fclose()
+*/
+
+int
+sm_stdioclose(fp)
+ SM_FILE_T *fp;
+{
+ register FILE *s;
+
+ if (fp->f_cookie == NULL)
+ setup(fp);
+ s = fp->f_cookie;
+ return fclose(s);
+}
+
+/*
+** SM_STDIOSETINFO -- set info for this open file
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information setting
+** valp -- memory location of info to set
+**
+** Return:
+** Failure: -1 and sets errno
+** Success: none (currently).
+*/
+
+/* ARGSUSED2 */
+int
+sm_stdiosetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STDIOGETINFO -- get info for this open file
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information request
+** valp -- memory location to place info
+**
+** Return:
+** Failure: -1 and sets errno
+** Success: none (currently).
+*/
+
+/* ARGSUSED2 */
+int
+sm_stdiogetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_IO_STDIOOPEN -- create an SM_FILE which interfaces to a stdio FILE
+**
+** Parameters:
+** stream -- an open stdio stream, as returned by fopen()
+** mode -- the mode argument to fopen() which describes stream
+**
+** Return:
+** On success, return a pointer to an SM_FILE object which
+** can be used for reading and writing 'stream'.
+** Abort if mode is gibberish or stream is bad.
+** Raise an exception if we can't allocate memory.
+*/
+
+SM_FILE_T *
+sm_io_stdioopen(stream, mode)
+ FILE *stream;
+ char *mode;
+{
+ int fd;
+ bool r, w;
+ int ioflags;
+ SM_FILE_T *fp;
+
+ fd = fileno(stream);
+ SM_REQUIRE(fd >= 0);
+
+ r = w = false;
+ switch (mode[0])
+ {
+ case 'r':
+ r = true;
+ break;
+ case 'w':
+ case 'a':
+ w = true;
+ break;
+ default:
+ sm_abort("sm_io_stdioopen: mode '%s' is bad", mode);
+ }
+ if (strchr(&mode[1], '+') != NULL)
+ r = w = true;
+ if (r && w)
+ ioflags = SMRW;
+ else if (r)
+ ioflags = SMRD;
+ else
+ ioflags = SMWR;
+
+ fp = sm_fp(SmFtRealStdio, ioflags, NULL);
+ fp->f_file = fd;
+ fp->f_cookie = stream;
+ return fp;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/snprintf.c b/gnu/usr.sbin/sendmail/libsm/snprintf.c
new file mode 100644
index 00000000000..9994140fff6
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/snprintf.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: snprintf.c,v 1.21 2001/03/02 23:53:41 ca Exp $")
+#include <limits.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_SNPRINTF -- format a string to a memory location of restricted size
+**
+** Parameters:
+** str -- memory location to place formatted string
+** n -- size of buffer pointed to by str, capped to
+** a maximum of INT_MAX
+** fmt -- the formatting directives
+** ... -- the data to satisfy the formatting
+**
+** Returns:
+** Failure: -1
+** Success: number of bytes that would have been written
+** to str, not including the trailing '\0',
+** up to a maximum of INT_MAX, as if there was
+** no buffer size limitation. If the result >= n
+** then the output was truncated.
+**
+** Side Effects:
+** If n > 0, then between 0 and n-1 bytes of formatted output
+** are written into 'str', followed by a '\0'.
+*/
+
+int
+#if SM_VA_STD
+sm_snprintf(char *str, size_t n, char const *fmt, ...)
+#else /* SM_VA_STD */
+sm_snprintf(str, n, fmt, va_alist)
+ char *str;
+ size_t n;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_VA_LOCAL_DECL
+ SM_FILE_T fake;
+
+ /* While snprintf(3) specifies size_t stdio uses an int internally */
+ if (n > INT_MAX)
+ n = INT_MAX;
+ SM_VA_START(ap, fmt);
+
+ /* XXX put this into a static? */
+ fake.sm_magic = SmFileMagic;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR;
+ fake.f_cookie = &fake;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_w = n ? n - 1 : 0;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_snprintf:fake";
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ if (n > 0)
+ *fake.f_p = '\0';
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/sscanf.c b/gnu/usr.sbin/sendmail/libsm/sscanf.c
new file mode 100644
index 00000000000..a24e5cb098a
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/sscanf.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: sscanf.c,v 1.22 2001/03/02 23:53:41 ca Exp $")
+#include <string.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_EOFREAD -- dummy read function for faked file below
+**
+** Parameters:
+** fp -- file pointer
+** buf -- location to place read data
+** len -- number of bytes to read
+**
+** Returns:
+** 0 (zero) always
+*/
+
+static ssize_t
+sm_eofread __P((
+ SM_FILE_T *fp,
+ char *buf,
+ size_t len));
+
+/* ARGSUSED0 */
+static ssize_t
+sm_eofread(fp, buf, len)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t len;
+{
+ return 0;
+}
+
+/*
+** SM_IO_SSCANF -- scan a string to find data units
+**
+** Parameters:
+** str -- strings containing data
+** fmt -- format directive for finding data units
+** ... -- memory locations to place format found data units
+**
+** Returns:
+** Failure: SM_IO_EOF
+** Success: number of data units found
+**
+** Side Effects:
+** Attempts to strlen() 'str'; if not a '\0' terminated string
+** then the call may SEGV/fail.
+** Faking the string 'str' as a file.
+*/
+
+int
+#if SM_VA_STD
+sm_io_sscanf(const char *str, char const *fmt, ...)
+#else /* SM_VA_STD */
+sm_io_sscanf(str, fmt, va_alist)
+ const char *str;
+ char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ int ret;
+ SM_FILE_T fake;
+ SM_VA_LOCAL_DECL
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_flags = SMRD;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *) str;
+ fake.f_bf.smb_size = fake.f_r = strlen(str);
+ fake.f_file = -1;
+ fake.f_read = sm_eofread;
+ fake.f_write = NULL;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_io_sscanf:fake";
+ fake.f_flushfp = NULL;
+ fake.f_ub.smb_base = NULL;
+ fake.f_lb.smb_base = NULL;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ SM_VA_START(ap, fmt);
+ ret = sm_vfscanf(&fake, SM_TIME_FOREVER, fmt, ap);
+ SM_VA_END(ap);
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/stdio.c b/gnu/usr.sbin/sendmail/libsm/stdio.c
new file mode 100644
index 00000000000..9180a5bbc7c
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/stdio.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: stdio.c,v 1.49 2001/08/28 16:06:59 gshapiro Exp $")
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h> /* FreeBSD: FD_ZERO needs <string.h> */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sm/heap.h>
+#include <sm/assert.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include <sm/fdset.h>
+#include <sm/setjmp.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** Overall:
+** Small standard I/O/seek/close functions.
+** These maintain the `known seek offset' for seek optimization.
+*/
+
+/*
+** SM_STDOPEN -- open a file with stdio behavior
+**
+** Not associated with the system's stdio in libc.
+**
+** Parameters:
+** fp -- file pointer to be associated with the open
+** info -- pathname of the file to be opened
+** flags -- indicates type of access methods
+** rpool -- ignored
+**
+** Returns:
+** Failure: -1 and set errno
+** Success: 0 or greater (fd of file from open(2)).
+**
+*/
+
+/* ARGSUSED3 */
+int
+sm_stdopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ char *path = (char *) info;
+ int oflags;
+
+ switch (flags)
+ {
+ case SM_IO_RDWR:
+ oflags = O_RDWR;
+ break;
+ case SM_IO_RDWRTR:
+ oflags = O_RDWR | O_CREAT | O_TRUNC;
+ break;
+ case SM_IO_RDONLY:
+ oflags = O_RDONLY;
+ break;
+ case SM_IO_WRONLY:
+ oflags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case SM_IO_APPEND:
+ oflags = O_APPEND | O_WRONLY | O_CREAT;
+ break;
+ case SM_IO_APPENDRW:
+ oflags = O_APPEND | O_RDWR | O_CREAT;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ fp->f_file = open(path, oflags,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (fp->f_file < 0)
+ return -1; /* errno set by open() */
+
+ if (oflags & O_APPEND)
+ (void) (*fp->f_seek)((void *)fp, (off_t)0, SEEK_END);
+
+ return fp->f_file;
+}
+
+/*
+** SM_STDREAD -- read from the file
+**
+** Parameters:
+** fp -- file pointer to read from
+** buf -- location to place read data
+** n -- number of bytes to read
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: number of bytes read
+**
+** Side Effects:
+** Updates internal offset into file.
+*/
+
+ssize_t
+sm_stdread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ register int ret;
+
+ ret = read(fp->f_file, buf, n);
+
+ /* if the read succeeded, update the current offset */
+ if (ret > 0)
+ fp->f_lseekoff += ret;
+ return ret;
+}
+
+/*
+** SM_STDWRITE -- write to the file
+**
+** Parameters:
+** fp -- file pointer ro write to
+** buf -- location of data to be written
+** n - number of bytes to write
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: number of bytes written
+*/
+
+ssize_t
+sm_stdwrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ return write(fp->f_file, buf, n);
+}
+
+/*
+** SM_STDSEEK -- set the file offset position
+**
+** Parmeters:
+** fp -- file pointer to position
+** offset -- how far to position from "base" (set by 'whence')
+** whence -- indicates where the "base" of the 'offset' to start
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: the current offset
+**
+** Side Effects:
+** Updates the internal value of the offset.
+*/
+
+off_t
+sm_stdseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ register off_t ret;
+
+ ret = lseek(fp->f_file, (off_t) offset, whence);
+ if (ret != (off_t) -1)
+ fp->f_lseekoff = ret;
+ return ret;
+}
+
+/*
+** SM_STDCLOSE -- close the file
+**
+** Parameters:
+** fp -- the file pointer to close
+**
+** Returns:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stdclose(fp)
+ SM_FILE_T *fp;
+{
+ return close(fp->f_file);
+}
+
+/*
+** SM_STDSETMODE -- set the access mode for the file
+**
+** Called by sm_stdsetinfo().
+**
+** Parameters:
+** fp -- file pointer
+** mode -- new mode to set the file access to
+**
+** Results:
+** Success: 0 (zero);
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stdsetmode(fp, mode)
+ SM_FILE_T *fp;
+ const int *mode;
+{
+ int flags = 0;
+
+ switch (*mode)
+ {
+ case SM_IO_RDWR:
+ flags |= SMRW;
+ break;
+ case SM_IO_RDONLY:
+ flags |= SMRD;
+ break;
+ case SM_IO_WRONLY:
+ flags |= SMWR;
+ break;
+ case SM_IO_APPEND:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ fp->f_flags = fp->f_flags & ~SMMODEMASK;
+ fp->f_flags |= flags;
+ return 0;
+}
+
+/*
+** SM_STDGETMODE -- for getinfo determine open mode
+**
+** Called by sm_stdgetinfo().
+**
+** Parameters:
+** fp -- the file mode being determined
+** mode -- internal mode to map to external value
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: external mode value
+*/
+
+int
+sm_stdgetmode(fp, mode)
+ SM_FILE_T *fp;
+ int *mode;
+{
+ switch (fp->f_flags & SMMODEMASK)
+ {
+ case SMRW:
+ *mode = SM_IO_RDWR;
+ break;
+ case SMRD:
+ *mode = SM_IO_RDONLY;
+ break;
+ case SMWR:
+ *mode = SM_IO_WRONLY;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** SM_STDSETINFO -- set/modify information for a file
+**
+** Parameters:
+** fp -- file to set info for
+** what -- type of info to set
+** valp -- location of data used for setting
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0
+*/
+
+int
+sm_stdsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_stdsetmode(fp, (const int *)valp);
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_GETINFO -- get information about the open file
+**
+** Parameters:
+** fp -- file to get info for
+** what -- type of info to get
+** valp -- location to place found info
+**
+** Returns:
+** Success: may or may not place info in 'valp' depending
+** on 'what' value, and returns values >=0. Return
+** value may be the obtained info
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stdgetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_stdgetmode(fp, (int *)valp);
+
+ case SM_IO_WHAT_FD:
+ return fp->f_file;
+
+ case SM_IO_IS_READABLE:
+ {
+ fd_set readfds;
+ struct timeval timeout;
+
+ FD_ZERO(&readfds);
+ SM_FD_SET(fp->f_file, &readfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (select(fp->f_file + 1,
+ FDSET_CAST &readfds,
+ NULL,
+ NULL,
+ &timeout) > 0 &&
+ SM_FD_ISSET(fp->f_file, &readfds))
+ return 1;
+ return 0;
+ }
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STDFDOPEN -- open file by primative 'fd' rather than pathname
+**
+** I/O function to handle fdopen() stdio equivalence. The rest of
+** the functions are the same as the sm_stdopen() above.
+**
+** Parameters:
+** fp -- the file pointer to be associated with the open
+** name -- the primative file descriptor for association
+** flags -- indicates type of access methods
+** rpool -- ignored
+**
+** Results:
+** Success: primative file descriptor value
+** Failure: -1 and sets errno
+*/
+
+/* ARGSUSED3 */
+int
+sm_stdfdopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ int oflags, tmp, fdflags, fd = (int) info;
+
+ switch (flags)
+ {
+ case SM_IO_RDWR:
+ oflags = O_RDWR | O_CREAT;
+ break;
+ case SM_IO_RDONLY:
+ oflags = O_RDONLY;
+ break;
+ case SM_IO_WRONLY:
+ oflags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case SM_IO_APPEND:
+ oflags = O_APPEND | O_WRONLY | O_CREAT;
+ break;
+ case SM_IO_APPENDRW:
+ oflags = O_APPEND | O_RDWR | O_CREAT;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Make sure the mode the user wants is a subset of the actual mode. */
+ if ((fdflags = fcntl(fd, F_GETFL, 0)) < 0)
+ return -1;
+
+ tmp = fdflags & O_ACCMODE;
+ if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE)))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ fp->f_file = fd;
+ if (oflags & O_APPEND)
+ (void) (*fp->f_seek)(fp, (off_t)0, SEEK_END);
+ return fp->f_file;
+}
+
+/*
+** SM_IO_FOPEN -- open a file
+**
+** Same interface and semantics as the open() system call,
+** except that it returns SM_FILE_T* instead of a file descriptor.
+**
+** Parameters:
+** pathname -- path of file to open
+** flags -- flags controlling the open
+** ... -- option "mode" for opening the file
+**
+** Returns:
+** Raises an exception on heap exhaustion.
+** Returns NULL and sets errno if open() fails.
+** Returns an SM_FILE_T pointer on success.
+*/
+
+SM_FILE_T *
+#if SM_VA_STD
+sm_io_fopen(char *pathname, int flags, ...)
+#else /* SM_VA_STD */
+sm_io_fopen(pathname, flags, va_alist)
+ char *pathname;
+ int flags;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ MODE_T mode;
+ SM_FILE_T *fp;
+ int ioflags;
+
+ if (flags & O_CREAT)
+ {
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, flags);
+ mode = (MODE_T) SM_VA_ARG(ap, int);
+ SM_VA_END(ap);
+ }
+ else
+ mode = 0;
+
+ switch (flags & O_ACCMODE)
+ {
+ case O_RDONLY:
+ ioflags = SMRD;
+ break;
+ case O_WRONLY:
+ ioflags = SMWR;
+ break;
+ case O_RDWR:
+ ioflags = SMRW;
+ break;
+ default:
+ sm_abort("sm_io_fopen: bad flags 0%o", flags);
+ }
+
+ fp = sm_fp(SmFtStdio, ioflags, NULL);
+ fp->f_file = open(pathname, flags, mode);
+ if (fp->f_file == -1)
+ {
+ fp->f_flags = 0;
+ fp->sm_magic = NULL;
+ return NULL;
+ }
+ return fp;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/strcasecmp.c b/gnu/usr.sbin/sendmail/libsm/strcasecmp.c
new file mode 100644
index 00000000000..f2df7f00f94
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strcasecmp.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1987, 1988, 1993
+ * The Regents of the University of California. 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("@(#)$Sendmail: strcasecmp.c,v 1.12 2001/08/27 22:09:15 gshapiro Exp $")
+
+#include <sm/config.h>
+#include <sm/string.h>
+#include <string.h>
+
+ /*
+** SM_STRCASECMP -- 8-bit clean version of strcasecmp
+**
+** Thank you, vendors, for making this all necessary.
+*/
+
+/*
+** This array is designed for mapping upper and lower case letter
+** together for a case independent comparison. The mappings are
+** based upon ascii character sequences.
+*/
+
+const unsigned char charmap[] =
+{
+ 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
+ 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
+ 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
+ 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
+ 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
+ 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+ 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
+ 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
+ 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+ 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+ 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+ 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
+ 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+ 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+ 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+ 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
+};
+
+int
+sm_strcasecmp(s1, s2)
+ const char *s1, *s2;
+{
+ const unsigned char *us1 = (const unsigned char *)s1;
+ const unsigned char *us2 = (const unsigned char *)s2;
+
+ while (charmap[*us1] == charmap[*us2])
+ {
+ if (*us1 == '\0')
+ return 0;
+ ++us1;
+ ++us2;
+ }
+ return charmap[*us1] - charmap[*us2];
+}
+
+int
+sm_strncasecmp(s1, s2, n)
+ const char *s1, *s2;
+ register size_t n;
+{
+ if (n != 0)
+ {
+ register const unsigned char *cm = charmap;
+ register const unsigned char *us1 = (const unsigned char *)s1;
+ register const unsigned char *us2 = (const unsigned char *)s2;
+
+ do
+ {
+ if (cm[*us1] != cm[*us2++])
+ return (cm[*us1] - cm[*--us2]);
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/strdup.c b/gnu/usr.sbin/sendmail/libsm/strdup.c
new file mode 100644
index 00000000000..442175edb85
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strdup.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: strdup.c,v 1.11 2001/03/03 03:06:47 ca Exp $")
+
+#include <sm/heap.h>
+#include <sm/string.h>
+
+/*
+** SM_STRNDUP_X -- Duplicate a string of a given length
+**
+** Allocates memory and copies source string (of given length) into it.
+**
+** Parameters:
+** s -- string to copy.
+** n -- length to copy.
+**
+** Returns:
+** copy of string, raises exception if out of memory.
+**
+** Side Effects:
+** allocate memory for new string.
+*/
+
+char *
+sm_strndup_x(s, n)
+ const char *s;
+ size_t n;
+{
+ char *d = sm_malloc_x(n + 1);
+
+ (void) memcpy(d, s, n);
+ d[n] = '\0';
+ return d;
+}
+
+/*
+** SM_STRDUP -- Duplicate a string
+**
+** Allocates memory and copies source string into it.
+**
+** Parameters:
+** s -- string to copy.
+**
+** Returns:
+** copy of string, NULL if out of memory.
+**
+** Side Effects:
+** allocate memory for new string.
+*/
+
+char *
+sm_strdup(s)
+ char *s;
+{
+ size_t l;
+ char *d;
+
+ l = strlen(s) + 1;
+ d = sm_malloc_tagged(l, "sm_strdup", 0, sm_heap_group());
+ if (d != NULL)
+ (void) sm_strlcpy(d, s, l);
+ return d;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/strerror.c b/gnu/usr.sbin/sendmail/libsm/strerror.c
new file mode 100644
index 00000000000..04beae8e1bf
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strerror.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. 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("@(#)$Sendmail: strerror.c,v 1.21 2001/06/17 21:31:41 ca Exp $")
+
+/*
+** define strerror for platforms that lack it.
+*/
+
+#include <errno.h>
+#include <stdio.h> /* sys_errlist, on some platforms */
+
+#include <sm/io.h> /* sm_snprintf */
+#include <sm/string.h>
+#include <sm/conf.h>
+#include <sm/errstring.h>
+
+#if !defined(ERRLIST_PREDEFINED)
+extern char *sys_errlist[];
+extern int sys_nerr;
+#endif /* !defined(ERRLIST_PREDEFINED) */
+
+#if !HASSTRERROR
+
+/*
+** STRERROR -- return error message string corresponding to an error number.
+**
+** Parameters:
+** err -- error number.
+**
+** Returns:
+** Error string (might be pointer to static buffer).
+*/
+
+char *
+strerror(err)
+ int err;
+{
+ static char buf[64];
+
+ if (err >= 0 && err < sys_nerr)
+ return (char *) sys_errlist[err];
+ else
+ {
+ (void) sm_snprintf(buf, sizeof(buf), "Error %d", err);
+ return buf;
+ }
+}
+#endif /* !HASSTRERROR */
diff --git a/gnu/usr.sbin/sendmail/libsm/strexit.c b/gnu/usr.sbin/sendmail/libsm/strexit.c
new file mode 100644
index 00000000000..241996e3800
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strexit.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: strexit.c,v 1.3 2001/01/15 18:39:11 ca Exp $")
+#include <sm/string.h>
+#include <sm/sysexits.h>
+
+/*
+** SM_STREXIT -- convert EX_* value from <sm/sysexits.h> to a character string
+**
+** This function is analogous to strerror(), except that it
+** operates on EX_* values from <sm/sysexits.h>.
+**
+** Parameters:
+** ex -- EX_* value
+**
+** Results:
+** pointer to a static message string
+*/
+
+char *
+sm_strexit(ex)
+ int ex;
+{
+ char *msg;
+ static char buf[64];
+
+ msg = sm_sysexitmsg(ex);
+ if (msg == NULL)
+ {
+ (void) sm_snprintf(buf, sizeof buf, "Unknown exit status %d",
+ ex);
+ msg = buf;
+ }
+ return msg;
+}
+
+/*
+** SM_SYSEXITMSG -- convert an EX_* value to a character string, or NULL
+**
+** Parameters:
+** ex -- EX_* value
+**
+** Results:
+** If ex is a known exit value, then a pointer to a static
+** message string is returned. Otherwise NULL is returned.
+*/
+
+char *
+sm_sysexitmsg(ex)
+ int ex;
+{
+ char *msg;
+
+ msg = sm_sysexmsg(ex);
+ if (msg != NULL)
+ return &msg[11];
+ else
+ return msg;
+}
+
+/*
+** SM_SYSEXMSG -- convert an EX_* value to a character string, or NULL
+**
+** Parameters:
+** ex -- EX_* value
+**
+** Results:
+** If ex is a known exit value, then a pointer to a static
+** string is returned. Otherwise NULL is returned.
+** The string contains the following fixed width fields:
+** [0] ':' if there is an errno value associated with this
+** exit value, otherwise ' '.
+** [1,3] 3 digit SMTP error code
+** [4] ' '
+** [5,9] 3 digit SMTP extended error code
+** [10] ' '
+** [11,] message string
+*/
+
+char *
+sm_sysexmsg(ex)
+ int ex;
+{
+ switch (ex)
+ {
+ case EX_USAGE:
+ return " 500 5.0.0 Command line usage error";
+ case EX_DATAERR:
+ return " 501 5.6.0 Data format error";
+ case EX_NOINPUT:
+ return ":550 5.3.0 Cannot open input";
+ case EX_NOUSER:
+ return " 550 5.1.1 User unknown";
+ case EX_NOHOST:
+ return " 550 5.1.2 Host unknown";
+ case EX_UNAVAILABLE:
+ return " 554 5.0.0 Service unavailable";
+ case EX_SOFTWARE:
+ return ":554 5.3.0 Internal error";
+ case EX_OSERR:
+ return ":451 4.0.0 Operating system error";
+ case EX_OSFILE:
+ return ":554 5.3.5 System file missing";
+ case EX_CANTCREAT:
+ return ":550 5.0.0 Can't create output";
+ case EX_IOERR:
+ return ":451 4.0.0 I/O error";
+ case EX_TEMPFAIL:
+ return " 450 4.0.0 Deferred";
+ case EX_PROTOCOL:
+ return " 554 5.5.0 Remote protocol error";
+ case EX_NOPERM:
+ return ":550 5.0.0 Insufficient permission";
+ case EX_CONFIG:
+ return " 554 5.3.5 Local configuration error";
+ default:
+ return NULL;
+ }
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/string.c b/gnu/usr.sbin/sendmail/libsm/string.c
new file mode 100644
index 00000000000..9948f52b703
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/string.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: string.c,v 1.1 2001/02/15 21:04:50 ca Exp $")
+
+#include <ctype.h>
+#include <errno.h>
+
+#include <sm/string.h>
+
+/*
+** STRIPQUOTES -- Strip quotes & quote bits from a string.
+**
+** Runs through a string and strips off unquoted quote
+** characters and quote bits. This is done in place.
+**
+** Parameters:
+** s -- the string to strip.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+void
+stripquotes(s)
+ char *s;
+{
+ register char *p;
+ register char *q;
+ register char c;
+
+ if (s == NULL)
+ return;
+
+ p = q = s;
+ do
+ {
+ c = *p++;
+ if (c == '\\')
+ c = *p++;
+ else if (c == '"')
+ continue;
+ *q++ = c;
+ } while (c != '\0');
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/stringf.c b/gnu/usr.sbin/sendmail/libsm/stringf.c
new file mode 100644
index 00000000000..271aa4a9380
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/stringf.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: stringf.c,v 1.13 2001/03/03 03:40:43 ca Exp $")
+#include <errno.h>
+#include <stdio.h>
+#include <sm/exc.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/varargs.h>
+
+/*
+** SM_STRINGF_X -- printf() to dynamically allocated string.
+**
+** Takes the same arguments as printf.
+** It returns a pointer to a dynamically allocated string
+** containing the text that printf would print to standard output.
+** It raises an exception on error.
+** The name comes from a PWB Unix function called stringf.
+**
+** Parameters:
+** fmt -- format string.
+** ... -- arguments for format.
+**
+** Returns:
+** Pointer to a dynamically allocated string.
+**
+** Exceptions:
+** F:sm_heap -- out of memory (via sm_vstringf_x()).
+*/
+
+char *
+#if SM_VA_STD
+sm_stringf_x(const char *fmt, ...)
+#else /* SM_VA_STD */
+sm_stringf_x(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif /* SM_VA_STD */
+{
+ SM_VA_LOCAL_DECL
+ char *s;
+
+ SM_VA_START(ap, fmt);
+ s = sm_vstringf_x(fmt, ap);
+ SM_VA_END(ap);
+ return s;
+}
+
+/*
+** SM_VSTRINGF_X -- printf() to dynamically allocated string.
+**
+** Parameters:
+** fmt -- format string.
+** ap -- arguments for format.
+**
+** Returns:
+** Pointer to a dynamically allocated string.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+char *
+sm_vstringf_x(fmt, ap)
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ char *s;
+
+ sm_vasprintf(&s, fmt, ap);
+ if (s == NULL)
+ {
+ if (errno == ENOMEM)
+ sm_exc_raise_x(&SmHeapOutOfMemory);
+ sm_exc_raisenew_x(&SmEtypeOs, errno, "sm_vasprintf", NULL);
+ }
+ return s;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/strio.c b/gnu/usr.sbin/sendmail/libsm/strio.c
new file mode 100644
index 00000000000..4883816e123
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strio.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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_IDSTR(id, "@(#)$Sendmail: strio.c,v 1.38 2001/03/06 17:27:06 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sm/rpool.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** Cookie structure for the "strio" file type
+*/
+
+struct sm_str_obj
+{
+ char *strio_base;
+ char *strio_end;
+ size_t strio_size;
+ size_t strio_offset;
+ int strio_flags;
+};
+
+typedef struct sm_str_obj SM_STR_OBJ_T;
+
+/*
+** SM_STRGROW -- increase storage space for string
+**
+** Parameters:
+** s -- current cookie
+** size -- new storage size request
+**
+** Returns:
+** true iff successful.
+*/
+
+static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t));
+
+static bool
+sm_strgrow(s, size)
+ SM_STR_OBJ_T *s;
+ size_t size;
+{
+ register void *p;
+
+ if (s->strio_size >= size)
+ return true;
+ p = sm_realloc(s->strio_base, size);
+ if (p == NULL)
+ return false;
+ s->strio_base = p;
+ s->strio_end = s->strio_base + size;
+ s->strio_size = size;
+ return true;
+}
+
+/*
+** SM_STRREAD -- read a portion of the string
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location to place read data
+** n -- number of bytes to read
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0, number of bytes read
+*/
+
+ssize_t
+sm_strread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+ int len;
+
+ if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW))
+ {
+ errno = EBADF;
+ return -1;
+ }
+ len = SM_MIN(s->strio_size - s->strio_offset, n);
+ (void) memmove(buf, s->strio_base + s->strio_offset, len);
+ s->strio_offset += len;
+ return len;
+}
+
+/*
+** SM_STRWRITE -- write a portion of the string
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- location of data for writting
+** n -- number of bytes to write
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0, number of bytes written
+*/
+
+ssize_t
+sm_strwrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+
+ if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW))
+ {
+ errno = EBADF;
+ return -1;
+ }
+ if (n + s->strio_offset > s->strio_size)
+ {
+ if (!sm_strgrow(s, n + s->strio_offset))
+ return 0;
+ }
+ (void) memmove(s->strio_base + s->strio_offset, buf, n);
+ s->strio_offset += n;
+ return n;
+}
+
+/*
+** SM_STRSEEK -- position the offset pointer for the string
+**
+** Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid
+** values for whence.
+**
+** Parameters:
+** fp -- the file pointer
+** offset -- number of bytes offset from "base"
+** whence -- determines "base" for 'offset'
+**
+** Returns:
+** Failure: -1 and sets errno
+** Success: >=0, number of bytes read
+*/
+
+off_t
+sm_strseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ register off_t ret;
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+
+reseek:
+ switch (whence)
+ {
+ case SM_IO_SEEK_SET:
+ ret = offset;
+ break;
+ case SM_IO_SEEK_CUR:
+ ret = s->strio_offset + offset;
+ break;
+ case SM_IO_SEEK_END:
+ ret = s->strio_size;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ if (ret < 0 || ret > (off_t)(size_t)(-1)) /* XXX ugly */
+ return -1;
+ if ((size_t) ret > s->strio_size)
+ {
+ if (sm_strgrow(s, (size_t)ret))
+ goto reseek;
+
+ /* errno set by sm_strgrow */
+ return -1;
+ }
+ s->strio_offset = (size_t) ret;
+ return ret;
+}
+
+/*
+** SM_STROPEN -- open a string file type
+**
+** Parameters:
+** fp -- file pointer open to be associated with
+** info -- flags for methods of access (was mode)
+** flags -- ignored
+** rpool -- resource pool to use memory from (if applicable)
+**
+** Results:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_stropen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ register SM_STR_OBJ_T *s;
+ int *strmode = (int *) info;
+
+#if SM_RPOOL
+ s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T));
+#else /* SM_RPOOL */
+ s = sm_malloc(sizeof(SM_STR_OBJ_T));
+ if (s == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+#endif /* SM_RPOOL */
+
+ fp->f_cookie = s;
+ s->strio_offset = 0;
+ s->strio_base = 0;
+ s->strio_end = 0;
+ switch (*strmode)
+ {
+ case SM_IO_RDWR:
+ s->strio_flags = SMRW;
+ break;
+ case SM_IO_RDONLY:
+ s->strio_flags = SMRD;
+ break;
+ case SM_IO_WRONLY:
+ s->strio_flags = SMWR;
+ break;
+ case SM_IO_APPEND:
+ return -1;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** SM_STRCLOSE -- close the string file type and free resources
+**
+** Parameters:
+** fp -- file pointer
+**
+** Results:
+** Success: 0 (zero)
+*/
+
+int
+sm_strclose(fp)
+ SM_FILE_T *fp;
+{
+ SM_STR_OBJ_T *s = fp->f_cookie;
+
+#if !SM_RPOOL
+ sm_free(s->strio_base);
+ s->strio_base = NULL;
+#endif /* !SM_RPOOL */
+ return 0;
+}
+
+/*
+** SM_STRSETMODE -- set mode info for the file
+**
+** Note: changing the mode can be a safe way to have the "parent"
+** set up a string that the "child" is not to modify
+**
+** Parameters:
+** fp -- the file pointer
+** mode -- location of new mode to set
+**
+** Results:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_strsetmode(fp, mode)
+ SM_FILE_T *fp;
+ const int *mode;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+ int flags;
+
+ switch (*mode)
+ {
+ case SM_IO_RDWR:
+ flags = SMRW;
+ break;
+ case SM_IO_RDONLY:
+ flags = SMRD;
+ break;
+ case SM_IO_WRONLY:
+ flags = SMWR;
+ break;
+ case SM_IO_APPEND:
+ errno = EINVAL;
+ return -1;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ s->strio_flags &= ~SMMODEMASK;
+ s->strio_flags |= flags;
+ return 0;
+}
+
+/*
+** SM_STRGETMODE -- get mode info for the file
+**
+** Parameters:
+** fp -- the file pointer
+** mode -- location to store current mode
+**
+** Results:
+** Success: 0 (zero)
+** Failure: -1 and sets errno
+*/
+
+int
+sm_strgetmode(fp, mode)
+ SM_FILE_T *fp;
+ int *mode;
+{
+ register SM_STR_OBJ_T *s = fp->f_cookie;
+
+ switch (s->strio_flags & SMMODEMASK)
+ {
+ case SMRW:
+ *mode = SM_IO_RDWR;
+ break;
+ case SMRD:
+ *mode = SM_IO_RDONLY;
+ break;
+ case SMWR:
+ *mode = SM_IO_WRONLY;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** SM_STRSETINFO -- set info for the file
+**
+** Currently only SM_IO_WHAT_MODE is supported for 'what'.
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information to set
+** valp -- location to data for doing set
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: sm_strsetmode() return [0 (zero)]
+*/
+
+int
+sm_strsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch(what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_strsetmode(fp, (int *) valp);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STRGETINFO -- get info for the file
+**
+** Currently only SM_IO_WHAT_MODE is supported for 'what'.
+**
+** Parameters:
+** fp -- the file pointer
+** what -- type of information requested
+** valp -- location to return information in
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: sm_strgetmode() return [0 (zero)]
+*/
+
+int
+sm_strgetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch(what)
+ {
+ case SM_IO_WHAT_MODE:
+ return sm_strgetmode(fp, (int *) valp);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_STRIO_INIT -- initializes a write-only string type
+**
+** Original comments below. This function does not appear to be used anywhere.
+** The same functionality can be done by changing the mode of the file.
+** ------------
+** sm_strio_init initializes an SM_FILE_T structure as a write-only file
+** that writes into the specified buffer:
+** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer.
+** Attempts to write more than size-1 characters into the buffer will fail
+** silently (no error is reported).
+** - Use sm_io_fflush to nul terminate the string in the buffer
+** (the write pointer is not advanced).
+** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc.
+**
+** Parameters:
+** fp -- file pointer
+** buf -- memory location for stored data
+** size -- size of 'buf'
+**
+** Results:
+** none.
+*/
+
+void
+sm_strio_init(fp, buf, size)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t size;
+{
+ fp->sm_magic = SmFileMagic;
+ fp->f_flags = SMWR | SMSTR;
+ fp->f_file = -1;
+ fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf;
+ fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0);
+ fp->f_lbfsize = 0;
+ fp->f_r = 0;
+ fp->f_read = NULL;
+ fp->f_seek = NULL;
+ fp->f_getinfo = NULL;
+ fp->f_setinfo = NULL;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/strl.c b/gnu/usr.sbin/sendmail/libsm/strl.c
new file mode 100644
index 00000000000..1ccd97cb812
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strl.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 1999-2001 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("@(#)$Sendmail: strl.c,v 1.25 2001/08/27 13:08:22 ca Exp $")
+#include <sm/config.h>
+#include <sm/string.h>
+
+/*
+** XXX the type of the length parameter has been changed
+** from size_t to ssize_t to avoid theoretical problems with negative
+** numbers passed into these functions.
+** The real solution to this problem is to make sure that this doesn't
+** happen, but for now we'll use this workaround.
+*/
+
+/*
+** SM_STRLCPY -- size bounded string copy
+**
+** This is a bounds-checking variant of strcpy.
+** If size > 0, copy up to size-1 characters from the nul terminated
+** string src to dst, nul terminating the result. If size == 0,
+** the dst buffer is not modified.
+** Additional note: this function has been "tuned" to run fast and tested
+** as such (versus versions in some OS's libc).
+**
+** The result is strlen(src). You can detect truncation (not all
+** of the characters in the source string were copied) using the
+** following idiom:
+**
+** char *s, buf[BUFSIZ];
+** ...
+** if (sm_strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
+** goto overflow;
+**
+** Parameters:
+** dst -- destination buffer
+** src -- source string
+** size -- size of destination buffer
+**
+** Returns:
+** strlen(src)
+*/
+
+size_t
+sm_strlcpy(dst, src, size)
+ register char *dst;
+ register const char *src;
+ ssize_t size;
+{
+ register ssize_t i;
+
+ if (size-- <= 0)
+ return strlen(src);
+ for (i = 0; i < size && (dst[i] = src[i]) != 0; i++)
+ continue;
+ dst[i] = '\0';
+ if (src[i] == '\0')
+ return i;
+ else
+ return i + strlen(src + i);
+}
+
+/*
+** SM_STRLCAT -- size bounded string concatenation
+**
+** This is a bounds-checking variant of strcat.
+** If strlen(dst) < size, then append at most size - strlen(dst) - 1
+** characters from the source string to the destination string,
+** nul terminating the result. Otherwise, dst is not modified.
+**
+** The result is the initial length of dst + the length of src.
+** You can detect overflow (not all of the characters in the
+** source string were copied) using the following idiom:
+**
+** char *s, buf[BUFSIZ];
+** ...
+** if (sm_strlcat(buf, s, sizeof(buf)) >= sizeof(buf))
+** goto overflow;
+**
+** Parameters:
+** dst -- nul-terminated destination string buffer
+** src -- nul-terminated source string
+** size -- size of destination buffer
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+*/
+
+size_t
+sm_strlcat(dst, src, size)
+ register char *dst;
+ register const char *src;
+ ssize_t size;
+{
+ register ssize_t i, j, o;
+
+ o = strlen(dst);
+ if (size < o + 1)
+ return o + strlen(src);
+ size -= o + 1;
+ for (i = 0, j = o; i < size && (dst[j] = src[i]) != 0; i++, j++)
+ continue;
+ dst[j] = '\0';
+ if (src[i] == '\0')
+ return j;
+ else
+ return j + strlen(src + i);
+}
+ /*
+** SM_STRLCAT2 -- append two strings to dst obeying length and
+** '\0' terminate it
+**
+** strlcat2 will append at most len - strlen(dst) - 1 chars.
+** terminates with '\0' if len > 0
+** dst = dst "+" src1 "+" src2
+** use this instead of sm_strlcat(dst,src1); sm_strlcat(dst,src2);
+** for better speed.
+**
+** Parameters:
+** dst -- "destination" string.
+** src1 -- "from" string 1.
+** src2 -- "from" string 2.
+** len -- max. length of "destination" string.
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+** if this is greater than len then an overflow would have
+** occurred.
+**
+*/
+
+size_t
+sm_strlcat2(dst, src1, src2, len)
+ register char *dst;
+ register const char *src1;
+ register const char *src2;
+ ssize_t len;
+{
+ register ssize_t i, j, o;
+
+ /* current size of dst */
+ o = strlen(dst);
+
+ /* max. size is less than current? */
+ if (len < o + 1)
+ return o + strlen(src1) + strlen(src2);
+
+ len -= o + 1; /* space left in dst */
+
+ /* copy the first string; i: index in src1; j: index in dst */
+ for (i = 0, j = o; i < len && (dst[j] = src1[i]) != 0; i++, j++)
+ continue;
+
+ /* src1: end reached? */
+ if (src1[i] != '\0')
+ {
+ /* no: terminate dst; there is space since i < len */
+ dst[j] = '\0';
+ return j + strlen(src1 + i) + strlen(src2);
+ }
+
+ len -= i; /* space left in dst */
+
+ /* copy the second string; i: index in src2; j: index in dst */
+ for (i = 0; i < len && (dst[j] = src2[i]) != 0; i++, j++)
+ continue;
+ dst[j] = '\0'; /* terminate dst; there is space since i < len */
+ if (src2[i] == '\0')
+ return j;
+ else
+ return j + strlen(src2 + i);
+}
+
+ /*
+** SM_STRLCPYN -- concatenate n strings and assign the result to dst
+** while obeying length and '\0' terminate it
+**
+** dst = src1 "+" src2 "+" ...
+** use this instead of sm_snprintf() for string values
+** and repeated sm_strlc*() calls for better speed.
+**
+** Parameters:
+** dst -- "destination" string.
+** len -- max. length of "destination" string.
+** n -- number of strings
+** strings...
+**
+** Returns:
+** total length of the string tried to create
+** (= initial length of dst + length of src)
+** if this is greater than len then an overflow would have
+** occurred.
+*/
+
+size_t
+#ifdef __STDC__
+sm_strlcpyn(char *dst, ssize_t len, int n, ...)
+#else /* __STDC__ */
+sm_strlcpyn(dst, len, n, va_alist)
+ register char *dst;
+ ssize_t len;
+ int n;
+ va_dcl
+#endif /* __STDC__ */
+{
+ register ssize_t i, j;
+ char *str;
+ SM_VA_LOCAL_DECL
+
+ SM_VA_START(ap, n);
+
+ if (len-- <= 0) /* This allows space for the terminating '\0' */
+ {
+ i = 0;
+ while (n-- > 0)
+ i += strlen(SM_VA_ARG(ap, char *));
+ return i;
+ }
+
+ j = 0; /* index in dst */
+
+ /* loop through all source strings */
+ while (n-- > 0)
+ {
+ str = SM_VA_ARG(ap, char *);
+
+ /* copy string; i: index in str; j: index in dst */
+ for (i = 0; j < len && (dst[j] = str[i]) != 0; i++, j++)
+ continue;
+
+ /* str: end reached? */
+ if (str[i] != '\0')
+ {
+ /* no: terminate dst; there is space since j < len */
+ dst[j] = '\0';
+ j += strlen(str + i);
+ while (n-- > 0)
+ j += strlen(SM_VA_ARG(ap, char *));
+ return j;
+ }
+ }
+
+ dst[j] = '\0'; /* terminate dst; there is space since j < len */
+ return j;
+}
+
+#if 0
+/*
+** SM_STRLAPP -- append string if it fits into buffer.
+**
+** If size > 0, copy up to size-1 characters from the nul terminated
+** string src to dst, nul terminating the result. If size == 0,
+** the dst buffer is not modified.
+**
+** This routine is useful for appending strings in a loop, e.g, instead of
+** s = buf;
+** for (ptr, ptr != NULL, ptr = next->ptr)
+** {
+** (void) sm_strlcpy(s, ptr->string, sizeof buf - (s - buf));
+** s += strlen(s);
+** }
+** replace the loop body with:
+** if (!sm_strlapp(*s, ptr->string, sizeof buf - (s - buf)))
+** break;
+** it's faster...
+**
+** XXX interface isn't completely clear (yet), hence this code is
+** not available.
+**
+**
+** Parameters:
+** dst -- (pointer to) destination buffer
+** src -- source string
+** size -- size of destination buffer
+**
+** Returns:
+** true if strlen(src) < size
+**
+** Side Effects:
+** modifies dst if append succeeds (enough space).
+*/
+
+bool
+sm_strlapp(dst, src, size)
+ register char **dst;
+ register const char *src;
+ ssize_t size;
+{
+ register size_t i;
+
+ if (size-- <= 0)
+ return false;
+ for (i = 0; i < size && ((*dst)[i] = src[i]) != '\0'; i++)
+ continue;
+ (*dst)[i] = '\0';
+ if (src[i] == '\0')
+ {
+ *dst += i;
+ return true;
+ }
+
+ /* undo */
+ (*dst)[0] = '\0';
+ return false;
+}
+#endif /* 0 */
diff --git a/gnu/usr.sbin/sendmail/libsm/strrevcmp.c b/gnu/usr.sbin/sendmail/libsm/strrevcmp.c
new file mode 100644
index 00000000000..122ac82e088
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strrevcmp.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: strrevcmp.c,v 1.2 2001/08/27 22:21:51 gshapiro Exp $")
+
+#include <sm/config.h>
+#include <sm/string.h>
+#include <string.h>
+
+/* strcasecmp.c */
+extern const unsigned char charmap[];
+
+/*
+** SM_STRREVCASECMP -- compare two strings starting at the end (ignore case)
+**
+** Parameters:
+** s1 -- first string.
+** s2 -- second string.
+**
+** Returns:
+** strcasecmp(reverse(s1), reverse(s2))
+*/
+
+int
+sm_strrevcasecmp(s1, s2)
+ const char *s1, *s2;
+{
+ register int i1, i2;
+
+ i1 = strlen(s1) - 1;
+ i2 = strlen(s2) - 1;
+ while (i1 >= 0 && i2 >= 0 &&
+ charmap[(unsigned char) s1[i1]] ==
+ charmap[(unsigned char) s2[i2]])
+ {
+ --i1;
+ --i2;
+ }
+ if (i1 < 0)
+ {
+ if (i2 < 0)
+ return 0;
+ else
+ return -1;
+ }
+ else
+ {
+ if (i2 < 0)
+ return 1;
+ else
+ return (charmap[(unsigned char) s1[i1]] -
+ charmap[(unsigned char) s2[i2]]);
+ }
+}
+ /*
+** SM_STRREVCMP -- compare two strings starting at the end
+**
+** Parameters:
+** s1 -- first string.
+** s2 -- second string.
+**
+** Returns:
+** strcmp(reverse(s1), reverse(s2))
+*/
+
+int
+sm_strrevcmp(s1, s2)
+ const char *s1, *s2;
+{
+ register int i1, i2;
+
+ i1 = strlen(s1) - 1;
+ i2 = strlen(s2) - 1;
+ while (i1 >= 0 && i2 >= 0 && s1[i1] == s2[i2])
+ {
+ --i1;
+ --i2;
+ }
+ if (i1 < 0)
+ {
+ if (i2 < 0)
+ return 0;
+ else
+ return -1;
+ }
+ else
+ {
+ if (i2 < 0)
+ return 1;
+ else
+ return s1[i1] - s2[i2];
+ }
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/strto.c b/gnu/usr.sbin/sendmail/libsm/strto.c
new file mode 100644
index 00000000000..0b44d169d1a
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/strto.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1992
+ * The Regents of the University of California. 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_IDSTR(id, "@(#)$Sendmail: strto.c,v 1.14 2001/08/27 22:27:14 gshapiro Exp $")
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sm/limits.h>
+#include <sm/string.h>
+
+/*
+** SM_STRTOLL -- Convert a string to a (signed) long long integer.
+**
+** Ignores `locale' stuff. Assumes that the upper and lower case
+** alphabets and digits are each contiguous.
+**
+** Parameters:
+** nptr -- string containing number
+** endptr -- location of first invalid character
+** base -- numeric base that 'nptr' number is based in
+**
+** Returns:
+** Failure: on underflow LLONG_MIN is returned; on overflow
+** LLONG_MAX is returned and errno is set.
+** When 'endptr' == '\0' then the entire string 'nptr'
+** was valid.
+** Success: returns the converted number
+*/
+
+LONGLONG_T
+sm_strtoll(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register bool neg;
+ register const char *s;
+ register LONGLONG_T acc, cutoff;
+ register int c;
+ register int any, cutlim;
+
+ /*
+ ** Skip white space and pick up leading +/- sign if any.
+ ** If base is 0, allow 0x for hex and 0 for octal, else
+ ** assume decimal; if base is already 16, allow 0x.
+ */
+
+ s = nptr;
+ do
+ {
+ c = (unsigned char) *s++;
+ } while (isascii(c) && isspace(c));
+ if (c == '-')
+ {
+ neg = true;
+ c = *s++;
+ }
+ else
+ {
+ neg = false;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X'))
+ {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ ** Compute the cutoff value between legal numbers and illegal
+ ** numbers. That is the largest legal value, divided by the
+ ** base. An input number that is greater than this value, if
+ ** followed by a legal input character, is too big. One that
+ ** is equal to this value may be valid or not; the limit
+ ** between valid and invalid numbers is then based on the last
+ ** digit. For instance, if the range for long-long's is
+ ** [-9223372036854775808..9223372036854775807] and the input base
+ ** is 10, cutoff will be set to 922337203685477580 and cutlim to
+ ** either 7 (!neg) or 8 (neg), meaning that if we have
+ ** accumulated a value > 922337203685477580, or equal but the
+ ** next digit is > 7 (or 8), the number is too big, and we will
+ ** return a range error.
+ **
+ ** Set any if any `digits' consumed; make it negative to indicate
+ ** overflow.
+ */
+
+ cutoff = neg ? LLONG_MIN : LLONG_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ if (neg)
+ {
+ if (cutlim > 0)
+ {
+ cutlim -= base;
+ cutoff += 1;
+ }
+ cutlim = -cutlim;
+ }
+ for (acc = 0, any = 0;; c = (unsigned char) *s++)
+ {
+ if (isascii(c) && isdigit(c))
+ c -= '0';
+ else if (isascii(c) && isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (neg)
+ {
+ if (acc < cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ acc = LLONG_MIN;
+ errno = ERANGE;
+ }
+ else
+ {
+ any = 1;
+ acc *= base;
+ acc -= c;
+ }
+ }
+ else
+ {
+ if (acc > cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ acc = LLONG_MAX;
+ errno = ERANGE;
+ }
+ else
+ {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ }
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return acc;
+}
+
+/*
+** SM_STRTOULL -- Convert a string to an unsigned long long integer.
+**
+** Ignores `locale' stuff. Assumes that the upper and lower case
+** alphabets and digits are each contiguous.
+**
+** Parameters:
+** nptr -- string containing (unsigned) number
+** endptr -- location of first invalid character
+** base -- numeric base that 'nptr' number is based in
+**
+** Returns:
+** Failure: on overflow ULLONG_MAX is returned and errno is set.
+** When 'endptr' == '\0' then the entire string 'nptr'
+** was valid.
+** Success: returns the converted number
+*/
+
+ULONGLONG_T
+sm_strtoull(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ register int base;
+{
+ register const char *s;
+ register ULONGLONG_T acc, cutoff;
+ register int c;
+ register bool neg;
+ register int any, cutlim;
+
+ /* See sm_strtoll for comments as to the logic used. */
+ s = nptr;
+ do
+ {
+ c = (unsigned char) *s++;
+ } while (isascii(c) && isspace(c));
+ neg = (c == '-');
+ if (neg)
+ {
+ c = *s++;
+ }
+ else
+ {
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X'))
+ {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ cutoff = ULLONG_MAX / (ULONGLONG_T)base;
+ cutlim = ULLONG_MAX % (ULONGLONG_T)base;
+ for (acc = 0, any = 0;; c = (unsigned char) *s++)
+ {
+ if (isascii(c) && isdigit(c))
+ c -= '0';
+ else if (isascii(c) && isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (acc > cutoff || (acc == cutoff && c > cutlim))
+ {
+ any = -1;
+ acc = ULLONG_MAX;
+ errno = ERANGE;
+ }
+ else
+ {
+ any = 1;
+ acc *= (ULONGLONG_T)base;
+ acc += c;
+ }
+ }
+ if (neg && any > 0)
+ acc = -((LONGLONG_T) acc);
+ if (endptr != 0)
+ *endptr = (char *) (any ? s - 1 : nptr);
+ return acc;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/syslogio.c b/gnu/usr.sbin/sendmail/libsm/syslogio.c
new file mode 100644
index 00000000000..d428f28a996
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/syslogio.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: syslogio.c,v 1.27 2001/03/04 17:55:32 ca Exp $")
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#ifdef SM_RPOOL
+# include <sm/rpool.h>
+#endif /* SM_RPOOL */
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** Overall:
+** This is a output file type that copies its output to the syslog daemon.
+** Each line of output is written as a separate syslog message.
+** The client is responsible for calling openlog() before writing to
+** any syslog file, and calling closelog() after all syslog output is complete.
+** The only state associated with a syslog file is 'int priority',
+** which we store in fp->f_ival.
+*/
+
+/*
+** SM_SYSLOGOPEN -- open a file pointer to syslog
+**
+** Parameters:
+** fp -- file pointer assigned for the open
+** info -- priority level of the syslog messages
+** flags -- not used
+** rpool -- ignored
+**
+** Returns:
+** 0 (zero) success always (see Overall)
+*/
+
+int
+sm_syslogopen(fp, info, flags, rpool)
+ SM_FILE_T *fp;
+ const void *info;
+ int flags;
+ const void *rpool;
+{
+ int *priority = (int *)info;
+
+ fp->f_ival = *priority;
+ return 0;
+}
+
+/*
+** SM_SYSLOGREAD -- read function for syslog
+**
+** This is a "stub" function (placeholder) that always returns an error.
+** It is an error to read syslog.
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- buffer to place the data read
+** n -- number of bytes to read
+**
+** Returns:
+** -1 (error) always and sets errno
+*/
+
+ssize_t
+sm_syslogread(fp, buf, n)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t n;
+{
+ /* an error to read */
+ errno = ENODEV;
+ return -1;
+}
+
+/*
+** SM_SYSLOGWRITE -- write function for syslog
+**
+** Send output to syslog.
+**
+** Parameters:
+** fp -- the file pointer
+** buf -- buffer that the write data comes from
+** n -- number of bytes to write
+**
+** Returns:
+** 0 (zero) for success always
+*/
+
+/*
+** XXX TODO: more work needs to be done to ensure that each line of output
+** XXX written to a syslog file is mapped to exactly one syslog message.
+*/
+ssize_t
+sm_syslogwrite(fp, buf, n)
+ SM_FILE_T *fp;
+ char const *buf;
+ size_t n;
+{
+ syslog(fp->f_ival, "%s", buf);
+ return 0;
+}
+
+/*
+** SM_SYSLOGSEEK -- position the syslog file offset
+**
+** This is a "stub" function (placeholder) that always returns an error.
+** It is an error to seek syslog.
+**
+** Parameters:
+** fp -- the file pointer
+** offset -- the new offset position relative to 'whence'
+** whence -- flag indicating start of 'offset'
+**
+** Returns:
+** -1 (error) always.
+*/
+
+off_t
+sm_syslogseek(fp, offset, whence)
+ SM_FILE_T *fp;
+ off_t offset;
+ int whence;
+{
+ errno = ENODEV;
+ return -1;
+}
+
+/*
+** SM_SYSLOGCLOSE -- close the syslog file pointer
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Returns:
+** 0 (zero) success always (see Overall)
+**
+*/
+
+int
+sm_syslogclose(fp)
+ SM_FILE_T *fp;
+{
+ return 0;
+}
+
+/*
+** SM_SYSLOGSETINFO -- set information for the file pointer
+**
+** Parameters:
+** fp -- the file pointer being set
+** what -- what information is being set
+** valp -- information content being set to
+**
+** Returns:
+** -1 on failure
+** 0 (zero) on success
+**
+** Side Effects:
+** Sets internal file pointer data
+*/
+
+int
+sm_syslogsetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_SL_PRIO:
+ fp->f_ival = *((int *)(valp));
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+** SM_SYSLOGGETINFO -- get information relating to the file pointer
+**
+** Parameters:
+** fp -- the file pointer being queried
+** what -- the information type being queried
+** valp -- location to placed queried information
+**
+** Returns:
+** 0 (zero) on success
+** -1 on failure
+**
+** Side Effects:
+** Fills in 'valp' with data.
+*/
+
+int
+sm_sysloggetinfo(fp, what, valp)
+ SM_FILE_T *fp;
+ int what;
+ void *valp;
+{
+ switch (what)
+ {
+ case SM_IO_SL_PRIO:
+ *((int *)(valp)) = fp->f_ival;
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-cf.c b/gnu/usr.sbin/sendmail/libsm/t-cf.c
new file mode 100644
index 00000000000..63e000f6e44
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-cf.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2001 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_IDSTR(id, "@(#)$Sendmail: t-cf.c,v 1.5 2001/03/21 18:30:41 ca Exp $")
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sm/cf.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ SM_CF_OPT_T opt;
+ int err;
+
+ if (argc != 3)
+ {
+ fprintf(stderr, "Usage: %s .cf-file option\n", argv[0]);
+ exit(1);
+ }
+ opt.opt_name = argv[2];
+ opt.opt_val = NULL;
+ err = sm_cf_getopt(argv[1], 1, &opt);
+ if (err)
+ {
+ fprintf(stderr, "%s: %s\n", argv[1], strerror(err));
+ exit(1);
+ }
+ if (opt.opt_val == NULL)
+ printf("Error: option \"%s\" not found\n", opt.opt_name);
+ else
+ printf("%s=%s\n", opt.opt_name, opt.opt_val);
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-event.c b/gnu/usr.sbin/sendmail/libsm/t-event.c
new file mode 100644
index 00000000000..8cb0790284d
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-event.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2001 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("@(#)$Sendmail: t-event.c,v 1.5 2001/09/05 20:02:02 gshapiro Exp $")
+
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#if SM_CONF_SETITIMER
+# include <sys/time.h>
+#endif /* SM_CONF_SETITIMER */
+
+#include <sm/clock.h>
+#include <sm/test.h>
+
+int check;
+
+void
+evcheck(arg)
+ int arg;
+{
+ SM_TEST(arg == 3);
+ SM_TEST(check == 0);
+ check++;
+}
+
+void
+ev1(arg)
+ int arg;
+{
+ SM_TEST(arg == 1);
+}
+
+/* define as x if you want debug output */
+#define DBG_OUT(x)
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SM_EVENT *ev;
+
+ sm_test_begin(argc, argv, "test event handling");
+ fprintf(stdout, "this test may hang. If there is no output within twelve seconds, abort it\nand recompile with -DSM_CONF_SETITIMER=%d\n",
+ SM_CONF_SETITIMER == 0 ? 1 : 0);
+ sleep(1);
+ SM_TEST(1 == 1);
+ DBG_OUT(fprintf(stdout, "We're back, test 1 seems to work.\n"));
+ ev = sm_seteventm(1000, ev1, 1);
+ sleep(1);
+ SM_TEST(2 == 2);
+ DBG_OUT(fprintf(stdout, "We're back, test 2 seems to work.\n"));
+
+ /* schedule an event in 9s */
+ ev = sm_seteventm(9000, ev1, 2);
+ sleep(1);
+
+ /* clear the event before it can fire */
+ sm_clrevent(ev);
+ SM_TEST(3 == 3);
+ DBG_OUT(fprintf(stdout, "We're back, test 3 seems to work.\n"));
+
+ /* schedule an event in 1s */
+ check = 0;
+ ev = sm_seteventm(1000, evcheck, 3);
+ sleep(2);
+
+ /* clear the event */
+ sm_clrevent(ev);
+ SM_TEST(4 == 4);
+ SM_TEST(check == 1);
+ DBG_OUT(fprintf(stdout, "We're back, test 4 seems to work.\n"));
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-exc.c b/gnu/usr.sbin/sendmail/libsm/t-exc.c
new file mode 100644
index 00000000000..0194d87b95d
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-exc.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-exc.c,v 1.18 2001/07/05 22:46:35 gshapiro Exp $")
+
+#include <string.h>
+#include <sm/heap.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+const SM_EXC_TYPE_T EtypeTest1 =
+{
+ SmExcTypeMagic,
+ "E:test1",
+ "i",
+ sm_etype_printf,
+ "test1 exception argv[0]=%0",
+};
+
+const SM_EXC_TYPE_T EtypeTest2 =
+{
+ SmExcTypeMagic,
+ "E:test2",
+ "i",
+ sm_etype_printf,
+ "test2 exception argv[0]=%0",
+};
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ void *p;
+ int volatile x;
+ char *unknown, *cant;
+
+ sm_test_begin(argc, argv, "test exception handling");
+
+ /*
+ ** SM_TRY
+ */
+
+ cant = "can't happen";
+ x = 0;
+ SM_TRY
+ x = 1;
+ SM_END_TRY
+ SM_TEST(x == 1);
+
+ /*
+ ** SM_FINALLY-0
+ */
+
+ x = 0;
+ SM_TRY
+ x = 1;
+ SM_FINALLY
+ x = 2;
+ SM_END_TRY
+ SM_TEST(x == 2);
+
+ /*
+ ** SM_FINALLY-1
+ */
+
+ x = 0;
+ SM_TRY
+ SM_TRY
+ x = 1;
+ sm_exc_raisenew_x(&EtypeTest1, 17);
+ SM_FINALLY
+ x = 2;
+ sm_exc_raisenew_x(&EtypeTest2, 42);
+ SM_END_TRY
+ SM_EXCEPT(exc, "E:test2")
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "got exception test2: can't happen\n");
+ SM_EXCEPT(exc, "E:test1")
+ SM_TEST(x == 2 && exc->exc_argv[0].v_int == 17);
+ if (!(x == 2 && exc->exc_argv[0].v_int == 17))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "can't happen: x=%d argv[0]=%d\n",
+ x, exc->exc_argv[0].v_int);
+ }
+ SM_EXCEPT(exc, "*")
+ {
+ unknown = "unknown exception: ";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ }
+ SM_END_TRY
+
+ x = 3;
+ SM_TRY
+ x = 4;
+ sm_exc_raisenew_x(&EtypeTest1, 94);
+ SM_FINALLY
+ x = 5;
+ sm_exc_raisenew_x(&EtypeTest2, 95);
+ SM_EXCEPT(exc, "E:test2")
+ {
+ unknown = "got exception test2: ";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ }
+ SM_EXCEPT(exc, "E:test1")
+ SM_TEST(x == 5 && exc->exc_argv[0].v_int == 94);
+ if (!(x == 5 && exc->exc_argv[0].v_int == 94))
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "can't happen: x=%d argv[0]=%d\n",
+ x, exc->exc_argv[0].v_int);
+ }
+ SM_EXCEPT(exc, "*")
+ {
+ unknown = "unknown exception: ";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ }
+ SM_END_TRY
+
+ SM_TRY
+ sm_exc_raisenew_x(&SmEtypeErr, "test %d", 0);
+ SM_EXCEPT(exc, "*")
+#if DEBUG
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "test 0 got an exception, as expected:\n");
+ sm_exc_print(exc, smioout);
+#endif /* DEBUG */
+ return sm_test_end();
+ SM_END_TRY
+
+ p = sm_malloc_x((size_t)(-1));
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "sm_malloc_x unexpectedly succeeded, returning %p\n", p);
+ unknown = "sm_malloc_x unexpectedly succeeded";
+ SM_TEST(strcmp(unknown, cant) == 0);
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-float.c b/gnu/usr.sbin/sendmail/libsm/t-float.c
new file mode 100644
index 00000000000..0cbbf758d76
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-float.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-float.c,v 1.16 2001/02/02 23:11:46 ca Exp $")
+
+#include <sm/limits.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+#include <sm/types.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ double d, d2;
+ double ld;
+ char buf[128];
+ char *r;
+
+ /*
+ ** Sendmail uses printf and scanf with doubles,
+ ** so make sure that this works.
+ */
+
+ sm_test_begin(argc, argv, "test floating point stuff");
+
+ d = 1.125;
+ sm_snprintf(buf, sizeof(buf), "%d %.3f %d", 0, d, 1);
+ r = "0 1.125 1";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+
+ d = 1.125;
+ sm_snprintf(buf, sizeof(buf), "%.3f", d);
+ r = "1.125";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+ d2 = 0.0;
+ sm_io_sscanf(buf, "%lf", &d2);
+#if SM_CONF_BROKEN_STRTOD
+ if (d != d2)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "wanted %f, got %f\n", d, d2);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "error ignored since SM_CONF_BROKEN_STRTOD is set for this OS\n");
+ }
+#else /* SM_CONF_BROKEN_STRTOD */
+ if (!SM_TEST(d == d2))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "wanted %f, got %f\n", d, d2);
+#endif /* SM_CONF_BROKEN_STRTOD */
+
+ ld = 2.5;
+ sm_snprintf(buf, sizeof(buf), "%.3f %.1f", d, ld);
+ r = "1.125 2.5";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-fopen.c b/gnu/usr.sbin/sendmail/libsm/t-fopen.c
new file mode 100644
index 00000000000..0420e729634
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-fopen.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-fopen.c,v 1.6 2001/03/05 03:21:28 ca Exp $")
+
+#include <fcntl.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+/* ARGSUSED0 */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SM_FILE_T *out;
+
+ sm_test_begin(argc, argv, "test sm_io_fopen");
+ out = sm_io_fopen("foo", O_WRONLY|O_APPEND|O_CREAT, 0666);
+ SM_TEST(out != NULL);
+ if (out != NULL)
+ {
+ (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "foo\n");
+ sm_io_close(out, SM_TIME_DEFAULT);
+ }
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-heap.c b/gnu/usr.sbin/sendmail/libsm/t-heap.c
new file mode 100644
index 00000000000..e4fea360966
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-heap.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-heap.c,v 1.8 2001/03/06 17:27:36 ca Exp $")
+
+#include <sm/debug.h>
+#include <sm/heap.h>
+#include <sm/io.h>
+#include <sm/test.h>
+#include <sm/xtrap.h>
+
+#if SM_HEAP_CHECK
+extern SM_DEBUG_T SmHeapCheck;
+# define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1)
+#else /* SM_HEAP_CHECK */
+# define HEAP_CHECK 0
+#endif /* SM_HEAP_CHECK */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ void *p;
+
+ sm_test_begin(argc, argv, "test heap handling");
+ if (argc > 1)
+ sm_debug_addsettings_x(argv[1]);
+
+ p = sm_malloc(10);
+ SM_TEST(p != NULL);
+ p = sm_realloc_x(p, 20);
+ SM_TEST(p != NULL);
+ p = sm_realloc(p, 30);
+ SM_TEST(p != NULL);
+ if (HEAP_CHECK)
+ {
+ sm_dprintf("heap with 1 30-byte block allocated:\n");
+ sm_heap_report(smioout, 3);
+ }
+
+ if (HEAP_CHECK)
+ {
+ sm_free(p);
+ sm_dprintf("heap with 0 blocks allocated:\n");
+ sm_heap_report(smioout, 3);
+ sm_dprintf("xtrap count = %d\n", SmXtrapCount);
+ }
+
+#if DEBUG
+ /* this will cause a core dump */
+ sm_dprintf("about to free %p for the second time\n", p);
+ sm_free(p);
+#endif /* DEBUG */
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-match.c b/gnu/usr.sbin/sendmail/libsm/t-match.c
new file mode 100644
index 00000000000..44a7e6b7c57
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-match.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000 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_IDSTR(id, "@(#)$Sendmail: t-match.c,v 1.7 2000/12/18 18:12:12 ca Exp $")
+
+#include <sm/string.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+#define try(str, pat, want) \
+ got = sm_match(str, pat); \
+ if (!SM_TEST(got == want)) \
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, \
+ "sm_match(\"%s\", \"%s\") returns %s\n", \
+ str, pat, got ? "true" : "false");
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ bool got;
+
+ sm_test_begin(argc, argv, "test sm_match");
+
+ try("foo", "foo", true);
+ try("foo", "bar", false);
+ try("foo[bar", "foo[bar", true);
+ try("foo[bar]", "foo[bar]", false);
+ try("foob", "foo[bar]", true);
+ try("a-b", "a[]-]b", true);
+ try("abcde", "a*e", true);
+ try("[", "[[]", true);
+ try("c", "[a-z]", true);
+ try("C", "[a-z]", false);
+ try("F:sm.heap", "[!F]*", false);
+ try("E:sm.err", "[!F]*", true);
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-path.c b/gnu/usr.sbin/sendmail/libsm/t-path.c
new file mode 100644
index 00000000000..9037434136f
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-path.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-path.c,v 1.6 2001/07/05 22:47:29 gshapiro Exp $")
+
+#include <string.h>
+#include <sm/path.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *r;
+
+ sm_test_begin(argc, argv, "test path handling");
+
+ SM_TEST(sm_path_isdevnull(SM_PATH_DEVNULL));
+ r = "/dev/null";
+ SM_TEST(sm_path_isdevnull(r));
+ r = "/nev/dull";
+ SM_TEST(!sm_path_isdevnull(r));
+ r = "nul";
+ SM_TEST(!sm_path_isdevnull(r));
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-rpool.c b/gnu/usr.sbin/sendmail/libsm/t-rpool.c
new file mode 100644
index 00000000000..65dd3df3e28
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-rpool.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-rpool.c,v 1.16 2001/03/04 18:38:47 ca Exp $")
+
+#include <sm/debug.h>
+#include <sm/heap.h>
+#include <sm/rpool.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+static void
+rfree __P((
+ void *cx));
+
+static void
+rfree(cx)
+ void *cx;
+{
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "rfree freeing `%s'\n",
+ (char *) cx);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ SM_RPOOL_T *rpool;
+ char *a[26];
+ int i, j;
+ SM_RPOOL_ATTACH_T att;
+
+ sm_test_begin(argc, argv, "test rpool");
+ sm_debug_addsetting_x("sm_check_heap", 1);
+ rpool = sm_rpool_new_x(NULL);
+ SM_TEST(rpool != NULL);
+ att = sm_rpool_attach_x(rpool, rfree, "attachment #1");
+ SM_TEST(att != NULL);
+ for (i = 0; i < 26; ++i)
+ {
+ size_t sz = i * i * i;
+
+ a[i] = sm_rpool_malloc_x(rpool, sz);
+ for (j = 0; j < sz; ++j)
+ a[i][j] = 'a' + i;
+ }
+ att = sm_rpool_attach_x(rpool, rfree, "attachment #2");
+ (void) sm_rpool_attach_x(rpool, rfree, "attachment #3");
+ sm_rpool_detach(att);
+
+ /* XXX more tests? */
+#if DEBUG
+ sm_dprintf("heap after filling up rpool:\n");
+ sm_heap_report(smioout, 3);
+ sm_dprintf("freeing rpool:\n");
+ sm_rpool_free(rpool);
+ sm_dprintf("heap after freeing rpool:\n");
+ sm_heap_report(smioout, 3);
+#endif /* DEBUG */
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-scanf.c b/gnu/usr.sbin/sendmail/libsm/t-scanf.c
new file mode 100644
index 00000000000..fe2d916dae0
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-scanf.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2001 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_IDSTR(id, "@(#)$Sendmail: t-scanf.c,v 1.2 2001/08/21 20:36:46 ca Exp $")
+
+#include <sm/limits.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+#include <sm/types.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i, d, h;
+ char buf[128];
+ char *r;
+
+ sm_test_begin(argc, argv, "test scanf point stuff");
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+"If tests for \"h == 2\" fail, check whether size_t is signed on your OS.\n\
+If that is the case, add -DSM_CONF_BROKEN_SIZE_T to confENVDEF\n\
+and start over. Otherwise contact sendmail.org.\n");
+
+ d = 2;
+ sm_snprintf(buf, sizeof(buf), "%d", d);
+ r = "2";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+
+ i = sm_io_sscanf(buf, "%d", &h);
+ SM_TEST(i == 1);
+ SM_TEST(h == 2);
+
+ d = 2;
+ sm_snprintf(buf, sizeof(buf), "%d\n", d);
+ r = "2\n";
+ if (!SM_TEST(strcmp(buf, r) == 0))
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "got %s instead\n", buf);
+
+ i = sm_io_sscanf(buf, "%d", &h);
+ SM_TEST(i == 1);
+ SM_TEST(h == 2);
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-shm.c b/gnu/usr.sbin/sendmail/libsm/t-shm.c
new file mode 100644
index 00000000000..ff0d84af1a1
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-shm.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2000-2001 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("@(#)$Sendmail: t-shm.c,v 1.15 2001/08/27 23:00:05 gshapiro Exp $")
+
+#include <stdio.h>
+
+#if SM_CONF_SHM
+# include <stdlib.h>
+# include <unistd.h>
+# include <sys/wait.h>
+
+# include <sm/heap.h>
+# include <sm/string.h>
+# include <sm/test.h>
+# include <sm/shm.h>
+
+# define SHMSIZE 1024
+# define SHM_MAX 6400000
+# define T_SHMKEY 21
+
+
+/*
+** SHMINTER -- interactive testing of shared memory
+**
+** Parameters:
+** owner -- create segment.
+**
+** Returns:
+** 0 on success
+** < 0 on failure.
+*/
+
+int shminter __P((bool));
+
+int
+shminter(owner)
+ bool owner;
+{
+ int *shm, shmid;
+ int i, j, t;
+
+ shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
+ if (shm == (int *) 0)
+ {
+ perror("shminit failed");
+ return -1;
+ }
+
+ while ((t = getchar()) != EOF)
+ {
+ switch (t)
+ {
+ case 'c':
+ *shm = 0;
+ break;
+ case 'i':
+ ++*shm;
+ break;
+ case 'd':
+ --*shm;
+ break;
+ case 's':
+ sleep(1);
+ break;
+ case 'l':
+ t = *shm;
+ for (i = 0; i < SHM_MAX; i++)
+ {
+ j += i;
+ ++*shm;
+ }
+ if (*shm != SHM_MAX + t)
+ fprintf(stderr, "error: %d != %d\n",
+ *shm, SHM_MAX + t);
+ break;
+ case 'v':
+ printf("shmval: %d\n", *shm);
+ break;
+ }
+ }
+ return sm_shmstop((void *) shm, shmid, owner);
+}
+
+
+/*
+** SHMBIG -- testing of shared memory
+**
+** Parameters:
+** owner -- create segment.
+** size -- size of segment.
+**
+** Returns:
+** 0 on success
+** < 0 on failure.
+*/
+
+int shmbig __P((bool, int));
+
+int
+shmbig(owner, size)
+ bool owner;
+ int size;
+{
+ int *shm, shmid;
+ int i;
+
+ shm = (int *) sm_shmstart(T_SHMKEY, size, 0, &shmid, owner);
+ if (shm == (int *) 0)
+ {
+ perror("shminit failed");
+ return -1;
+ }
+
+ for (i = 0; i < size / sizeof(int); i++)
+ shm[i] = i;
+ for (i = 0; i < size / sizeof(int); i++)
+ {
+ if (shm[i] != i)
+ {
+ fprintf(stderr, "failed at %d: %d", i, shm[i]);
+ }
+ }
+
+ return sm_shmstop((void *) shm, shmid, owner);
+}
+
+
+/*
+** SHMTEST -- test of shared memory
+**
+** Parameters:
+** owner -- create segment.
+**
+** Returns:
+** 0 on success
+** < 0 on failure.
+*/
+
+# define MAX_CNT 10
+
+int
+shmtest(owner)
+ int owner;
+{
+ int *shm, shmid;
+ int cnt = 0;
+
+ shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
+ if (shm == (int *) 0)
+ {
+ perror("shminit failed");
+ return -1;
+ }
+
+ if (owner)
+ {
+ int r;
+
+ *shm = 1;
+ while (*shm == 1 && cnt++ < MAX_CNT)
+ sleep(1);
+ SM_TEST(cnt <= MAX_CNT);
+
+ /* release and re-acquire the segment */
+ r = sm_shmstop((void *) shm, shmid, owner);
+ SM_TEST(r == 0);
+ shm = (int *) sm_shmstart(T_SHMKEY, SHMSIZE, 0, &shmid, owner);
+ SM_TEST(shm != (int *) 0);
+ }
+ else
+ {
+ while (*shm != 1 && cnt++ < MAX_CNT)
+ sleep(1);
+ SM_TEST(cnt <= MAX_CNT);
+ *shm = 2;
+
+ /* wait a momemt so the segment is still in use */
+ sleep(2);
+ }
+ return sm_shmstop((void *) shm, shmid, owner);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ bool interactive = false;
+ bool owner = false;
+ int big = -1;
+ int ch;
+ int r = 0;
+ int status;
+ extern char *optarg;
+
+# define OPTIONS "b:io"
+ while ((ch = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch ((char) ch)
+ {
+ case 'b':
+ big = atoi(optarg);
+ break;
+
+ case 'i':
+ interactive = true;
+ break;
+
+ case 'o':
+ owner = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (interactive)
+ r = shminter(owner);
+ else if (big > 0)
+ r = shmbig(true, big);
+ else
+ {
+ pid_t pid;
+
+ if ((pid = fork()) < 0)
+ {
+ perror("fork failed\n");
+ return -1;
+ }
+
+ sm_test_begin(argc, argv, "test shared memory");
+ if (pid == 0)
+ {
+ /* give the parent the chance to setup data */
+ sleep(1);
+ r = shmtest(false);
+ }
+ else
+ {
+ r = shmtest(true);
+ (void) wait(&status);
+ }
+ SM_TEST(r == 0);
+ return sm_test_end();
+ }
+ return r;
+}
+#else /* SM_CONF_SHM */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ printf("No support for shared memory configured on this machine\n");
+ return 0;
+}
+#endif /* SM_CONF_SHM */
diff --git a/gnu/usr.sbin/sendmail/libsm/t-smstdio.c b/gnu/usr.sbin/sendmail/libsm/t-smstdio.c
new file mode 100644
index 00000000000..f7e4c078c47
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-smstdio.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-smstdio.c,v 1.9 2001/03/21 18:30:41 ca Exp $")
+
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *stream;
+ SM_FILE_T *fp;
+ char buf[128];
+ size_t n;
+ static char testmsg[] = "hello, world\n";
+
+ sm_test_begin(argc, argv,
+ "test sm_io_stdioopen, smiostdin, smiostdout");
+
+ stream = fopen("t-smstdio.1", "w");
+ SM_TEST(stream != NULL);
+
+ fp = sm_io_stdioopen(stream, "w");
+ SM_TEST(fp != NULL);
+
+ (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", testmsg);
+ sm_io_close(fp, SM_TIME_DEFAULT);
+
+#if 0
+ /*
+ ** stream should now be closed. This is a tricky way to test
+ ** if it is still open. Alas, it core dumps on Linux.
+ */
+
+ fprintf(stream, "oops! stream is still open!\n");
+ fclose(stream);
+#endif
+
+ stream = fopen("t-smstdio.1", "r");
+ SM_TEST(stream != NULL);
+
+ fp = sm_io_stdioopen(stream, "r");
+ SM_TEST(fp != NULL);
+
+ n = sm_io_read(fp, SM_TIME_DEFAULT, buf, sizeof(buf));
+ if (SM_TEST(n == strlen(testmsg)))
+ {
+ buf[n] = '\0';
+ SM_TEST(strcmp(buf, testmsg) == 0);
+ }
+
+#if 0
+
+ /*
+ ** Copy smiostdin to smiostdout
+ ** gotta think some more about how to test smiostdin and smiostdout
+ */
+
+ while ((c = sm_io_getc(smiostdin)) != SM_IO_EOF)
+ sm_io_putc(smiostdout, c);
+#endif
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-string.c b/gnu/usr.sbin/sendmail/libsm/t-string.c
new file mode 100644
index 00000000000..8a5073a938c
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-string.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-string.c,v 1.9 2001/01/26 03:28:43 ca Exp $")
+
+#include <sm/exc.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *s;
+ char buf[4096];
+ char foo[4];
+ char *r;
+ int n;
+
+ sm_test_begin(argc, argv, "test string utilities");
+
+ s = sm_stringf_x("%.3s%03d", "foobar", 42);
+ r = "foo042";
+ SM_TEST(strcmp(s, r) == 0);
+
+ s = sm_stringf_x("+%*x+", 2000, 0xCAFE);
+ sm_snprintf(buf, 4096, "+%*x+", 2000, 0xCAFE);
+ SM_TEST(strcmp(s, buf) == 0);
+
+ foo[3] = 1;
+ n = sm_snprintf(foo, sizeof(foo), "foobar%dbaz", 42);
+ SM_TEST(n == 11);
+ r = "foo";
+ SM_TEST(strcmp(foo, r) == 0);
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-strio.c b/gnu/usr.sbin/sendmail/libsm/t-strio.c
new file mode 100644
index 00000000000..ea3a50f21ce
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-strio.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-strio.c,v 1.9 2001/03/03 04:00:53 ca Exp $")
+#include <sm/string.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char buf[20];
+ char *r;
+ SM_FILE_T f;
+
+ sm_test_begin(argc, argv, "test strio");
+ (void) memset(buf, '.', 20);
+ sm_strio_init(&f, buf, 10);
+ (void) sm_io_fprintf(&f, SM_TIME_DEFAULT, "foobarbazoom");
+ sm_io_flush(&f, SM_TIME_DEFAULT);
+ r = "foobarbaz";
+ SM_TEST(strcmp(buf, r) == 0);
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-strl.c b/gnu/usr.sbin/sendmail/libsm/t-strl.c
new file mode 100644
index 00000000000..3ec903173d0
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-strl.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-strl.c,v 1.13 2001/08/27 23:00:05 gshapiro Exp $")
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sm/heap.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+#define MAXL 16
+#define N 5
+#define SIZE 128
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *s1, *s2, *s3;
+ int one, two, k;
+ char src1[N][SIZE], dst1[SIZE], dst2[SIZE];
+ char *r;
+
+ sm_test_begin(argc, argv, "test strl* string functions");
+ s1 = "abc";
+ s2 = "123";
+ s3 = sm_malloc_x(MAXL);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ SM_TEST(strcmp(s1, s3) == 0);
+
+ SM_TEST(sm_strlcat(s3, s2, 8) == 6);
+ r ="abc123";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 2) == 3);
+ r = "a";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcat(s3, s2, 3) == 4);
+ r = "a1";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, MAXL) == 7);
+ r = "abc:123";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 6) == 7);
+ r = "abc:1";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 2) == 7);
+ r = "abc";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 4) == 7);
+ r = "abc";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 5) == 7);
+ r = "abc:";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ SM_TEST(sm_strlcpy(s3, s1, 4) == 3);
+ r = ":";
+ SM_TEST(sm_strlcat2(s3, r, s2, 6) == 7);
+ r = "abc:1";
+ SM_TEST(strcmp(s3, r) == 0);
+
+ for (k = 0; k < N; k++)
+ {
+ (void) sm_strlcpy(src1[k], "abcdef", sizeof src1);
+ }
+
+ one = sm_strlcpyn(dst1, sizeof dst1, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, sizeof dst2, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 10, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, 10, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 5, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, 5, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 0, 3, src1[0], "/", src1[1]);
+ two = sm_snprintf(dst2, 0, "%s/%s", src1[0], src1[1]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, sizeof dst1, 5, src1[0], "/", src1[1], "/", src1[2]);
+ two = sm_snprintf(dst2, sizeof dst2, "%s/%s/%s", src1[0], src1[1], src1[2]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 15, 5, src1[0], "/", src1[1], "/", src1[2]);
+ two = sm_snprintf(dst2, 15, "%s/%s/%s", src1[0], src1[1], src1[2]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+ one = sm_strlcpyn(dst1, 20, 5, src1[0], "/", src1[1], "/", src1[2]);
+ two = sm_snprintf(dst2, 20, "%s/%s/%s", src1[0], src1[1], src1[2]);
+ SM_TEST(one == two);
+ SM_TEST(strcmp(dst1, dst2) == 0);
+
+ one = sm_strlcpyn(dst1, sizeof dst1, 0);
+ SM_TEST(one == 0);
+ r = "";
+ SM_TEST(strcmp(dst1, r) == 0);
+ one = sm_strlcpyn(dst1, 20, 1, src1[0]);
+ two = sm_snprintf(dst2, 20, "%s", src1[0]);
+ SM_TEST(one == two);
+ one = sm_strlcpyn(dst1, 2, 1, src1[0]);
+ two = sm_snprintf(dst2, 2, "%s", src1[0]);
+ SM_TEST(one == two);
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-strrevcmp.c b/gnu/usr.sbin/sendmail/libsm/t-strrevcmp.c
new file mode 100644
index 00000000000..41c4d98470b
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-strrevcmp.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2001 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_IDSTR(id, "@(#)$Sendmail: t-strrevcmp.c,v 1.1 2001/07/16 21:35:28 ca Exp $")
+
+#include <sm/exc.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *s1;
+ char *s2;
+
+ sm_test_begin(argc, argv, "test string compare");
+
+ s1 = "equal";
+ s2 = "equal";
+ SM_TEST(sm_strrevcmp(s1, s2) == 0);
+
+ s1 = "equal";
+ s2 = "qual";
+ SM_TEST(sm_strrevcmp(s1, s2) > 0);
+
+ s1 = "qual";
+ s2 = "equal";
+ SM_TEST(sm_strrevcmp(s1, s2) < 0);
+
+ s1 = "Equal";
+ s2 = "equal";
+ SM_TEST(sm_strrevcmp(s1, s2) < 0);
+
+ s1 = "Equal";
+ s2 = "equal";
+ SM_TEST(sm_strrevcasecmp(s1, s2) == 0);
+
+ s1 = "Equal";
+ s2 = "eQuaL";
+ SM_TEST(sm_strrevcasecmp(s1, s2) == 0);
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/t-types.c b/gnu/usr.sbin/sendmail/libsm/t-types.c
new file mode 100644
index 00000000000..b5901b64fa1
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/t-types.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(id, "@(#)$Sendmail: t-types.c,v 1.14 2001/07/30 00:01:42 ca Exp $")
+
+#include <sm/limits.h>
+#include <sm/io.h>
+#include <sm/string.h>
+#include <sm/test.h>
+#include <sm/types.h>
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ LONGLONG_T ll;
+ LONGLONG_T volatile lt;
+ ULONGLONG_T ull;
+ char buf[128];
+ char *r;
+
+ sm_test_begin(argc, argv, "test standard integral types");
+
+ SM_TEST(sizeof(LONGLONG_T) == sizeof(ULONGLONG_T));
+
+ /*
+ ** sendmail assumes that ino_t, off_t and void* can be cast
+ ** to ULONGLONG_T without losing information.
+ */
+
+ if (!SM_TEST(sizeof(ino_t) <= sizeof(ULONGLONG_T)) ||
+ !SM_TEST(sizeof(off_t) <= sizeof(ULONGLONG_T)) ||
+ !SM_TEST(sizeof(void*) <= sizeof(ULONGLONG_T)))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\
+Your C compiler appears to support a 64 bit integral type,\n\
+but libsm is not configured to use it. You will need to set\n\
+either SM_CONF_LONGLONG or SM_CONF_QUAD_T to 1. See libsm/README\n\
+for more details.\n");
+ }
+
+ /*
+ ** Most compilers notice that LLONG_MIN - 1 generate an underflow.
+ ** Some compiler generate code that will use the 'X' status bit
+ ** in a CPU and hence (LLONG_MIN - 1 > LLONG_MIN) will be false.
+ ** So we have to decide whether we want compiler warnings or
+ ** a wrong test...
+ ** Question: where do we really need what this test tests?
+ */
+
+#if SM_CONF_TEST_LLONG
+ ll = LLONG_MIN;
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "\
+Your C compiler maybe issued a warning during compilation,\n\
+please IGNORE the compiler warning!.\n");
+ lt = LLONG_MIN - 1;
+ SM_TEST(lt > ll);
+ sm_snprintf(buf, sizeof(buf), "%llx", ll);
+ r = "0";
+ if (!SM_TEST(buf[0] == '8')
+ || !SM_TEST(strspn(&buf[1], r) == sizeof(ll) * 2 - 1))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "oops: LLONG_MIN=%s\n", buf);
+ }
+
+ ll = LLONG_MAX;
+ lt = ll + 1;
+ SM_TEST(lt < ll);
+ sm_snprintf(buf, sizeof(buf), "%llx", ll);
+ r = "f";
+ if (!SM_TEST(buf[0] == '7')
+ || !SM_TEST(strspn(&buf[1], r) == sizeof(ll) * 2 - 1))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "oops: LLONG_MAX=%s\n", buf);
+ }
+#endif /* SM_CONF_TEST_LLONG */
+
+ ull = ULLONG_MAX;
+ SM_TEST(ull + 1 == 0);
+ sm_snprintf(buf, sizeof(buf), "%llx", ull);
+ r = "f";
+ SM_TEST(strspn(buf, r) == sizeof(ll) * 2);
+
+ /*
+ ** If QUAD_MAX is defined by <limits.h> then quad_t is defined.
+ ** Make sure LONGLONG_T is at least as big as quad_t.
+ */
+#ifdef QUAD_MAX
+ SM_TEST(QUAD_MAX <= LLONG_MAX);
+#endif
+
+ return sm_test_end();
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/test.c b/gnu/usr.sbin/sendmail/libsm/test.c
new file mode 100644
index 00000000000..5a186c638ad
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/test.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000-2001 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_IDSTR(Id, "@(#)$Sendmail: test.c,v 1.12 2001/03/05 03:22:41 ca Exp $")
+
+/*
+** Abstractions for writing libsm test programs.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sm/debug.h>
+#include <sm/io.h>
+#include <sm/test.h>
+
+extern char *optarg;
+extern int optind;
+extern int optopt;
+extern int opterr;
+
+int SmTestIndex;
+int SmTestNumErrors;
+bool SmTestVerbose;
+
+static char Help[] = "\
+%s [-h] [-d debugging] [-v]\n\
+\n\
+%s\n\
+\n\
+-h Display this help information.\n\
+-d debugging Set debug activation levels.\n\
+-v Verbose output.\n\
+";
+
+static char Usage[] = "\
+Usage: %s [-h] [-v]\n\
+Use %s -h for help.\n\
+";
+
+/*
+** SM_TEST_BEGIN -- initialize test system.
+**
+** Parameters:
+** argc -- argument counter.
+** argv -- argument vector.
+** testname -- description of tests.
+**
+** Results:
+** none.
+*/
+
+void
+sm_test_begin(argc, argv, testname)
+ int argc;
+ char **argv;
+ char *testname;
+{
+ int c;
+
+ SmTestIndex = 0;
+ SmTestNumErrors = 0;
+ SmTestVerbose = false;
+ opterr = 0;
+
+ while ((c = getopt(argc, argv, "vhd:")) != -1)
+ {
+ switch (c)
+ {
+ case 'v':
+ SmTestVerbose = true;
+ break;
+ case 'd':
+ sm_debug_addsettings_x(optarg);
+ break;
+ case 'h':
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, Help,
+ argv[0], testname);
+ exit(0);
+ default:
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Unknown command line option -%c\n", optopt);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, Usage,
+ argv[0], argv[0]);
+ exit(1);
+ }
+ }
+}
+
+/*
+** SM_TEST -- single test.
+**
+** Parameters:
+** success -- did test succeeed?
+** expr -- expression that has been evaluated.
+** filename -- guess...
+** lineno -- line number.
+**
+** Results:
+** value of success.
+*/
+
+bool
+sm_test(success, expr, filename, lineno)
+ bool success;
+ char *expr;
+ char *filename;
+ int lineno;
+{
+ ++SmTestIndex;
+ if (SmTestVerbose)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%d..",
+ SmTestIndex);
+ if (!success)
+ {
+ ++SmTestNumErrors;
+ if (!SmTestVerbose)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%d..", SmTestIndex);
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "bad! %s:%d %s\n", filename, lineno, expr);
+ }
+ else
+ {
+ if (SmTestVerbose)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "ok\n");
+ }
+ return success;
+}
+
+/*
+** SM_TEST_END -- end of test system.
+**
+** Parameters:
+** none.
+**
+** Results:
+** number of errors.
+*/
+
+int
+sm_test_end()
+{
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%d of %d tests completed successfully\n",
+ SmTestIndex - SmTestNumErrors, SmTestIndex);
+ if (SmTestNumErrors != 0)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "*** %d error%s in test! ***\n",
+ SmTestNumErrors,
+ SmTestNumErrors > 1 ? "s" : "");
+
+ return SmTestNumErrors;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/ungetc.c b/gnu/usr.sbin/sendmail/libsm/ungetc.c
new file mode 100644
index 00000000000..2d8f260d1f1
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/ungetc.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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_IDSTR(id, "@(#)$Sendmail: ungetc.c,v 1.26 2001/03/05 02:18:16 ca Exp $")
+
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/assert.h>
+#include <sm/conf.h>
+#include "local.h"
+
+/*
+** SM_SUBMORE_X -- expand ungetc buffer
+**
+** Expand the ungetc buffer `in place'. That is, adjust fp->f_p when
+** the buffer moves, so that it points the same distance from the end,
+** and move the bytes in the buffer around as necessary so that they
+** are all at the end (stack-style).
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Results:
+** none.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+static void
+sm_submore_x(fp)
+ register SM_FILE_T *fp;
+{
+ register int i;
+ register unsigned char *p;
+
+ if (fp->f_ub.smb_base == fp->f_ubuf)
+ {
+ /* Get a buffer; f_ubuf is fixed size. */
+ p = sm_malloc_x((size_t) SM_IO_BUFSIZ);
+ fp->f_ub.smb_base = p;
+ fp->f_ub.smb_size = SM_IO_BUFSIZ;
+ p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf);
+ for (i = sizeof(fp->f_ubuf); --i >= 0;)
+ p[i] = fp->f_ubuf[i];
+ fp->f_p = p;
+ return;
+ }
+ i = fp->f_ub.smb_size;
+ p = sm_realloc_x(fp->f_ub.smb_base, i << 1);
+
+ /* no overlap (hence can use memcpy) because we doubled the size */
+ (void) memcpy((void *) (p + i), (void *) p, (size_t) i);
+ fp->f_p = p + i;
+ fp->f_ub.smb_base = p;
+ fp->f_ub.smb_size = i << 1;
+}
+
+/*
+** SM_IO_UNGETC -- place a character back into the buffer just read
+**
+** Parameters:
+** fp -- the file pointer affected
+** timeout -- time to complete ungetc
+** c -- the character to place back
+**
+** Results:
+** On success, returns value of character placed back, 0-255.
+** Returns SM_IO_EOF if c == SM_IO_EOF or if last operation
+** was a write and flush failed.
+**
+** Exceptions:
+** F:sm_heap -- out of memory
+*/
+
+int
+sm_io_ungetc(fp, timeout, c)
+ register SM_FILE_T *fp;
+ int timeout;
+ int c;
+{
+ SM_REQUIRE_ISA(fp, SmFileMagic);
+ if (c == SM_IO_EOF)
+ return SM_IO_EOF;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Ungetting the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+
+ if (!Sm_IO_DidInit)
+ sm_init();
+ if ((fp->f_flags & SMRD) == 0)
+ {
+ /*
+ ** Not already reading: no good unless reading-and-writing.
+ ** Otherwise, flush any current write stuff.
+ */
+
+ if ((fp->f_flags & SMRW) == 0)
+ return SM_IO_EOF;
+ if (fp->f_flags & SMWR)
+ {
+ if (sm_flush(fp, &timeout))
+ return SM_IO_EOF;
+ fp->f_flags &= ~SMWR;
+ fp->f_w = 0;
+ fp->f_lbfsize = 0;
+ }
+ fp->f_flags |= SMRD;
+ }
+ c = (unsigned char) c;
+
+ /*
+ ** If we are in the middle of ungetc'ing, just continue.
+ ** This may require expanding the current ungetc buffer.
+ */
+
+ if (HASUB(fp))
+ {
+ if (fp->f_r >= fp->f_ub.smb_size)
+ sm_submore_x(fp);
+ *--fp->f_p = c;
+ fp->f_r++;
+ return c;
+ }
+ fp->f_flags &= ~SMFEOF;
+
+ /*
+ ** If we can handle this by simply backing up, do so,
+ ** but never replace the original character.
+ ** (This makes sscanf() work when scanning `const' data.)
+ */
+
+ if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base &&
+ fp->f_p[-1] == c)
+ {
+ fp->f_p--;
+ fp->f_r++;
+ return c;
+ }
+
+ /*
+ ** Create an ungetc buffer.
+ ** Initially, we will use the `reserve' buffer.
+ */
+
+ fp->f_ur = fp->f_r;
+ fp->f_up = fp->f_p;
+ fp->f_ub.smb_base = fp->f_ubuf;
+ fp->f_ub.smb_size = sizeof(fp->f_ubuf);
+ fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c;
+ fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1];
+ fp->f_r = 1;
+
+ return c;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vasprintf.c b/gnu/usr.sbin/sendmail/libsm/vasprintf.c
new file mode 100644
index 00000000000..5e2020fcf58
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vasprintf.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2000-2001 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.
+ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sm/gen.h>
+SM_RCSID("@(#)$Sendmail: vasprintf.c,v 1.24 2001/03/06 17:28:06 ca Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include "local.h"
+
+/*
+** SM_VASPRINTF -- printf to a dynamically allocated string
+**
+** Write 'printf' output to a dynamically allocated string
+** buffer which is returned to the caller.
+**
+** Parameters:
+** str -- *str receives a pointer to the allocated string
+** fmt -- format directives for printing
+** ap -- variable argument list
+**
+** Results:
+** On failure, set *str to NULL, set errno, and return -1.
+**
+** On success, set *str to a pointer to a nul-terminated
+** string buffer containing printf output, and return the
+** length of the string (not counting the nul).
+*/
+
+#define SM_VA_BUFSIZE 128
+
+int
+sm_vasprintf(str, fmt, ap)
+ char **str;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ SM_FILE_T fake;
+ unsigned char *base;
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR | SMALC;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)sm_malloc(SM_VA_BUFSIZE);
+ if (fake.f_bf.smb_base == NULL)
+ goto err2;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vasprintf:fake";
+ fake.f_bf.smb_size = fake.f_w = SM_VA_BUFSIZE - 1;
+ fake.f_timeout = SM_TIME_FOREVER;
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ if (ret == -1)
+ goto err;
+ *fake.f_p = '\0';
+
+ /* use no more space than necessary */
+ base = (unsigned char *) sm_realloc(fake.f_bf.smb_base, ret + 1);
+ if (base == NULL)
+ goto err;
+ *str = (char *)base;
+ return ret;
+
+err:
+ if (fake.f_bf.smb_base != NULL)
+ {
+ sm_free(fake.f_bf.smb_base);
+ fake.f_bf.smb_base = NULL;
+ }
+err2:
+ *str = NULL;
+ errno = ENOMEM;
+ return -1;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vfprintf.c b/gnu/usr.sbin/sendmail/libsm/vfprintf.c
new file mode 100644
index 00000000000..9e6e0b23a76
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vfprintf.c
@@ -0,0 +1,1107 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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_IDSTR(id, "@(#)$Sendmail: vfprintf.c,v 1.50 2001/06/24 04:22:03 ca Exp $")
+
+/*
+** Overall:
+** Actual printing innards.
+** This code is large and complicated...
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sm/config.h>
+#include <sm/varargs.h>
+#include <sm/io.h>
+#include <sm/heap.h>
+#include <sm/conf.h>
+#include "local.h"
+#include "fvwrite.h"
+
+static void sm_find_arguments __P((const char *, va_list , va_list **));
+static void sm_grow_type_table_x __P((unsigned char **, int *));
+static int sm_print __P((SM_FILE_T *, int, struct sm_uio *));
+
+/*
+** SM_PRINT -- print/flush to the file
+**
+** Flush out all the vectors defined by the given uio,
+** then reset it so that it can be reused.
+**
+** Parameters:
+** fp -- file pointer
+** timeout -- time to complete operation (milliseconds)
+** uio -- vector list of memory locations of data for printing
+**
+** Results:
+** Success: 0 (zero)
+** Failure:
+*/
+
+static int
+sm_print(fp, timeout, uio)
+ SM_FILE_T *fp;
+ int timeout;
+ register struct sm_uio *uio;
+{
+ register int err;
+
+ if (uio->uio_resid == 0)
+ {
+ uio->uio_iovcnt = 0;
+ return 0;
+ }
+ err = sm_fvwrite(fp, timeout, uio);
+ uio->uio_resid = 0;
+ uio->uio_iovcnt = 0;
+ return err;
+}
+
+/*
+** SM_BPRINTF -- allow formating to an unbuffered file.
+**
+** Helper function for `fprintf to unbuffered unix file': creates a
+** temporary buffer (via a "fake" file pointer).
+** We only work on write-only files; this avoids
+** worries about ungetc buffers and so forth.
+**
+** Parameters:
+** fp -- the file to send the o/p to
+** fmt -- format instructions for the o/p
+** ap -- vectors of data units used for formating
+**
+** Results:
+** Failure: SM_IO_EOF and errno set
+** Success: number of data units used in the formating
+**
+** Side effects:
+** formatted o/p can be SM_IO_BUFSIZ length maximum
+*/
+
+static int
+sm_bprintf(fp, fmt, ap)
+ register SM_FILE_T *fp;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ SM_FILE_T fake;
+ unsigned char buf[SM_IO_BUFSIZ];
+ extern const char SmFileMagic[];
+
+ /* copy the important variables */
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_flags = fp->f_flags & ~SMNBF;
+ fake.f_file = fp->f_file;
+ fake.f_cookie = fp->f_cookie;
+ fake.f_write = fp->f_write;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_bprintf:fake";
+
+ /* set up the buffer */
+ fake.f_bf.smb_base = fake.f_p = buf;
+ fake.f_bf.smb_size = fake.f_w = sizeof(buf);
+ fake.f_lbfsize = 0; /* not actually used, but Just In Case */
+
+ /* do the work, then copy any error status */
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ if (ret >= 0 && sm_io_flush(&fake, SM_TIME_FOREVER))
+ ret = SM_IO_EOF; /* errno set by sm_io_flush */
+ if (fake.f_flags & SMERR)
+ fp->f_flags |= SMERR;
+ return ret;
+}
+
+
+#define BUF 40
+
+#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
+
+
+/* Macros for converting digits to letters and vice versa */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned) to_digit(c) <= 9)
+#define to_char(n) ((char) (n) + '0')
+
+/* Flags used during conversion. */
+#define ALT 0x001 /* alternate form */
+#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGINT 0x010 /* long integer */
+#define QUADINT 0x020 /* quad integer */
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+
+/*
+** SM_IO_VPRINTF -- performs actual formating for o/p
+**
+** Parameters:
+** fp -- file pointer for o/p
+** timeout -- time to complete the print
+** fmt0 -- formating directives
+** ap -- vectors with data units for formating
+**
+** Results:
+** Success: number of data units used for formatting
+** Failure: SM_IO_EOF and sets errno
+*/
+
+int
+sm_io_vfprintf(fp, timeout, fmt0, ap)
+ SM_FILE_T *fp;
+ int timeout;
+ const char *fmt0;
+ SM_VA_LOCAL_DECL
+{
+ register char *fmt; /* format string */
+ register int ch; /* character from fmt */
+ register int n, m, n2; /* handy integers (short term usage) */
+ register char *cp; /* handy char pointer (short term usage) */
+ register struct sm_iov *iovp;/* for PRINT macro */
+ register int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format (%.3d), or -1 */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+ wchar_t wc;
+ ULONGLONG_T _uquad; /* integer arguments %[diouxX] */
+ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int realsz; /* field size expanded by dprec */
+ int size; /* size of converted field or string */
+ char *xdigs="0123456789abcdef"; /* digits for [xX] conversion */
+#define NIOV 8
+ struct sm_uio uio; /* output information: summary */
+ struct sm_iov iov[NIOV];/* ... and individual io vectors */
+ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
+ char ox[2]; /* space for 0x hex-prefix */
+ va_list *argtable; /* args, built due to positional arg */
+ va_list statargtable[STATIC_ARG_TBL_SIZE];
+ int nextarg; /* 1-based argument index */
+ va_list orgap; /* original argument pointer */
+
+ /*
+ ** Choose PADSIZE to trade efficiency vs. size. If larger printf
+ ** fields occur frequently, increase PADSIZE and make the initialisers
+ ** below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+ static char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+ static char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ /*
+ ** BEWARE, these `goto error' on error, and PAD uses `n'.
+ */
+#define PRINT(ptr, len) do { \
+ iovp->iov_base = (ptr); \
+ iovp->iov_len = (len); \
+ uio.uio_resid += (len); \
+ iovp++; \
+ if (++uio.uio_iovcnt >= NIOV) \
+ { \
+ if (sm_print(fp, timeout, &uio)) \
+ goto error; \
+ iovp = iov; \
+ } \
+} while (0)
+#define PAD(howmany, with) do \
+{ \
+ if ((n = (howmany)) > 0) \
+ { \
+ while (n > PADSIZE) { \
+ PRINT(with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT(with, n); \
+ } \
+} while (0)
+#define FLUSH() do \
+{ \
+ if (uio.uio_resid && sm_print(fp, timeout, &uio)) \
+ goto error; \
+ uio.uio_iovcnt = 0; \
+ iovp = iov; \
+} while (0)
+
+ /*
+ ** To extend shorts properly, we need both signed and unsigned
+ ** argument extraction methods.
+ */
+#define SARG() \
+ (flags&QUADINT ? SM_VA_ARG(ap, LONGLONG_T) : \
+ flags&LONGINT ? GETARG(long) : \
+ flags&SHORTINT ? (long) (short) GETARG(int) : \
+ (long) GETARG(int))
+#define UARG() \
+ (flags&QUADINT ? SM_VA_ARG(ap, ULONGLONG_T) : \
+ flags&LONGINT ? GETARG(unsigned long) : \
+ flags&SHORTINT ? (unsigned long) (unsigned short) GETARG(int) : \
+ (unsigned long) GETARG(unsigned int))
+
+ /*
+ ** Get * arguments, including the form *nn$. Preserve the nextarg
+ ** that the argument can be gotten once the type is determined.
+ */
+#define GETASTER(val) \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) \
+ { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') \
+ { \
+ int hold = nextarg; \
+ if (argtable == NULL) \
+ { \
+ argtable = statargtable; \
+ sm_find_arguments(fmt0, orgap, &argtable); \
+ } \
+ nextarg = n2; \
+ val = GETARG(int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } \
+ else \
+ { \
+ val = GETARG(int); \
+ }
+
+/*
+** Get the argument indexed by nextarg. If the argument table is
+** built, use it to get the argument. If its not, get the next
+** argument (and arguments must be gotten sequentially).
+*/
+
+#if SM_VA_STD
+# define GETARG(type) \
+ (((argtable != NULL) ? (void) (ap = argtable[nextarg]) : (void) 0), \
+ nextarg++, SM_VA_ARG(ap, type))
+#else /* SM_VA_STD */
+# define GETARG(type) \
+ ((argtable != NULL) ? (*((type*)(argtable[nextarg++]))) : \
+ (nextarg++, SM_VA_ARG(ap, type)))
+#endif /* SM_VA_STD */
+
+ /* sorry, fprintf(read_only_file, "") returns SM_IO_EOF, not 0 */
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->f_flags & (SMNBF|SMWR|SMRW)) == (SMNBF|SMWR) &&
+ fp->f_file >= 0)
+ return sm_bprintf(fp, fmt0, ap);
+
+ fmt = (char *) fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ SM_VA_COPY(orgap, ap);
+ uio.uio_iov = iovp = iov;
+ uio.uio_resid = 0;
+ uio.uio_iovcnt = 0;
+ ret = 0;
+
+ /* Scan the format for conversions (`%' character). */
+ for (;;)
+ {
+ cp = fmt;
+ n = 0;
+ while ((wc = *fmt) != '\0')
+ {
+ if (wc == '%')
+ {
+ n = 1;
+ break;
+ }
+ fmt++;
+ }
+ if ((m = fmt - cp) != 0)
+ {
+ PRINT(cp, m);
+ ret += m;
+ }
+ if (n <= 0)
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ sign = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch)
+ {
+ case ' ':
+
+ /*
+ ** ``If the space and + flags both appear, the space
+ ** flag will be ignored.''
+ ** -- ANSI X3J11
+ */
+
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+
+ /*
+ ** ``A negative field width argument is taken as a
+ ** - flag followed by a positive field width.''
+ ** -- ANSI X3J11
+ ** They don't exclude field widths read from args.
+ */
+
+ GETASTER(width);
+ if (width >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*')
+ {
+ GETASTER(n);
+ prec = n < 0 ? -1 : n;
+ goto rflag;
+ }
+ n = 0;
+ while (is_digit(ch))
+ {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ }
+ if (ch == '$')
+ {
+ nextarg = n;
+ if (argtable == NULL)
+ {
+ argtable = statargtable;
+ sm_find_arguments(fmt0, orgap,
+ &argtable);
+ }
+ goto rflag;
+ }
+ prec = n < 0 ? -1 : n;
+ goto reswitch;
+ case '0':
+
+ /*
+ ** ``Note that 0 is taken as a flag, not as the
+ ** beginning of a field width.''
+ ** -- ANSI X3J11
+ */
+
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do
+ {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$')
+ {
+ nextarg = n;
+ if (argtable == NULL)
+ {
+ argtable = statargtable;
+ sm_find_arguments(fmt0, orgap,
+ &argtable);
+ }
+ goto rflag;
+ }
+ width = n;
+ goto reswitch;
+ case 'h':
+ flags |= SHORTINT;
+ goto rflag;
+ case 'l':
+ if (*fmt == 'l')
+ {
+ fmt++;
+ flags |= QUADINT;
+ }
+ else
+ {
+ flags |= LONGINT;
+ }
+ goto rflag;
+ case 'q':
+ flags |= QUADINT;
+ goto rflag;
+ case 'c':
+ *(cp = buf) = GETARG(int);
+ size = 1;
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ _uquad = SARG();
+ if ((LONGLONG_T) _uquad < 0)
+ {
+ _uquad = -(LONGLONG_T) _uquad;
+ sign = '-';
+ }
+ base = DEC;
+ goto number;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ {
+ double val;
+ char *p;
+ char fmt[16];
+ char out[150];
+ size_t len;
+
+ /*
+ ** This code implements floating point output
+ ** in the most portable manner possible,
+ ** relying only on 'sprintf' as defined by
+ ** the 1989 ANSI C standard.
+ ** We silently cap width and precision
+ ** at 120, to avoid buffer overflow.
+ */
+
+ val = GETARG(double);
+
+ p = fmt;
+ *p++ = '%';
+ if (sign)
+ *p++ = sign;
+ if (flags & ALT)
+ *p++ = '#';
+ if (flags & LADJUST)
+ *p++ = '-';
+ if (flags & ZEROPAD)
+ *p++ = '0';
+ *p++ = '*';
+ if (prec >= 0)
+ {
+ *p++ = '.';
+ *p++ = '*';
+ }
+ *p++ = ch;
+ *p = '\0';
+
+ if (width > 120)
+ width = 120;
+ if (prec > 120)
+ prec = 120;
+ if (prec >= 0)
+ sprintf(out, fmt, width, prec, val);
+ else
+ sprintf(out, fmt, width, val);
+ len = strlen(out);
+ PRINT(out, len);
+ FLUSH();
+ continue;
+ }
+ case 'n':
+ if (flags & QUADINT)
+ *GETARG(LONGLONG_T *) = ret;
+ else if (flags & LONGINT)
+ *GETARG(long *) = ret;
+ else if (flags & SHORTINT)
+ *GETARG(short *) = ret;
+ else
+ *GETARG(int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ _uquad = UARG();
+ base = OCT;
+ goto nosign;
+ case 'p':
+
+ /*
+ ** ``The argument shall be a pointer to void. The
+ ** value of the pointer is converted to a sequence
+ ** of printable characters, in an implementation-
+ ** defined manner.''
+ ** -- ANSI X3J11
+ */
+
+ /* NOSTRICT */
+ {
+ union
+ {
+ void *p;
+ ULONGLONG_T ll;
+ unsigned long l;
+ unsigned i;
+ } u;
+ u.p = GETARG(void *);
+ if (sizeof(void *) == sizeof(ULONGLONG_T))
+ _uquad = u.ll;
+ else if (sizeof(void *) == sizeof(long))
+ _uquad = u.l;
+ else
+ _uquad = u.i;
+ }
+ base = HEX;
+ xdigs = "0123456789abcdef";
+ flags |= HEXPREFIX;
+ ch = 'x';
+ goto nosign;
+ case 's':
+ if ((cp = GETARG(char *)) == NULL)
+ cp = "(null)";
+ if (prec >= 0)
+ {
+ /*
+ ** can't use strlen; can only look for the
+ ** NUL in the first `prec' characters, and
+ ** strlen() will go further.
+ */
+
+ char *p = memchr(cp, 0, prec);
+
+ if (p != NULL)
+ {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ }
+ else
+ size = prec;
+ }
+ else
+ size = strlen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ _uquad = UARG();
+ base = DEC;
+ goto nosign;
+ case 'X':
+ xdigs = "0123456789ABCDEF";
+ goto hex;
+ case 'x':
+ xdigs = "0123456789abcdef";
+hex: _uquad = UARG();
+ base = HEX;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT && _uquad != 0)
+ flags |= HEXPREFIX;
+
+ /* unsigned conversions */
+nosign: sign = '\0';
+
+ /*
+ ** ``... diouXx conversions ... if a precision is
+ ** specified, the 0 flag will be ignored.''
+ ** -- ANSI X3J11
+ */
+
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*
+ ** ``The result of converting a zero value with an
+ ** explicit precision of zero is no characters.''
+ ** -- ANSI X3J11
+ */
+
+ cp = buf + BUF;
+ if (_uquad != 0 || prec != 0)
+ {
+ /*
+ ** Unsigned mod is hard, and unsigned mod
+ ** by a constant is easier than that by
+ ** a variable; hence this switch.
+ */
+
+ switch (base)
+ {
+ case OCT:
+ do
+ {
+ *--cp = to_char(_uquad & 7);
+ _uquad >>= 3;
+ } while (_uquad);
+ /* handle octal leading 0 */
+ if (flags & ALT && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case DEC:
+ /* many numbers are 1 digit */
+ while (_uquad >= 10)
+ {
+ *--cp = to_char(_uquad % 10);
+ _uquad /= 10;
+ }
+ *--cp = to_char(_uquad);
+ break;
+
+ case HEX:
+ do
+ {
+ *--cp = xdigs[_uquad & 15];
+ _uquad >>= 4;
+ } while (_uquad);
+ break;
+
+ default:
+ cp = "bug in sm_io_vfprintf: bad base";
+ size = strlen(cp);
+ goto skipsize;
+ }
+ }
+ size = buf + BUF - cp;
+ skipsize:
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *cp = ch;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ ** All reasonable formats wind up here. At this point, `cp'
+ ** points to a string which (if not flags&LADJUST) should be
+ ** padded out to `width' places. If flags&ZEROPAD, it should
+ ** first be prefixed by any sign or other prefix; otherwise,
+ ** it should be blank padded before the prefix is emitted.
+ ** After any left-hand padding and prefixing, emit zeroes
+ ** required by a decimal [diouxX] precision, then print the
+ ** string proper, then emit zeroes required by any leftover
+ ** floating precision; finally, if LADJUST, pad with blanks.
+ **
+ ** Compute actual size, so we know how much to pad.
+ ** size excludes decimal prec; realsz includes it.
+ */
+
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ else if (flags & HEXPREFIX)
+ realsz+= 2;
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign)
+ {
+ PRINT(&sign, 1);
+ }
+ else if (flags & HEXPREFIX)
+ {
+ ox[0] = '0';
+ ox[1] = ch;
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+
+ /* the string or number proper */
+ PRINT(cp, size);
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += width > realsz ? width : realsz;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ if ((argtable != NULL) && (argtable != statargtable))
+ sm_free(argtable);
+ return sm_error(fp) ? SM_IO_EOF : ret;
+ /* NOTREACHED */
+}
+
+/* Type ids for argument type table. */
+#define T_UNUSED 0
+#define T_SHORT 1
+#define T_U_SHORT 2
+#define TP_SHORT 3
+#define T_INT 4
+#define T_U_INT 5
+#define TP_INT 6
+#define T_LONG 7
+#define T_U_LONG 8
+#define TP_LONG 9
+#define T_QUAD 10
+#define T_U_QUAD 11
+#define TP_QUAD 12
+#define T_DOUBLE 13
+#define TP_CHAR 15
+#define TP_VOID 16
+
+/*
+** SM_FIND_ARGUMENTS -- find all args when a positional parameter is found.
+**
+** Find all arguments when a positional parameter is encountered. Returns a
+** table, indexed by argument number, of pointers to each arguments. The
+** initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
+** It will be replaced with a malloc-ed one if it overflows.
+**
+** Parameters:
+** fmt0 -- formating directives
+** ap -- vector list of data unit for formating consumption
+** argtable -- an indexable table (returned) of 'ap'
+**
+** Results:
+** none.
+*/
+
+static void
+sm_find_arguments(fmt0, ap, argtable)
+ const char *fmt0;
+ SM_VA_LOCAL_DECL
+ va_list **argtable;
+{
+ register char *fmt; /* format string */
+ register int ch; /* character from fmt */
+ register int n, n2; /* handy integer (short term usage) */
+ register char *cp; /* handy char pointer (short term usage) */
+ register int flags; /* flags as above */
+ unsigned char *typetable; /* table of types */
+ unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
+ int tablesize; /* current size of type table */
+ int tablemax; /* largest used index in table */
+ int nextarg; /* 1-based argument index */
+
+ /* Add an argument type to the table, expanding if necessary. */
+#define ADDTYPE(type) \
+ ((nextarg >= tablesize) ? \
+ (sm_grow_type_table_x(&typetable, &tablesize), 0) : 0, \
+ typetable[nextarg++] = type, \
+ (nextarg > tablemax) ? tablemax = nextarg : 0)
+
+#define ADDSARG() \
+ ((flags & LONGINT) ? ADDTYPE(T_LONG) : \
+ ((flags & SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT)))
+
+#define ADDUARG() \
+ ((flags & LONGINT) ? ADDTYPE(T_U_LONG) : \
+ ((flags & SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT)))
+
+ /* Add * arguments to the type array. */
+#define ADDASTER() \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) \
+ { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') \
+ { \
+ int hold = nextarg; \
+ nextarg = n2; \
+ ADDTYPE (T_INT); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } \
+ else \
+ { \
+ ADDTYPE (T_INT); \
+ }
+ fmt = (char *) fmt0;
+ typetable = stattypetable;
+ tablesize = STATIC_ARG_TBL_SIZE;
+ tablemax = 0;
+ nextarg = 1;
+ (void) memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
+
+ /* Scan the format for conversions (`%' character). */
+ for (;;)
+ {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch)
+ {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ ADDASTER();
+ goto rflag;
+ case '-':
+ case '+':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*')
+ {
+ ADDASTER();
+ goto rflag;
+ }
+ while (is_digit(ch))
+ {
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do
+ {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$')
+ {
+ nextarg = n;
+ goto rflag;
+ }
+ goto reswitch;
+ case 'h':
+ flags |= SHORTINT;
+ goto rflag;
+ case 'l':
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= QUADINT;
+ goto rflag;
+ case 'c':
+ ADDTYPE(T_INT);
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if (flags & QUADINT)
+ {
+ ADDTYPE(T_QUAD);
+ }
+ else
+ {
+ ADDSARG();
+ }
+ break;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ ADDTYPE(T_DOUBLE);
+ break;
+ case 'n':
+ if (flags & QUADINT)
+ ADDTYPE(TP_QUAD);
+ else if (flags & LONGINT)
+ ADDTYPE(TP_LONG);
+ else if (flags & SHORTINT)
+ ADDTYPE(TP_SHORT);
+ else
+ ADDTYPE(TP_INT);
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if (flags & QUADINT)
+ ADDTYPE(T_U_QUAD);
+ else
+ ADDUARG();
+ break;
+ case 'p':
+ ADDTYPE(TP_VOID);
+ break;
+ case 's':
+ ADDTYPE(TP_CHAR);
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ if (flags & QUADINT)
+ ADDTYPE(T_U_QUAD);
+ else
+ ADDUARG();
+ break;
+ case 'X':
+ case 'x':
+ if (flags & QUADINT)
+ ADDTYPE(T_U_QUAD);
+ else
+ ADDUARG();
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ /* Build the argument table. */
+ if (tablemax >= STATIC_ARG_TBL_SIZE)
+ {
+ *argtable = (va_list *)
+ sm_malloc(sizeof(va_list) * (tablemax + 1));
+ }
+
+ for (n = 1; n <= tablemax; n++)
+ {
+ SM_VA_COPY((*argtable)[n], ap);
+ switch (typetable [n])
+ {
+ case T_UNUSED:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case T_SHORT:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case T_U_SHORT:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case TP_SHORT:
+ (void) SM_VA_ARG(ap, short *);
+ break;
+ case T_INT:
+ (void) SM_VA_ARG(ap, int);
+ break;
+ case T_U_INT:
+ (void) SM_VA_ARG(ap, unsigned int);
+ break;
+ case TP_INT:
+ (void) SM_VA_ARG(ap, int *);
+ break;
+ case T_LONG:
+ (void) SM_VA_ARG(ap, long);
+ break;
+ case T_U_LONG:
+ (void) SM_VA_ARG(ap, unsigned long);
+ break;
+ case TP_LONG:
+ (void) SM_VA_ARG(ap, long *);
+ break;
+ case T_QUAD:
+ (void) SM_VA_ARG(ap, LONGLONG_T);
+ break;
+ case T_U_QUAD:
+ (void) SM_VA_ARG(ap, ULONGLONG_T);
+ break;
+ case TP_QUAD:
+ (void) SM_VA_ARG(ap, LONGLONG_T *);
+ break;
+ case T_DOUBLE:
+ (void) SM_VA_ARG(ap, double);
+ break;
+ case TP_CHAR:
+ (void) SM_VA_ARG(ap, char *);
+ break;
+ case TP_VOID:
+ (void) SM_VA_ARG(ap, void *);
+ break;
+ }
+ }
+
+ if ((typetable != NULL) && (typetable != stattypetable))
+ sm_free(typetable);
+}
+
+/*
+** SM_GROW_TYPE_TABLE -- Increase the size of the type table.
+**
+** Parameters:
+** tabletype -- type of table to grow
+** tablesize -- requested new table size
+**
+** Results:
+** Raises an exception if can't allocate memory.
+*/
+
+static void
+sm_grow_type_table_x(typetable, tablesize)
+ unsigned char **typetable;
+ int *tablesize;
+{
+ unsigned char *oldtable = *typetable;
+ int newsize = *tablesize * 2;
+
+ if (*tablesize == STATIC_ARG_TBL_SIZE)
+ {
+ *typetable = (unsigned char *) sm_malloc_x(sizeof(unsigned char)
+ * newsize);
+ (void) memmove(*typetable, oldtable, *tablesize);
+ }
+ else
+ {
+ *typetable = (unsigned char *) sm_realloc_x(typetable,
+ sizeof(unsigned char) * newsize);
+ }
+ (void) memset(&typetable [*tablesize], T_UNUSED,
+ (newsize - *tablesize));
+
+ *tablesize = newsize;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vfscanf.c b/gnu/usr.sbin/sendmail/libsm/vfscanf.c
new file mode 100644
index 00000000000..044807c6f41
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vfscanf.c
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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_IDSTR(id, "@(#)$Sendmail: vfscanf.c,v 1.49 2001/08/14 18:07:18 ca Exp $")
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sm/varargs.h>
+#include <sm/config.h>
+#include <sm/io.h>
+#include <sm/signal.h>
+#include <sm/clock.h>
+#include <sm/string.h>
+#include "local.h"
+
+#define BUF 513 /* Maximum length of numeric string. */
+
+/* Flags used during conversion. */
+#define LONG 0x01 /* l: long or double */
+#define SHORT 0x04 /* h: short */
+#define QUAD 0x08 /* q: quad (same as ll) */
+#define SUPPRESS 0x10 /* suppress assignment */
+#define POINTER 0x20 /* weird %p pointer (`fake hex') */
+#define NOSKIP 0x40 /* do not skip blanks */
+
+/*
+** The following are used in numeric conversions only:
+** SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+** SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+*/
+
+#define SIGNOK 0x080 /* +/- is (still) legal */
+#define NDIGITS 0x100 /* no digits detected */
+
+#define DPTOK 0x200 /* (float) decimal point is still legal */
+#define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */
+
+#define PFXOK 0x200 /* 0x prefix is (still) legal */
+#define NZDIGITS 0x400 /* no zero digits detected */
+
+/* Conversion types. */
+#define CT_CHAR 0 /* %c conversion */
+#define CT_CCL 1 /* %[...] conversion */
+#define CT_STRING 2 /* %s conversion */
+#define CT_INT 3 /* integer, i.e., strtoll or strtoull */
+#define CT_FLOAT 4 /* floating, i.e., strtod */
+
+static unsigned char *sm_sccl __P((char *, unsigned char *));
+static jmp_buf ScanTimeOut;
+
+/*
+** SCANALRM -- handler when timeout activated for sm_io_vfscanf()
+**
+** Returns flow of control to where setjmp(ScanTimeOut) was set.
+**
+** Parameters:
+** sig -- unused
+**
+** Returns:
+** does not return
+**
+** Side Effects:
+** returns flow of control to setjmp(ScanTimeOut).
+**
+** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
+** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
+** DOING.
+*/
+
+/* ARGSUSED0 */
+static void
+scanalrm(sig)
+ int sig;
+{
+ longjmp(ScanTimeOut, 1);
+}
+
+/*
+** SM_VFSCANF -- convert input into data units
+**
+** Parameters:
+** fp -- file pointer for input data
+** timeout -- time intvl allowed to complete (milliseconds)
+** fmt0 -- format for finding data units
+** ap -- vectors for memory location for storing data units
+**
+** Results:
+** Success: number of data units assigned
+** Failure: SM_IO_EOF
+*/
+
+int
+sm_vfscanf(fp, timeout, fmt0, ap)
+ register SM_FILE_T *fp;
+ int SM_NONVOLATILE timeout;
+ char const *fmt0;
+ va_list SM_NONVOLATILE ap;
+{
+ register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0;
+ register int c; /* character from format, or conversion */
+ register size_t width; /* field width, or 0 */
+ register char *p; /* points into all kinds of strings */
+ register int n; /* handy integer */
+ register int flags; /* flags as defined above */
+ register char *p0; /* saves original value of p when necessary */
+ int nassigned; /* number of fields assigned */
+ int nread; /* number of characters consumed from fp */
+ int base; /* base argument to strtoll/strtoull */
+ ULONGLONG_T (*ccfn)(); /* conversion function (strtoll/strtoull) */
+ char ccltab[256]; /* character class table for %[...] */
+ char buf[BUF]; /* buffer for numeric conversions */
+ SM_EVENT *evt = NULL;
+
+ /* `basefix' is used to avoid `if' tests in the integer scanner */
+ static short basefix[17] =
+ { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ if (timeout == SM_TIME_DEFAULT)
+ timeout = fp->f_timeout;
+ if (timeout == SM_TIME_IMMEDIATE)
+ {
+ /*
+ ** Filling the buffer will take time and we are wanted to
+ ** return immediately. So...
+ */
+
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+
+ if (timeout != SM_TIME_FOREVER)
+ {
+ if (setjmp(ScanTimeOut) != 0)
+ {
+ errno = EAGAIN;
+ return SM_IO_EOF;
+ }
+
+ evt = sm_seteventm(timeout, scanalrm, 0);
+ }
+
+ nassigned = 0;
+ nread = 0;
+ base = 0; /* XXX just to keep gcc happy */
+ ccfn = NULL; /* XXX just to keep gcc happy */
+ for (;;)
+ {
+ c = *fmt++;
+ if (c == 0)
+ {
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return nassigned;
+ }
+ if (isspace(c))
+ {
+ while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER)
+ == 0) &&
+ isspace(*fp->f_p))
+ nread++, fp->f_r--, fp->f_p++;
+ continue;
+ }
+ if (c != '%')
+ goto literal;
+ width = 0;
+ flags = 0;
+
+ /*
+ ** switch on the format. continue if done;
+ ** break once format type is derived.
+ */
+
+again: c = *fmt++;
+ switch (c)
+ {
+ case '%':
+literal:
+ if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
+ goto input_failure;
+ if (*fp->f_p != c)
+ goto match_failure;
+ fp->f_r--, fp->f_p++;
+ nread++;
+ continue;
+
+ case '*':
+ flags |= SUPPRESS;
+ goto again;
+ case 'h':
+ flags |= SHORT;
+ goto again;
+ case 'l':
+ if (*fmt == 'l')
+ {
+ fmt++;
+ flags |= QUAD;
+ }
+ else
+ {
+ flags |= LONG;
+ }
+ goto again;
+ case 'q':
+ flags |= QUAD;
+ goto again;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ width = width * 10 + c - '0';
+ goto again;
+
+ /*
+ ** Conversions.
+ ** Those marked `compat' are for 4.[123]BSD compatibility.
+ **
+ ** (According to ANSI, E and X formats are supposed
+ ** to the same as e and x. Sorry about that.)
+ */
+
+ case 'D': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'd':
+ c = CT_INT;
+ ccfn = (ULONGLONG_T (*)())sm_strtoll;
+ base = 10;
+ break;
+
+ case 'i':
+ c = CT_INT;
+ ccfn = (ULONGLONG_T (*)())sm_strtoll;
+ base = 0;
+ break;
+
+ case 'O': /* compat */
+ flags |= LONG;
+ /* FALLTHROUGH */
+ case 'o':
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 8;
+ break;
+
+ case 'u':
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 10;
+ break;
+
+ case 'X':
+ case 'x':
+ flags |= PFXOK; /* enable 0x prefixing */
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 16;
+ break;
+
+ case 'E':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'g':
+ c = CT_FLOAT;
+ break;
+
+ case 's':
+ c = CT_STRING;
+ break;
+
+ case '[':
+ fmt = sm_sccl(ccltab, fmt);
+ flags |= NOSKIP;
+ c = CT_CCL;
+ break;
+
+ case 'c':
+ flags |= NOSKIP;
+ c = CT_CHAR;
+ break;
+
+ case 'p': /* pointer format is like hex */
+ flags |= POINTER | PFXOK;
+ c = CT_INT;
+ ccfn = sm_strtoull;
+ base = 16;
+ break;
+
+ case 'n':
+ if (flags & SUPPRESS) /* ??? */
+ continue;
+ if (flags & SHORT)
+ *SM_VA_ARG(ap, short *) = nread;
+ else if (flags & LONG)
+ *SM_VA_ARG(ap, long *) = nread;
+ else
+ *SM_VA_ARG(ap, int *) = nread;
+ continue;
+
+ /* Disgusting backwards compatibility hacks. XXX */
+ case '\0': /* compat */
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return SM_IO_EOF;
+
+ default: /* compat */
+ if (isupper(c))
+ flags |= LONG;
+ c = CT_INT;
+ ccfn = (ULONGLONG_T (*)()) sm_strtoll;
+ base = 10;
+ break;
+ }
+
+ /* We have a conversion that requires input. */
+ if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER))
+ goto input_failure;
+
+ /*
+ ** Consume leading white space, except for formats
+ ** that suppress this.
+ */
+
+ if ((flags & NOSKIP) == 0)
+ {
+ while (isspace(*fp->f_p))
+ {
+ nread++;
+ if (--fp->f_r > 0)
+ fp->f_p++;
+ else if (sm_refill(fp, SM_TIME_FOREVER))
+ goto input_failure;
+ }
+ /*
+ ** Note that there is at least one character in
+ ** the buffer, so conversions that do not set NOSKIP
+ ** can no longer result in an input failure.
+ */
+ }
+
+ /* Do the conversion. */
+ switch (c)
+ {
+ case CT_CHAR:
+ /* scan arbitrary characters (sets NOSKIP) */
+ if (width == 0)
+ width = 1;
+ if (flags & SUPPRESS)
+ {
+ size_t sum = 0;
+ for (;;)
+ {
+ if ((size_t) (n = fp->f_r) < width)
+ {
+ sum += n;
+ width -= n;
+ fp->f_p += n;
+ if (sm_refill(fp,
+ SM_TIME_FOREVER))
+ {
+ if (sum == 0)
+ goto input_failure;
+ break;
+ }
+ }
+ else
+ {
+ sum += width;
+ fp->f_r -= width;
+ fp->f_p += width;
+ break;
+ }
+ }
+ nread += sum;
+ }
+ else
+ {
+ size_t r;
+
+ r = sm_io_read(fp, SM_TIME_FOREVER,
+ (void *) SM_VA_ARG(ap, char *),
+ width);
+ if (r == 0)
+ goto input_failure;
+ nread += r;
+ nassigned++;
+ }
+ break;
+
+ case CT_CCL:
+ /* scan a (nonempty) character class (sets NOSKIP) */
+ if (width == 0)
+ width = (size_t)~0; /* `infinity' */
+
+ /* take only those things in the class */
+ if (flags & SUPPRESS)
+ {
+ n = 0;
+ while (ccltab[*fp->f_p] != '\0')
+ {
+ n++, fp->f_r--, fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ {
+ if (n == 0) /* XXX how? */
+ goto input_failure;
+ break;
+ }
+ }
+ if (n == 0)
+ goto match_failure;
+ }
+ else
+ {
+ p0 = p = SM_VA_ARG(ap, char *);
+ while (ccltab[*fp->f_p] != '\0')
+ {
+ fp->f_r--;
+ *p++ = *fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ {
+ if (p == p0)
+ goto input_failure;
+ break;
+ }
+ }
+ n = p - p0;
+ if (n == 0)
+ goto match_failure;
+ *p = 0;
+ nassigned++;
+ }
+ nread += n;
+ break;
+
+ case CT_STRING:
+ /* like CCL, but zero-length string OK, & no NOSKIP */
+ if (width == 0)
+ width = (size_t)~0;
+ if (flags & SUPPRESS)
+ {
+ n = 0;
+ while (!isspace(*fp->f_p))
+ {
+ n++, fp->f_r--, fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ break;
+ }
+ nread += n;
+ }
+ else
+ {
+ p0 = p = SM_VA_ARG(ap, char *);
+ while (!isspace(*fp->f_p))
+ {
+ fp->f_r--;
+ *p++ = *fp->f_p++;
+ if (--width == 0)
+ break;
+ if (fp->f_r <= 0 &&
+ sm_refill(fp, SM_TIME_FOREVER))
+ break;
+ }
+ *p = 0;
+ nread += p - p0;
+ nassigned++;
+ }
+ continue;
+
+ case CT_INT:
+ /* scan an integer as if by strtoll/strtoull */
+#if SM_CONF_BROKEN_SIZE_T
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+#else /* SM_CONF_BROKEN_SIZE_T */
+ /* size_t is unsigned, hence this optimisation */
+ if (--width > sizeof(buf) - 2)
+ width = sizeof(buf) - 2;
+ width++;
+#endif /* SM_CONF_BROKEN_SIZE_T */
+ flags |= SIGNOK | NDIGITS | NZDIGITS;
+ for (p = buf; width > 0; width--)
+ {
+ c = *fp->f_p;
+
+ /*
+ ** Switch on the character; `goto ok'
+ ** if we accept it as a part of number.
+ */
+
+ switch (c)
+ {
+
+ /*
+ ** The digit 0 is always legal, but is
+ ** special. For %i conversions, if no
+ ** digits (zero or nonzero) have been
+ ** scanned (only signs), we will have
+ ** base==0. In that case, we should set
+ ** it to 8 and enable 0x prefixing.
+ ** Also, if we have not scanned zero digits
+ ** before this, do not turn off prefixing
+ ** (someone else will turn it off if we
+ ** have scanned any nonzero digits).
+ */
+
+ case '0':
+ if (base == 0)
+ {
+ base = 8;
+ flags |= PFXOK;
+ }
+ if (flags & NZDIGITS)
+ flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+ else
+ flags &= ~(SIGNOK|PFXOK|NDIGITS);
+ goto ok;
+
+ /* 1 through 7 always legal */
+ case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ base = basefix[base];
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* digits 8 and 9 ok iff decimal or hex */
+ case '8': case '9':
+ base = basefix[base];
+ if (base <= 8)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* letters ok iff hex */
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+
+ /* no need to fix base here */
+ if (base <= 10)
+ break; /* not legal here */
+ flags &= ~(SIGNOK | PFXOK | NDIGITS);
+ goto ok;
+
+ /* sign ok only as first character */
+ case '+': case '-':
+ if (flags & SIGNOK)
+ {
+ flags &= ~SIGNOK;
+ goto ok;
+ }
+ break;
+
+ /* x ok iff flag still set & 2nd char */
+ case 'x': case 'X':
+ if (flags & PFXOK && p == buf + 1)
+ {
+ base = 16; /* if %i */
+ flags &= ~PFXOK;
+ goto ok;
+ }
+ break;
+ }
+
+ /*
+ ** If we got here, c is not a legal character
+ ** for a number. Stop accumulating digits.
+ */
+
+ break;
+ ok:
+ /* c is legal: store it and look at the next. */
+ *p++ = c;
+ if (--fp->f_r > 0)
+ fp->f_p++;
+ else if (sm_refill(fp, SM_TIME_FOREVER))
+ break; /* SM_IO_EOF */
+ }
+
+ /*
+ ** If we had only a sign, it is no good; push
+ ** back the sign. If the number ends in `x',
+ ** it was [sign] '0' 'x', so push back the x
+ ** and treat it as [sign] '0'.
+ */
+
+ if (flags & NDIGITS)
+ {
+ if (p > buf)
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
+ *(unsigned char *)--p);
+ goto match_failure;
+ }
+ c = ((unsigned char *)p)[-1];
+ if (c == 'x' || c == 'X')
+ {
+ --p;
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
+ }
+ if ((flags & SUPPRESS) == 0)
+ {
+ ULONGLONG_T res;
+
+ *p = 0;
+ res = (*ccfn)(buf, (char **)NULL, base);
+ if (flags & POINTER)
+ *SM_VA_ARG(ap, void **) =
+ (void *)(long) res;
+ else if (flags & QUAD)
+ *SM_VA_ARG(ap, LONGLONG_T *) = res;
+ else if (flags & LONG)
+ *SM_VA_ARG(ap, long *) = res;
+ else if (flags & SHORT)
+ *SM_VA_ARG(ap, short *) = res;
+ else
+ *SM_VA_ARG(ap, int *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+
+ case CT_FLOAT:
+ /* scan a floating point number as if by strtod */
+ if (width == 0 || width > sizeof(buf) - 1)
+ width = sizeof(buf) - 1;
+ flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
+ for (p = buf; width; width--)
+ {
+ c = *fp->f_p;
+
+ /*
+ ** This code mimicks the integer conversion
+ ** code, but is much simpler.
+ */
+
+ switch (c)
+ {
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ flags &= ~(SIGNOK | NDIGITS);
+ goto fok;
+
+ case '+': case '-':
+ if (flags & SIGNOK)
+ {
+ flags &= ~SIGNOK;
+ goto fok;
+ }
+ break;
+ case '.':
+ if (flags & DPTOK)
+ {
+ flags &= ~(SIGNOK | DPTOK);
+ goto fok;
+ }
+ break;
+ case 'e': case 'E':
+
+ /* no exponent without some digits */
+ if ((flags&(NDIGITS|EXPOK)) == EXPOK)
+ {
+ flags =
+ (flags & ~(EXPOK|DPTOK)) |
+ SIGNOK | NDIGITS;
+ goto fok;
+ }
+ break;
+ }
+ break;
+ fok:
+ *p++ = c;
+ if (--fp->f_r > 0)
+ fp->f_p++;
+ else if (sm_refill(fp, SM_TIME_FOREVER))
+ break; /* SM_IO_EOF */
+ }
+
+ /*
+ ** If no digits, might be missing exponent digits
+ ** (just give back the exponent) or might be missing
+ ** regular digits, but had sign and/or decimal point.
+ */
+
+ if (flags & NDIGITS)
+ {
+ if (flags & EXPOK)
+ {
+ /* no digits at all */
+ while (p > buf)
+ (void) sm_io_ungetc(fp,
+ SM_TIME_DEFAULT,
+ *(unsigned char *)--p);
+ goto match_failure;
+ }
+
+ /* just a bad exponent (e and maybe sign) */
+ c = *(unsigned char *) --p;
+ if (c != 'e' && c != 'E')
+ {
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
+ c); /* sign */
+ c = *(unsigned char *)--p;
+ }
+ (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
+ }
+ if ((flags & SUPPRESS) == 0)
+ {
+ double res;
+
+ *p = 0;
+ res = strtod(buf, (char **) NULL);
+ if (flags & LONG)
+ *SM_VA_ARG(ap, double *) = res;
+ else
+ *SM_VA_ARG(ap, float *) = res;
+ nassigned++;
+ }
+ nread += p - buf;
+ break;
+ }
+ }
+input_failure:
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return nassigned ? nassigned : -1;
+match_failure:
+ if (evt != NULL)
+ sm_clrevent(evt); /* undo our timeout */
+ return nassigned;
+}
+
+/*
+** SM_SCCL -- sequenced character comparison list
+**
+** Fill in the given table from the scanset at the given format
+** (just after `['). Return a pointer to the character past the
+** closing `]'. The table has a 1 wherever characters should be
+** considered part of the scanset.
+**
+** Parameters:
+** tab -- array flagging "active" char's to match (returned)
+** fmt -- character list (within "[]")
+**
+** Results:
+*/
+
+static unsigned char *
+sm_sccl(tab, fmt)
+ register char *tab;
+ register unsigned char *fmt;
+{
+ register int c, n, v;
+
+ /* first `clear' the whole table */
+ c = *fmt++; /* first char hat => negated scanset */
+ if (c == '^')
+ {
+ v = 1; /* default => accept */
+ c = *fmt++; /* get new first char */
+ }
+ else
+ v = 0; /* default => reject */
+
+ /* should probably use memset here */
+ for (n = 0; n < 256; n++)
+ tab[n] = v;
+ if (c == 0)
+ return fmt - 1; /* format ended before closing ] */
+
+ /*
+ ** Now set the entries corresponding to the actual scanset
+ ** to the opposite of the above.
+ **
+ ** The first character may be ']' (or '-') without being special;
+ ** the last character may be '-'.
+ */
+
+ v = 1 - v;
+ for (;;)
+ {
+ tab[c] = v; /* take character c */
+doswitch:
+ n = *fmt++; /* and examine the next */
+ switch (n)
+ {
+
+ case 0: /* format ended too soon */
+ return fmt - 1;
+
+ case '-':
+ /*
+ ** A scanset of the form
+ ** [01+-]
+ ** is defined as `the digit 0, the digit 1,
+ ** the character +, the character -', but
+ ** the effect of a scanset such as
+ ** [a-zA-Z0-9]
+ ** is implementation defined. The V7 Unix
+ ** scanf treats `a-z' as `the letters a through
+ ** z', but treats `a-a' as `the letter a, the
+ ** character -, and the letter a'.
+ **
+ ** For compatibility, the `-' is not considerd
+ ** to define a range if the character following
+ ** it is either a close bracket (required by ANSI)
+ ** or is not numerically greater than the character
+ ** we just stored in the table (c).
+ */
+
+ n = *fmt;
+ if (n == ']' || n < c)
+ {
+ c = '-';
+ break; /* resume the for(;;) */
+ }
+ fmt++;
+ do
+ {
+ /* fill in the range */
+ tab[++c] = v;
+ } while (c < n);
+#if 1 /* XXX another disgusting compatibility hack */
+
+ /*
+ ** Alas, the V7 Unix scanf also treats formats
+ ** such as [a-c-e] as `the letters a through e'.
+ ** This too is permitted by the standard....
+ */
+
+ goto doswitch;
+#else
+ c = *fmt++;
+ if (c == 0)
+ return fmt - 1;
+ if (c == ']')
+ return fmt;
+ break;
+#endif
+
+ case ']': /* end of scanset */
+ return fmt;
+
+ default: /* just another character */
+ c = n;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vprintf.c b/gnu/usr.sbin/sendmail/libsm/vprintf.c
new file mode 100644
index 00000000000..cc10e50d4f5
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vprintf.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: vprintf.c,v 1.12 2001/01/24 01:27:26 gshapiro Exp $")
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_VPRINTF -- print to standard out with variable length args
+**
+** Parameters:
+** timeout -- length of time allow to do the print
+** fmt -- the format of the output
+** ap -- the variable number of args to be used for output
+**
+** Returns:
+** as sm_io_vfprintf() does.
+*/
+
+int
+sm_vprintf(timeout, fmt, ap)
+ int timeout;
+ char const *fmt;
+ SM_VA_LOCAL_DECL
+{
+ return sm_io_vfprintf(smiostdout, timeout, fmt, ap);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vsnprintf.c b/gnu/usr.sbin/sendmail/libsm/vsnprintf.c
new file mode 100644
index 00000000000..63c5c85bce7
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vsnprintf.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: vsnprintf.c,v 1.21 2001/03/04 23:28:41 ca Exp $")
+#include <limits.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_VSNPRINTF -- format data for "output" into a string
+**
+** Assigned 'str' to a "fake" file pointer. This allows common
+** o/p formatting function sm_vprintf() to be used.
+**
+** Parameters:
+** str -- location for output
+** n -- maximum size for o/p
+** fmt -- format directives
+** ap -- data unit vectors for use by 'fmt'
+**
+** Results:
+** result from sm_io_vfprintf()
+**
+** Side Effects:
+** Limits the size ('n') to INT_MAX.
+*/
+
+int
+sm_vsnprintf(str, n, fmt, ap)
+ char *str;
+ size_t n;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ char dummy;
+ SM_FILE_T fake;
+
+ /* While snprintf(3) specifies size_t stdio uses an int internally */
+ if (n > INT_MAX)
+ n = INT_MAX;
+
+ /* Stdio internals do not deal correctly with zero length buffer */
+ if (n == 0)
+ {
+ str = &dummy;
+ n = 1;
+ }
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_w = n - 1;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vsnprintf:fake";
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ *fake.f_p = 0;
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vsprintf.c b/gnu/usr.sbin/sendmail/libsm/vsprintf.c
new file mode 100644
index 00000000000..bf514ea1c85
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vsprintf.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: vsprintf.c,v 1.19 2001/03/05 03:22:41 ca Exp $")
+#include <limits.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_VSPRINTF -- format data for "output" into a string
+**
+** Assigned 'str' to a "fake" file pointer. This allows common
+** o/p formatting function sm_vprintf() to be used.
+**
+** Parameters:
+** str -- location for output
+** fmt -- format directives
+** ap -- data unit vectors for use by 'fmt'
+**
+** Results:
+** result from sm_io_vfprintf()
+**
+** Side Effects:
+** Quietly limits the size to INT_MAX though this may
+** not prevent SEGV's.
+*/
+
+int
+sm_vsprintf(str, fmt, ap)
+ char *str;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ int ret;
+ SM_FILE_T fake;
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_file = -1;
+ fake.f_flags = SMWR | SMSTR;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_w = INT_MAX;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_read = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vsprintf:fake";
+ ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap);
+ *fake.f_p = '\0';
+ return ret;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/vsscanf.c b/gnu/usr.sbin/sendmail/libsm/vsscanf.c
new file mode 100644
index 00000000000..ee298f40dbb
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/vsscanf.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at UUNET Technologies, Inc.
+ *
+ * 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("@(#)$Sendmail: vsscanf.c,v 1.20 2001/03/04 23:28:41 ca Exp $")
+#include <string.h>
+#include <sm/io.h>
+
+/*
+** SM_EOFREAD -- dummy read function for faked file below
+**
+** Parameters:
+** fp -- file pointer
+** buf -- location to place read data
+** len -- number of bytes to read
+**
+** Returns:
+** 0 (zero) always
+*/
+
+/* type declaration for later use */
+static ssize_t sm_eofread __P((SM_FILE_T *, char *, size_t));
+
+/* ARGSUSED0 */
+static ssize_t
+sm_eofread(fp, buf, len)
+ SM_FILE_T *fp;
+ char *buf;
+ size_t len;
+{
+ return 0;
+}
+
+/*
+** SM_VSSCANF -- scan a string to find data units
+**
+** Parameters:
+** str -- strings containing data
+** fmt -- format directive for finding data units
+** ap -- memory locations to place format found data units
+**
+** Returns:
+** Failure: SM_IO_EOF
+** Success: number of data units found
+**
+** Side Effects:
+** Attempts to strlen() 'str'; if not a '\0' terminated string
+** then the call may SEGV/fail.
+** Faking the string 'str' as a file.
+*/
+
+int
+sm_vsscanf(str, fmt, ap)
+ const char *str;
+ const char *fmt;
+ SM_VA_LOCAL_DECL
+{
+ SM_FILE_T fake;
+
+ fake.sm_magic = SmFileMagic;
+ fake.f_timeout = SM_TIME_FOREVER;
+ fake.f_timeoutstate = SM_TIME_BLOCK;
+ fake.f_file = -1;
+ fake.f_flags = SMRD;
+ fake.f_bf.smb_base = fake.f_p = (unsigned char *)str;
+ fake.f_bf.smb_size = fake.f_r = strlen(str);
+ fake.f_read = sm_eofread;
+ fake.f_ub.smb_base = NULL;
+ fake.f_lb.smb_base = NULL;
+ fake.f_close = NULL;
+ fake.f_open = NULL;
+ fake.f_write = NULL;
+ fake.f_seek = NULL;
+ fake.f_setinfo = fake.f_getinfo = NULL;
+ fake.f_type = "sm_vsscanf:fake";
+ return sm_vfscanf(&fake, SM_TIME_FOREVER, fmt, ap);
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/wbuf.c b/gnu/usr.sbin/sendmail/libsm/wbuf.c
new file mode 100644
index 00000000000..e72db9a8d3a
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/wbuf.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: wbuf.c,v 1.19 2001/03/05 03:22:41 ca Exp $")
+#include <errno.h>
+#include <sm/io.h>
+#include "local.h"
+
+/* Note: This function is called from a macro located in <sm/io.h> */
+
+/*
+** SM_WBUF -- write character to and flush (likely now full) buffer
+**
+** Write the given character into the (probably full) buffer for
+** the given file. Flush the buffer out if it is or becomes full,
+** or if c=='\n' and the file is line buffered.
+**
+** Parameters:
+** fp -- the file pointer
+** timeout -- time to complete operation (milliseconds)
+** c -- int representation of the character to add
+**
+** Results:
+** Failure: -1 and sets errno
+** Success: int value of 'c'
+*/
+
+int
+sm_wbuf(fp, timeout, c)
+ register SM_FILE_T *fp;
+ int timeout;
+ register int c;
+{
+ register int n;
+
+ /*
+ ** In case we cannot write, or longjmp takes us out early,
+ ** make sure w is 0 (if fully- or un-buffered) or -bf.smb_size
+ ** (if line buffered) so that we will get called again.
+ ** If we did not do this, a sufficient number of sm_io_putc()
+ ** calls might wrap w from negative to positive.
+ */
+
+ fp->f_w = fp->f_lbfsize;
+ if (cantwrite(fp))
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ c = (unsigned char)c;
+
+ /*
+ ** If it is completely full, flush it out. Then, in any case,
+ ** stuff c into the buffer. If this causes the buffer to fill
+ ** completely, or if c is '\n' and the file is line buffered,
+ ** flush it (perhaps a second time). The second flush will always
+ ** happen on unbuffered streams, where bf.smb_size==1; sm_io_flush()
+ ** guarantees that sm_io_putc() will always call sm_wbuf() by setting
+ ** w to 0, so we need not do anything else.
+ ** Note for the timeout, only one of the sm_io_flush's will get called.
+ */
+
+ n = fp->f_p - fp->f_bf.smb_base;
+ if (n >= fp->f_bf.smb_size)
+ {
+ if (sm_io_flush(fp, timeout))
+ return SM_IO_EOF; /* sm_io_flush() sets errno */
+ n = 0;
+ }
+ fp->f_w--;
+ *fp->f_p++ = c;
+ if (++n == fp->f_bf.smb_size || (fp->f_flags & SMLBF && c == '\n'))
+ if (sm_io_flush(fp, timeout))
+ return SM_IO_EOF; /* sm_io_flush() sets errno */
+ return c;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/wsetup.c b/gnu/usr.sbin/sendmail/libsm/wsetup.c
new file mode 100644
index 00000000000..67bf8b8bb1c
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/wsetup.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * 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("@(#)$Sendmail: wsetup.c,v 1.17 2001/02/28 16:56:45 ca Exp $")
+#include <stdlib.h>
+#include <errno.h>
+#include <sm/io.h>
+#include "local.h"
+
+/*
+** SM_WSETUP -- check writting is safe
+**
+** Various output routines call wsetup to be sure it is safe to write,
+** because either flags does not include SMMWR, or buf is NULL.
+** Used in the macro "cantwrite" found in "local.h".
+**
+** Parameters:
+** fp -- the file pointer
+**
+** Results:
+** Failure: SM_IO_EOF and sets errno
+** Success: 0 (zero)
+*/
+
+int
+sm_wsetup(fp)
+ register SM_FILE_T *fp;
+{
+ /* make sure stdio is set up */
+ if (!Sm_IO_DidInit)
+ sm_init();
+
+ /* If we are not writing, we had better be reading and writing. */
+ if ((fp->f_flags & SMWR) == 0)
+ {
+ if ((fp->f_flags & SMRW) == 0)
+ {
+ errno = EBADF;
+ return SM_IO_EOF;
+ }
+ if (fp->f_flags & SMRD)
+ {
+ /* clobber any ungetc data */
+ if (HASUB(fp))
+ FREEUB(fp);
+ fp->f_flags &= ~(SMRD|SMFEOF);
+ fp->f_r = 0;
+ fp->f_p = fp->f_bf.smb_base;
+ }
+ fp->f_flags |= SMWR;
+ }
+
+ /* Make a buffer if necessary, then set w. */
+ if (fp->f_bf.smb_base == NULL)
+ sm_makebuf(fp);
+ if (fp->f_flags & SMLBF)
+ {
+ /*
+ ** It is line buffered, so make lbfsize be -bufsize
+ ** for the sm_putc() macro. We will change lbfsize back
+ ** to 0 whenever we turn off SMWR.
+ */
+
+ fp->f_w = 0;
+ fp->f_lbfsize = -fp->f_bf.smb_size;
+ }
+ else
+ fp->f_w = fp->f_flags & SMNBF ? 0 : fp->f_bf.smb_size;
+ return 0;
+}
diff --git a/gnu/usr.sbin/sendmail/libsm/xtrap.c b/gnu/usr.sbin/sendmail/libsm/xtrap.c
new file mode 100644
index 00000000000..7d47209f086
--- /dev/null
+++ b/gnu/usr.sbin/sendmail/libsm/xtrap.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2000 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("@(#)$Sendmail: xtrap.c,v 1.3 2000/12/08 08:03:09 rodney Exp $")
+
+#include <sm/xtrap.h>
+
+SM_ATOMIC_UINT_T SmXtrapCount;
+
+SM_DEBUG_T SmXtrapDebug = SM_DEBUG_INITIALIZER("sm_xtrap",
+ "@(#)$Debug: sm_xtrap - raise exception at N'th xtrap point $");
+
+SM_DEBUG_T SmXtrapReport = SM_DEBUG_INITIALIZER("sm_xtrap_report",
+ "@(#)$Debug: sm_xtrap_report - report xtrap count on exit $");