---
 CHANGELOG           |    8 +
 COPYRIGHT           |   36 +++-
 daemon/automount.c  |   72 +++++--
 include/automount.h |   27 +++
 include/syslog.h    |  201 +++++++++++++++++
 lib/Makefile        |    5 +-
 lib/syslog.c        |  383 +++++++++++++++++++++++++++++++
 lib/vsprintf.c      |  619 +++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 1332 insertions(+), 19 deletions(-)
 create mode 100644 include/syslog.h
 create mode 100644 lib/syslog.c
 create mode 100644 lib/vsprintf.c

diff --git a/CHANGELOG b/CHANGELOG
index bbf4d3d..b4959ec 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,11 @@
+15/07/2010 autofs-4.1.4 - syslog patch
+--------------------------------------
+
+This patch is necessary - especially when using debug syslog messages
+and testing high mount rates. Without it I've see the daemon wedge in
+syslog. I'm pretty sure Ian Kent did the patch.
+
+
 14/07/2010 autofs-4.1.4 - bryder p42
 ------------------------------------
  Adds retrying to nfs mounts. 
diff --git a/COPYRIGHT b/COPYRIGHT
index cf647f8..ee56c0c 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -14,4 +14,38 @@ For all software in this distribution unless otherwise 
indicated:
    GNU General Public License for more details.
 
 Portions Copyright (C) 1999-2000 Jeremy Fitzhardinge
-Portions Copyright (C) 2001-2003 Ian Kent
+Portions Copyright (C) 2001-2005 Ian Kent
+
+The files lib/syslog.c and include/syslog.h are licenced under the
+BSD License and require that a copy of the notice ibelow be included in
+accompanying documentation and be distributed with binary distributions
+of the code, so be sure to include this file along with any binary
+distributions derived from this source package.
+
+Copyright (c) 1983, 1988, 1993
+     The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+
diff --git a/daemon/automount.c b/daemon/automount.c
index 3567abf..92476b4 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -38,13 +38,32 @@
 #include <sys/poll.h>
 #include <linux/auto_fs4.h>
 
+#include "automount.h"
+
 #ifndef NDEBUG
-#define assert(x)      do { if (!(x)) { syslog(LOG_CRIT, __FILE__ ":%d: 
assertion failed: " #x, __LINE__); } } while(0)
+#define assert(x)                                                  \
+       do {                                                        \
+               if (!(x)) {                                         \
+                       crit(__FILE__ ":%d: assertion failed: " #x, \
+                               __LINE__);                          \
+               }                                                   \
+       } while(0)
 #else
 #define assert(x)      do { } while(0)
 #endif
 
-#include "automount.h"
+#ifndef NDEBUG
+#define assert_r(context, x)                                      \
+       do {                                                       \
+               if (!(x)) {                                        \
+                       crit_r(context,                            \
+                               __FILE__ ":%d: assertion failed: ",\
+                               __LINE__);                         \
+               }                                                  \
+       } while(0)
+#else
+#define assert_r(context, x)   do { } while(0)
+#endif
 
 const char *program;           /* Initialized with argv[0] */
 const char *version = VERSION_STRING;  /* Program version */
@@ -68,6 +87,9 @@ sigset_t sigchld_mask;
 
 struct autofs_point ap;
 
+/* re-entrant syslog default context data */
+#define AUTOFS_SYSLOG_CONTEXT {-1, 0, 0, LOG_PID, (const char *)0, LOG_DAEMON, 
0xff}
+
 volatile struct pending_mount *junk_mounts = NULL;
 
 #define CHECK_RATIO     4      /* exp_runfreq = exp_timeout/CHECK_RATIO */
