---
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 <[email protected]>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb 1 16:51:32 CET 2004 Juergen Quade <[email protected]>
+ * - 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 <[email protected]>
+ * - 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 <[email protected]>,
+ * Matthew Hawkins <[email protected]>
+ * - 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
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs