On Thu, 2011-01-13 at 11:15 +1300, Bill Ryder wrote:
> ---
>  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.

Guilty as charged.

> +
> +
>  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;
> +}
> +


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

Reply via email to