@@ -481,19 +503,25 @@ static int mount_autofs(char *path)
 
 static void nextstate(enum states next)
 {
+       static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+       static struct syslog_data *slc = &syslog_context;
+
        if (write(ap.state_pipe[1], &next, sizeof(next)) != sizeof(next))
-               error("nextstate: write failed %m");
+               error_r(slc, "nextstate: write failed %m");
 }
 
 /* Deal with all the signal-driven events in the state machine */
 static void sig_statemachine(int sig)
 {
+       static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+       static struct syslog_data *slc = &syslog_context;
        int save_errno = errno;
        enum states next = ap.state;
 
        switch (sig) {
        default:                /* all the "can't happen" signals */
-               error("process %d got unexpected signal %d!", getpid(), sig);
+               error_r(slc, "process %d got unexpected signal %d!",
+                       getpid(), sig);
                break;
                /* don't FALLTHROUGH */
 
@@ -519,18 +547,21 @@ static void sig_statemachine(int sig)
                break;
        }
 
-       debug("sig %d switching from %d to %d", sig, ap.state, next);
+       debug_r(slc, "sig %d switching from %d to %d", sig, ap.state, next);
 
        errno = save_errno;
 }
 
 static int send_ready(unsigned int wait_queue_token)
 {
+       static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+       static struct syslog_data *slc = &syslog_context;
+
        if (wait_queue_token == 0)
                return 0;
-       debug("send_ready: token=%d\n", wait_queue_token);
+       debug_r(slc, "send_ready: token=%d\n", wait_queue_token);
        if (ioctl(ap.ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) {
-               error("AUTOFS_IOC_READY: %m");
+               error_r(slc, "AUTOFS_IOC_READY: %m");
                return 1;
        }
        return 0;
@@ -538,11 +569,14 @@ static int send_ready(unsigned int wait_queue_token)
 
 static int send_fail(unsigned int wait_queue_token)
 {
+       static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+       static struct syslog_data *slc = &syslog_context;
+
        if (wait_queue_token == 0)
                return 0;
-       debug("send_fail: token=%d\n", wait_queue_token);
+       debug_r(slc, "send_fail: token=%d\n", wait_queue_token);
        if (ioctl(ap.ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) {
-               syslog(LOG_ERR, "AUTOFS_IOC_FAIL: %m");
+               error_r(slc, "AUTOFS_IOC_FAIL: %m");
                return 1;
        }
        return 0;
@@ -553,6 +587,8 @@ static int send_fail(unsigned int wait_queue_token)
    result.  */
 static enum states handle_child(int hang)
 {
+       static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+       static struct syslog_data *slc = &syslog_context;
        pid_t pid;
        int status;
        enum states next = ST_INVAL;
@@ -560,7 +596,7 @@ static enum states handle_child(int hang)
        while ((pid = waitpid(-1, &status, hang ? 0 : WNOHANG)) > 0) {
                struct pending_mount volatile *mt, *volatile *mtp;
 
-               debug("handle_child: got pid %d, sig %d (%d), stat %d\n",
+               debug_r(slc, "handle_child: got pid %d, sig %d (%d), stat %d",
                        pid, WIFSIGNALED(status),
                        WTERMSIG(status), WEXITSTATUS(status));
 
@@ -606,18 +642,19 @@ static enum states handle_child(int hang)
                                }
 
                                /* Failed shutdown returns to ready */
-                               warn("can't shutdown: filesystem %s still busy",
-                                    ap.path);
+                               warn_r(slc,
+                                  "can't shutdown: filesystem %s still busy",
+                                  ap.path);
                                alarm(ap.exp_runfreq);
                                next = ST_READY;
                                break;
 
                        default:
-                               error("bad state %d", ap.state);
+                               error_r(slc, "bad state %d", ap.state);
                        }
 
                        if (next != ST_INVAL)
-                               debug("sigchld: exp "
+                               debug_r(slc, "sigchld: exp "
                                     "%d finished, switching from %d to %d",
                                     pid, ap.state, next);
 
@@ -633,7 +670,7 @@ static enum states handle_child(int hang)
                        if (!WIFEXITED(status) && !WIFSIGNALED(status))
                                break;
 
-                       debug("sig_child: found pending iop pid %d: "
+                       debug_r(slc, "sig_child: found pending iop pid %d: "
                             "signalled %d (sig %d), exit status %d",
                                pid, WIFSIGNALED(status),
                                WTERMSIG(status), WEXITSTATUS(status));
@@ -1530,11 +1567,14 @@ static void setup_signals(__sighandler_t event_handler, 
__sighandler_t cld_handl
 /* Deal with the signals recieved by direct mount supervisor */
 static void sig_supervisor(int sig)
 {
+       static struct syslog_data syslog_context = AUTOFS_SYSLOG_CONTEXT;
+       static struct syslog_data *slc = &syslog_context;
        int save_errno = errno;
 
        switch (sig) {
        default:                /* all the signals not handled */
-               error("process %d got unexpected signal %d!", getpid(), sig);
+               error_r(slc, "process %d got unexpected signal %d!",
+                       getpid(), sig);
                return;
                /* don't FALLTHROUGH */
 
diff --git a/include/automount.h b/include/automount.h
index b09dd78..72f6c91 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -15,6 +15,9 @@
 #include <time.h>
 #include "config.h"
 
+/* OpenBSD re-entrant syslog */
+#include "syslog.h"
+
 /* We MUST have the paths to mount(8) and umount(8) */
 #ifndef HAVE_MOUNT
 #error Failed to locate mount(8)!
@@ -318,5 +321,29 @@ if (do_verbose || do_debug)                \
 if (do_debug)                          \
        syslog(LOG_DEBUG, msg, ##args);
 
+/* Define reentrant logging macros for signal handlers */
+
+#define debug_r(context, msg, args...)                         \
+do {                                                           \
+       if (do_debug)                                           \
+               syslog_r(LOG_DEBUG, context, msg, ##args);      \
+} while (0)
+
+#define warn_r(context, msg, args...)                          \
+do {                                                           \
+       if (do_verbose || do_debug)                             \
+               syslog_r(LOG_WARNING, context, msg, ##args);    \
+} while (0)
+
+#define error_r(context, msg, args...)                 \
+do {                                                   \
+       syslog_r(LOG_ERR, context, msg, ##args);        \
+} while (0)
+
+#define crit_r(context, msg, args...)                  \
+do {                                                   \
+       syslog_r(LOG_CRIT, context, msg, ##args);       \
+} while (0)
+
 #endif
 
diff --git a/include/syslog.h b/include/syslog.h
new file mode 100644
index 0000000..9f1cae4
--- /dev/null
+++ b/include/syslog.h
@@ -0,0 +1,201 @@
+/*     $OpenBSD: syslog.h,v 1.11 2003/08/24 01:27:07 avsm Exp $        */
+/*     $NetBSD: syslog.h,v 1.14 1996/04/03 20:46:44 christos Exp $     */
+
+/*
+ * Copyright (c) 1982, 1986, 1988, 1993
+ *     The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *     @(#)syslog.h    8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _SYS_SYSLOG_H_
+#define _SYS_SYSLOG_H_
+
+#include <features.h>
+#define __need___va_list
+#include <stdarg.h>
+
+#define        _PATH_LOG       "/dev/log"
+
+/*
+ * priorities/facilities are encoded into a single 32-bit quantity, where the
+ * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
+ * (0-big number).  Both the priorities and the facilities map roughly
+ * one-to-one to strings in the syslogd(8) source code.  This mapping is
+ * included in this file.
+ *
+ * priorities (these are ordered)
+ */
+#define        LOG_EMERG       0       /* system is unusable */
+#define        LOG_ALERT       1       /* action must be taken immediately */
+#define        LOG_CRIT        2       /* critical conditions */
+#define        LOG_ERR         3       /* error conditions */
+#define        LOG_WARNING     4       /* warning conditions */
+#define        LOG_NOTICE      5       /* normal but significant condition */
+#define        LOG_INFO        6       /* informational */
+#define        LOG_DEBUG       7       /* debug-level messages */
+
+#define        LOG_PRIMASK     0x07    /* mask to extract priority part 
(internal) */
+                               /* extract priority */
+#define        LOG_PRI(p)      ((p) & LOG_PRIMASK)
+#define        LOG_MAKEPRI(fac, pri)   (((fac) << 3) | (pri))
+
+#ifdef SYSLOG_NAMES
+#define        INTERNAL_NOPRI  0x10    /* the "no priority" priority */
+                               /* mark "facility" */
+#define        INTERNAL_MARK   LOG_MAKEPRI(LOG_NFACILITIES, 0)
+typedef struct _code {
+       char    *c_name;
+       int     c_val;
+} CODE;
+
+CODE prioritynames[] = {
+       { "alert",      LOG_ALERT },
+       { "crit",       LOG_CRIT },
+       { "debug",      LOG_DEBUG },
+       { "emerg",      LOG_EMERG },
+       { "err",        LOG_ERR },
+       { "error",      LOG_ERR },              /* DEPRECATED */
+       { "info",       LOG_INFO },
+       { "none",       INTERNAL_NOPRI },       /* INTERNAL */
+       { "notice",     LOG_NOTICE },
+       { "panic",      LOG_EMERG },            /* DEPRECATED */
+       { "warn",       LOG_WARNING },          /* DEPRECATED */
+       { "warning",    LOG_WARNING },
+       { NULL,         -1 },
+};
+#endif
+
+/* facility codes */
+#define        LOG_KERN        (0<<3)  /* kernel messages */
+#define        LOG_USER        (1<<3)  /* random user-level messages */
+#define        LOG_MAIL        (2<<3)  /* mail system */
+#define        LOG_DAEMON      (3<<3)  /* system daemons */
+#define        LOG_AUTH        (4<<3)  /* security/authorization messages */
+#define        LOG_SYSLOG      (5<<3)  /* messages generated internally by 
syslogd */
+#define        LOG_LPR         (6<<3)  /* line printer subsystem */
+#define        LOG_NEWS        (7<<3)  /* network news subsystem */
+#define        LOG_UUCP        (8<<3)  /* UUCP subsystem */
+#define        LOG_CRON        (9<<3)  /* clock daemon */
+#define        LOG_AUTHPRIV    (10<<3) /* security/authorization messages 
(private) */
+#define        LOG_FTP         (11<<3) /* ftp daemon */
+
+       /* other codes through 15 reserved for system use */
+#define        LOG_LOCAL0      (16<<3) /* reserved for local use */
+#define        LOG_LOCAL1      (17<<3) /* reserved for local use */
+#define        LOG_LOCAL2      (18<<3) /* reserved for local use */
+#define        LOG_LOCAL3      (19<<3) /* reserved for local use */
+#define        LOG_LOCAL4      (20<<3) /* reserved for local use */
+#define        LOG_LOCAL5      (21<<3) /* reserved for local use */
+#define        LOG_LOCAL6      (22<<3) /* reserved for local use */
+#define        LOG_LOCAL7      (23<<3) /* reserved for local use */
+
+#define        LOG_NFACILITIES 24      /* current number of facilities */
+#define        LOG_FACMASK     0x03f8  /* mask to extract facility part */
+                               /* facility of pri */
+#define        LOG_FAC(p)      (((p) & LOG_FACMASK) >> 3)
+
+#ifdef SYSLOG_NAMES
+CODE facilitynames[] = {
+       { "auth",       LOG_AUTH },
+       { "authpriv",   LOG_AUTHPRIV },
+       { "cron",       LOG_CRON },
+       { "daemon",     LOG_DAEMON },
+       { "ftp",        LOG_FTP },
+       { "kern",       LOG_KERN },
+       { "lpr",        LOG_LPR },
+       { "mail",       LOG_MAIL },
+       { "mark",       INTERNAL_MARK },        /* INTERNAL */
+       { "news",       LOG_NEWS },
+       { "security",   LOG_AUTH },             /* DEPRECATED */
+       { "syslog",     LOG_SYSLOG },
+       { "user",       LOG_USER },
+       { "uucp",       LOG_UUCP },
+       { "local0",     LOG_LOCAL0 },
+       { "local1",     LOG_LOCAL1 },
+       { "local2",     LOG_LOCAL2 },
+       { "local3",     LOG_LOCAL3 },
+       { "local4",     LOG_LOCAL4 },
+       { "local5",     LOG_LOCAL5 },
+       { "local6",     LOG_LOCAL6 },
+       { "local7",     LOG_LOCAL7 },
+       { NULL,         -1 },
+};
+#endif
+
+/* Used by reentrant functions */
+
+struct syslog_data {
+       int     log_file;
+       int     connected;
+       int     opened;
+       int     log_stat;
+       const char      *log_tag;
+       int     log_fac;
+       int     log_mask;
+};
+
+#define SYSLOG_DATA_INIT {-1, 0, 0, 0, (const char *)0, LOG_USER, 0xff}
+
+/*
+ * arguments to setlogmask.
+ */
+#define        LOG_MASK(pri)   (1 << (pri))            /* mask for one 
priority */
+#define        LOG_UPTO(pri)   ((1 << ((pri)+1)) - 1)  /* all priorities 
through pri */
+
+/*
+ * Option flags for openlog.
+ *
+ * LOG_ODELAY no longer does anything.
+ * LOG_NDELAY is the inverse of what it used to be.
+ */
+#define        LOG_PID         0x01    /* log the pid with each message */
+#define        LOG_CONS        0x02    /* log on the console if errors in 
sending */
+#define        LOG_ODELAY      0x04    /* delay open until first syslog() 
(default) */
+#define        LOG_NDELAY      0x08    /* don't delay open */
+#define        LOG_NOWAIT      0x10    /* don't wait for console forks: 
DEPRECATED */
+#define        LOG_PERROR      0x20    /* log to stderr as well */
+
+__BEGIN_DECLS
+void   closelog(void);
+void   openlog(const char *__ident, int __option, int __facility);
+int    setlogmask(int __mask);
+void   syslog(int __pri, const char *__fmt, ...)
+               __attribute__((__format__(__printf__, 2, 3)));
+void   vsyslog(int __pri, const char *, __gnuc_va_list __ap)
+               __attribute__((__format__(__printf__, 2, 0)));
+void   closelog_r(struct syslog_data *__data);
+void   openlog_r(const char *__ident, int __option, int __facility, struct 
syslog_data *__data);
+int    setlogmask_r(int __mask, struct syslog_data *__data);
+void   syslog_r(int __pri, struct syslog_data *__data, const char *__fmt, ...)
+               __attribute__((__format__(__printf__, 3, 4)));
+void   vsyslog_r(int __pri, struct syslog_data *__data, const char *__fmt, 
__gnuc_va_list __ap)
+               __attribute__((__format__(__printf__, 3, 0)));
+__END_DECLS
+
+#endif /* !_SYS_SYSLOG_H_ */
+
diff --git a/lib/Makefile b/lib/Makefile
index 5cc809c..1771b1f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -9,10 +9,11 @@ include ../Makefile.rules
 RPCGEN = /usr/bin/rpcgen
 RANLIB = /usr/bin/ranlib
 
-SRCS = cache.c listmount.c cat_path.c rpc_subs.c mounts.c lock.c
+SRCS = cache.c listmount.c cat_path.c rpc_subs.c mounts.c lock.c syslog.c \
+       vsprintf.c
 RPCS = mount.h mount_clnt.c mount_xdr.c
 OBJS = cache.o mount_clnt.o mount_xdr.o listmount.o \
-       cat_path.o rpc_subs.o mounts.o lock.o
+       cat_path.o rpc_subs.o mounts.o lock.o syslog.o vsprintf.o
 
 LIB = autofs.a
 
diff --git a/lib/syslog.c b/lib/syslog.c
new file mode 100644
index 0000000..9e5623e
--- /dev/null
+++ b/lib/syslog.c
@@ -0,0 +1,383 @@
+#ident "$Id: syslog.c,v 1.1 2005/05/01 09:48:34 raven Exp $"
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *     The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "syslog.h"
+
+#define        TBUF_LEN        2048
+#define        FMT_LEN         1024
+#define        INTERNALLOG     LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
+
+#define        DEC()                                   \
+       do {                                    \
+               if (prlen < 0)                  \
+                       prlen = 0;              \
+               if (prlen >= tbuf_left)         \
+                       prlen = tbuf_left - 1;  \
+               p += prlen;                     \
+               tbuf_left -= prlen;             \
+       } while (0)
+
+/* Use our internal printf routines */
+extern int snprintf_int(char * buf, size_t size, const char * fmt, ...)
+       __attribute__ ((format (printf, 3, 4)));
+extern int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list args)
+       __attribute__ ((format (printf, 3, 0)));
+
+static struct syslog_data sdata = SYSLOG_DATA_INIT;
+static int LogType = SOCK_DGRAM;       /* type of socket connection */
+
+extern char    *__progname;            /* Program name, from crt0. */
+
+static void    disconnectlog_r(struct syslog_data *);  /* disconnect from 
syslogd */
+static void    connectlog_r(struct syslog_data *);     /* (re)connect to 
syslogd */
+
+/*
+ * syslog, vsyslog --
+ *     print message on log file; output is intended for syslogd(8).
+ */
+void
+syslog(int pri, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsyslog(pri, fmt, ap);
+       va_end(ap);
+}
+
+void
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+       vsyslog_r(pri, &sdata, fmt, ap);
+}
+
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+       openlog_r(ident, logstat, logfac, &sdata);
+}
+
+void
+closelog(void)
+{
+       closelog_r(&sdata);
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask(int pmask)
+{
+       return setlogmask_r(pmask, &sdata);
+}
+
+/* Reentrant version of syslog, i.e. syslog_r() */
+
+void
+syslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsyslog_r(pri, data, fmt, ap);
+       va_end(ap);
+}
+
+void
+vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
+{
+       int cnt;
+       char ch, *p, *t;
+       time_t now;
+       int fd, saved_errno, error;
+       char *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
+       int tbuf_left, fmt_left, prlen;
+
+       /* Check for invalid bits. */
+       if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
+               if (data == &sdata) {
+                       syslog(INTERNALLOG,
+                           "syslog: unknown facility/priority: %x", pri);
+               } else {
+                       syslog_r(INTERNALLOG, data,
+                           "syslog_r: unknown facility/priority: %x", pri);
+               }
+               pri &= LOG_PRIMASK|LOG_FACMASK;
+       }
+
+       /* Check priority against setlogmask values. */
+       if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
+               return;
+
+       saved_errno = errno;
+
+       /* Set default facility if none specified. */
+       if ((pri & LOG_FACMASK) == 0)
+               pri |= data->log_fac;
+
+       /* If we have been called through syslog(), no need for reentrancy. */
+       if (data == &sdata)
+               (void)time(&now);
+
+       p = tbuf;
+       tbuf_left = TBUF_LEN;
+
+       prlen = snprintf_int(p, tbuf_left, "<%d>", pri);
+       DEC();
+
+       /* 
+        * syslogd will expand time automagically for reentrant case, and
+        * for normal case, just do like before
+        */
+       if (data == &sdata) {
+               prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
+               DEC();
+       }
+
+       if (data->log_stat & LOG_PERROR)
+               stdp = p;
+       if (data->log_tag == NULL)
+               data->log_tag = __progname;
+       if (data->log_tag != NULL) {
+               prlen = snprintf_int(p, tbuf_left, "%s", data->log_tag);
+               DEC();
+       }
+       if (data->log_stat & LOG_PID) {
+               prlen = snprintf_int(p, tbuf_left, "[%ld]", (long)getpid());
+               DEC();
+       }
+       if (data->log_tag != NULL) {
+               if (tbuf_left > 1) {
+                       *p++ = ':';
+                       tbuf_left--;
+               }
+               if (tbuf_left > 1) {
+                       *p++ = ' ';
+                       tbuf_left--;
+               }
+       }
+
+       /* strerror() is not reentrant */
+
+       for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
+               if (ch == '%' && fmt[1] == 'm') {
+                       ++fmt;
+                       if (data == &sdata) {
+                               prlen = snprintf_int(t, fmt_left, "%s",
+                                   strerror(saved_errno)); 
+                       } else {
+                               prlen = snprintf_int(t, fmt_left, "Error %d",
+                                   saved_errno); 
+                       }
+                       if (prlen < 0)
+                               prlen = 0;
+                       if (prlen >= fmt_left)
+                               prlen = fmt_left - 1;
+                       t += prlen;
+                       fmt_left -= prlen;
+               } else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
+                       *t++ = '%';
+                       *t++ = '%';
+                       fmt++;
+                       fmt_left -= 2;
+               } else {
+                       if (fmt_left > 1) {
+                               *t++ = ch;
+                               fmt_left--;
+                       }
+               }
+       }
+       *t = '\0';
+
+       prlen = vsnprintf_int(p, tbuf_left, fmt_cpy, ap);
+       DEC();
+       cnt = p - tbuf;
+
+       /* Output to stderr if requested. */
+       if (data->log_stat & LOG_PERROR) {
+               struct iovec iov[2];
+
+               iov[0].iov_base = stdp;
+               iov[0].iov_len = cnt - (stdp - tbuf);
+               iov[1].iov_base = "\n";
+               iov[1].iov_len = 1;
+               (void)writev(STDERR_FILENO, iov, 2);
+       }
+
+       /* Get connected, output the message to the local logger. */
+       if (!data->opened)
+               openlog_r(data->log_tag, data->log_stat, 0, data);
+       connectlog_r(data);
+
+       /* If we have a SOCK_STREAM connection, also send ASCII NUL as
+          a record terminator.  */
+       if (LogType == SOCK_STREAM)
+               cnt++;
+
+       /*
+        * If the send() failed, there are two likely scenarios:
+        *  1) syslogd was restarted
+        *  2) /dev/log is out of socket buffer space
+        * We attempt to reconnect to /dev/log to take care of
+        * case #1 and keep send()ing data to cover case #2
+        * to give syslogd a chance to empty its socket buffer.
+        */
+       if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
+               if (errno != ENOBUFS) {
+                       disconnectlog_r(data);
+                       connectlog_r(data);
+               }
+               do {
+                       usleep(1);
+                       if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
+                               break;
+               } while (errno == ENOBUFS);
+       }
+
+       /*
+        * Output the message to the console; try not to block
+        * as a blocking console should not stop other processes.
+        * Make sure the error reported is the one from the syslogd failure.
+        */
+       if (error == -1 && (data->log_stat & LOG_CONS) &&
+           (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
+               struct iovec iov[2];
+               
+               p = strchr(tbuf, '>') + 1;
+               iov[0].iov_base = p;
+               iov[0].iov_len = cnt - (p - tbuf);
+               iov[1].iov_base = "\r\n";
+               iov[1].iov_len = 2;
+               (void)writev(fd, iov, 2);
+               (void)close(fd);
+       }
+
+       if (data != &sdata)
+               closelog_r(data);
+}
+
+static void
+disconnectlog_r(struct syslog_data *data)
+{
+       /*
+        * If the user closed the FD and opened another in the same slot,
+        * that's their problem.  They should close it before calling on
+        * system services.
+        */
+       if (data->log_file != -1) {
+               close(data->log_file);
+               data->log_file = -1;
+       }
+       data->connected = 0;            /* retry connect */
+}
+
+static void
+connectlog_r(struct syslog_data *data)
+{
+       struct sockaddr_un SyslogAddr;  /* AF_UNIX address of local logger */
+
+again:
+       if (data->log_file == -1) {
+               if ((data->log_file = socket(AF_UNIX, LogType, 0)) == -1)
+                       return;
+               (void)fcntl(data->log_file, F_SETFD, 1);
+       }
+       if (data->log_file != -1 && !data->connected) {
+               int old_errno;
+               
+               memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
+               SyslogAddr.sun_family = AF_UNIX;
+               strncpy(SyslogAddr.sun_path, _PATH_LOG,
+                   sizeof(SyslogAddr.sun_path));
+               old_errno = errno;
+               if (connect(data->log_file, (struct sockaddr *)&SyslogAddr,
+                   sizeof(SyslogAddr)) == -1) {
+                       int save_errno = errno;
+                       (void)close(data->log_file);
+                       data->log_file = -1;
+                       if (LogType == SOCK_DGRAM && save_errno == EPROTOTYPE) {
+                               /* retry with SOCK_STREAM */
+                               LogType = SOCK_STREAM;
+                               errno = old_errno;
+                               goto again;
+                       }
+               } else
+                       data->connected = 1;
+       }
+}
+
+void
+openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
+{
+       if (ident != NULL)
+               data->log_tag = ident;
+       data->log_stat = logstat;
+       if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+               data->log_fac = logfac;
+
+       if (data->log_stat & LOG_NDELAY)        /* open immediately */
+               connectlog_r(data);
+
+       data->opened = 1;       /* ident and facility has been set */
+}
+
+void
+closelog_r(struct syslog_data *data)
+{
+       (void)close(data->log_file);
+       data->log_file = -1;
+       data->connected = 0;
+       data->log_tag = NULL;
+}
+
+/* setlogmask -- set the log mask level */
+int
+setlogmask_r(int pmask, struct syslog_data *data)
+{
+       int omask;
+
+       omask = data->log_mask;
+       if (pmask != 0)
+               data->log_mask = pmask;
+       return (omask);
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
new file mode 100644
index 0000000..eabe83f
--- /dev/null
+++ b/lib/vsprintf.c
@@ -0,0 +1,619 @@
+#ident "$Id: vsprintf.c,v 1.1 2005/05/01 09:48:34 raven Exp $"
+/*
+ *  Stolen from the linux kernel.
+ *
+ *  License: GPL
+ */
+/*------------------ Original Copyright -----------------*/
+/*
+ *  linux/lib/vsprintf.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/* 
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+ker...@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb  1 16:51:32 CET 2004 Juergen Quade <qu...@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+/* Also copied from: */
+
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <i...@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <ja...@topic.com.au>,
+ *                    Matthew Hawkins <m...@mh.dropbear.id.au>
+ * -  Kissed strtok() goodbye
+ */
+/*-------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define BITS_PER_LONG  __WORDSIZE
+#define PAGE_SIZE      getpagesize()
+
+
+#if BITS_PER_LONG == 64
+
+# define do_div(n,base) ({                                     \
+       uint32_t __base = (base);                               \
+       uint32_t __rem;                                         \
+       __rem = ((uint64_t)(n)) % __base;                       \
+       (n) = ((uint64_t)(n)) / __base;                         \
+       __rem;                                                  \
+ })
+
+#elif BITS_PER_LONG == 32
+
+/* Not needed on 64bit architectures */
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+       uint64_t rem = *n;
+       uint64_t b = base;
+       uint64_t res, d = 1;
+       uint32_t high = rem >> 32;
+
+       /* Reduce the thing a bit first */
+       res = 0;
+       if (high >= base) {
+               high /= base;
+               res = (uint64_t) high << 32;
+               rem -= (uint64_t) (high*base) << 32;
+       }
+
+       while ((int64_t)b > 0 && b < rem) {
+               b = b+b;
+               d = d+d;
+       }
+
+       do {
+               if (rem >= b) {
+                       rem -= b;
+                       res += d;
+               }
+               b >>= 1;
+               d >>= 1;
+       } while (d);
+
+       *n = res;
+       return rem;
+}
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({                             \
+       uint32_t __base = (base);                       \
+       uint32_t __rem;                                 \
+       (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
+       if (((n) >> 32) == 0) {                         \
+               __rem = (uint32_t)(n) % __base;         \
+               (n) = (uint32_t)(n) / __base;           \
+       } else                                          \
+               __rem = __div64_32(&(n), __base);       \
+       __rem;                                          \
+ })
+
+# else
+
+# error do_div() does not yet support the C64
+
+#endif /* BITS_PER_LONG */
+
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+       unsigned long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*cp == '0') {
+                       base = 8;
+                       cp++;
+                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                               cp++;
+                               base = 16;
+                       }
+               }
+       } else if (base == 16) {
+               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+                       cp += 2;
+       }
+       while (isxdigit(*cp) &&
+              (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+               result = result*base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+       return result;
+}
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+       if(*cp=='-')
+               return -simple_strtoul(cp+1,endp,base);
+       return simple_strtoul(cp,endp,base);
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int 
base)
+{
+       unsigned long long result = 0,value;
+
+       if (!base) {
+               base = 10;
+               if (*cp == '0') {
+                       base = 8;
+                       cp++;
+                       if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+                               cp++;
+                               base = 16;
+                       }
+               }
+       } else if (base == 16) {
+               if (cp[0] == '0' && toupper(cp[1]) == 'X')
+                       cp += 2;
+       }
+       while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+           ? toupper(*cp) : *cp)-'A'+10) < base) {
+               result = result*base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+       return result;
+}
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+       if(*cp=='-')
+               return -simple_strtoull(cp+1,endp,base);
+       return simple_strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+       int i=0;
+
+       while (isdigit(**s))
+               i = i*10 + *((*s)++) - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, unsigned long long num, int base, 
int size, int precision, int type)
+{
+       char c,sign,tmp[66];
+       const char *digits;
+       static const char small_digits[] = 
"0123456789abcdefghijklmnopqrstuvwxyz";
+       static const char large_digits[] = 
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       int i;
+
+       digits = (type & LARGE) ? large_digits : small_digits;
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return NULL;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if ((signed long long) num < 0) {
+                       sign = '-';
+                       num = - (signed long long) num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0)
+               tmp[i++] = digits[do_div(num,base)];
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT))) {
+               while(size-->0) {
+                       if (buf <= end)
+                               *buf = ' ';
+                       ++buf;
+               }
+       }
+       if (sign) {
+               if (buf <= end)
+                       *buf = sign;
+               ++buf;
+       }
+       if (type & SPECIAL) {
+               if (base==8) {
+                       if (buf <= end)
+                               *buf = '0';
+                       ++buf;
+               } else if (base==16) {
+                       if (buf <= end)
+                               *buf = '0';
+                       ++buf;
+                       if (buf <= end)
+                               *buf = digits[33];
+                       ++buf;
+               }
+       }
+       if (!(type & LEFT)) {
+               while (size-- > 0) {
+                       if (buf <= end)
+                               *buf = c;
+                       ++buf;
+               }
+       }
+       while (i < precision--) {
+               if (buf <= end)
+                       *buf = '0';
+               ++buf;
+       }
+       while (i-- > 0) {
+               if (buf <= end)
+                       *buf = tmp[i];
+               ++buf;
+       }
+       while (size-- > 0) {
+               if (buf <= end)
+                       *buf = ' ';
+               ++buf;
+       }
+       return buf;
+}
+
+/**
+ * vsnprintf_int - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long long num;
+       int i, base;
+       char *str, *end, c;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+
+       /* Reject out-of-range values early */
+       if ((int) size < 0)
+               return 0;
+
+       str = buf;
+       end = buf + size - 1;
+
+       if (end < buf - 1) {
+               end = ((void *) -1);
+               size = end - buf + 1;
+       }
+
+       for (; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       if (str <= end)
+                               *str = *fmt;
+                       ++str;
+                       continue;
+               }
+
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= LEFT; goto repeat;
+                               case '+': flags |= PLUS; goto repeat;
+                               case ' ': flags |= SPACE; goto repeat;
+                               case '#': flags |= SPECIAL; goto repeat;
+                               case '0': flags |= ZEROPAD; goto repeat;
+                       }
+
+               /* get field width */
+               field_width = -1;
+               if (isdigit(*fmt))
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;  
+                       if (isdigit(*fmt))
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+                   *fmt =='Z' || *fmt == 'z') {
+                       qualifier = *fmt;
+                       ++fmt;
+                       if (qualifier == 'l' && *fmt == 'l') {
+                               qualifier = 'L';
+                               ++fmt;
+                       }
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+                       case 'c':
+                               if (!(flags & LEFT)) {
+                                       while (--field_width > 0) {
+                                               if (str <= end)
+                                                       *str = ' ';
+                                               ++str;
+                                       }
+                               }
+                               c = (unsigned char) va_arg(args, int);
+                               if (str <= end)
+                                       *str = c;
+                               ++str;
+                               while (--field_width > 0) {
+                                       if (str <= end)
+                                               *str = ' ';
+                                       ++str;
+                               }
+                               continue;
+
+                       case 's':
+                               s = va_arg(args, char *);
+                               if ((unsigned long)s < PAGE_SIZE)
+                                       s = "<NULL>";
+
+                               len = strnlen(s, precision);
+
+                               if (!(flags & LEFT)) {
+                                       while (len < field_width--) {
+                                               if (str <= end)
+                                                       *str = ' ';
+                                               ++str;
+                                       }
+                               }
+                               for (i = 0; i < len; ++i) {
+                                       if (str <= end)
+                                               *str = *s;
+                                       ++str; ++s;
+                               }
+                               while (len < field_width--) {
+                                       if (str <= end)
+                                               *str = ' ';
+                                       ++str;
+                               }
+                               continue;
+
+                       case 'p':
+                               if (field_width == -1) {
+                                       field_width = 2*sizeof(void *);
+                                       flags |= ZEROPAD;
+                               }
+                               str = number(str, end,
+                                               (unsigned long) va_arg(args, 
void *),
+                                               16, field_width, precision, 
flags);
+                               continue;
+
+
+                       case 'n':
+                               /* FIXME:
+                               * What does C99 say about the overflow case 
here? */
+                               if (qualifier == 'l') {
+                                       long * ip = va_arg(args, long *);
+                                       *ip = (str - buf);
+                               } else if (qualifier == 'Z' || qualifier == 
'z') {
+                                       size_t * ip = va_arg(args, size_t *);
+                                       *ip = (str - buf);
+                               } else {
+                                       int * ip = va_arg(args, int *);
+                                       *ip = (str - buf);
+                               }
+                               continue;
+
+                       case '%':
+                               if (str <= end)
+                                       *str = '%';
+                               ++str;
+                               continue;
+
+                               /* integer number formats - set up the flags 
and "break" */
+                       case 'o':
+                               base = 8;
+                               break;
+
+                       case 'X':
+                               flags |= LARGE;
+                       case 'x':
+                               base = 16;
+                               break;
+
+                       case 'd':
+                       case 'i':
+                               flags |= SIGN;
+                       case 'u':
+                               break;
+
+                       default:
+                               if (str <= end)
+                                       *str = '%';
+                               ++str;
+                               if (*fmt) {
+                                       if (str <= end)
+                                               *str = *fmt;
+                                       ++str;
+                               } else {
+                                       --fmt;
+                               }
+                               continue;
+               }
+               if (qualifier == 'L')
+                       num = va_arg(args, long long);
+               else if (qualifier == 'l') {
+                       num = va_arg(args, unsigned long);
+                       if (flags & SIGN)
+                               num = (signed long) num;
+               } else if (qualifier == 'Z' || qualifier == 'z') {
+                       num = va_arg(args, size_t);
+               } else if (qualifier == 'h') {
+                       num = (unsigned short) va_arg(args, int);
+                       if (flags & SIGN)
+                               num = (signed short) num;
+               } else {
+                       num = va_arg(args, unsigned int);
+                       if (flags & SIGN)
+                               num = (signed int) num;
+               }
+               str = number(str, end, num, base,
+                               field_width, precision, flags);
+       }
+       if (str <= end)
+               *str = '\0';
+       else if (size > 0)
+               /* don't write out a null byte if the buf size is zero */
+               *end = '\0';
+       /* the trailing null byte doesn't count towards the total
+       * ++str;
+       */
+       return str-buf;
+}
+
+/**
+ * snprintf_int - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99.  If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf_int(char * buf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsnprintf_int(buf,size,fmt,args);
+       va_end(args);
+       return i;
+}
+
-- 
1.7.3.3

_______________________________________________
autofs mailing list
autofs@linux.kernel.org
http://linux.kernel.org/mailman/listinfo/autofs

Reply via email to