On Mon, 18 Apr 2005 [EMAIL PROTECTED] wrote:
Hang on, I think I've got a problem with white space and my mailer.
If you have problems with the patch in the previous mail try this one
instead (maybe just use this one).
diff -Nurp autofs-4.1.4.orig/daemon/automount.c autofs-4.1.4/daemon/automount.c
--- autofs-4.1.4.orig/daemon/automount.c 2005-03-06 17:43:55.000000000
+0800
+++ autofs-4.1.4/daemon/automount.c 2005-04-18 20:59:43.000000000 +0800
@@ -5,7 +5,7 @@
*
* Copyright 1997 Transmeta Corporation - All Rights Reserved
* Copyright 1999-2000 Jeremy Fitzhardinge <[EMAIL PROTECTED]>
- * Copyright 2001-2003 Ian Kent <[EMAIL PROTECTED]>
+ * Copyright 2001-2005 Ian Kent <[EMAIL PROTECTED]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,14 @@
#include <linux/auto_fs4.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)) { \
+ safe_logger(LOG_CRIT, \
+ __FILE__ ":%d: assertion failed: " #x, \
+ __LINE__); \
+ } \
+ } while(0)
#else
#define assert(x) do { } while(0)
#endif
@@ -58,14 +65,12 @@ int kproto_sub_version = 0; /* Kernel pr
static int submount = 0;
-int do_verbose = 0; /* Verbose feedback option */
-int do_debug = 0; /* Enable full debug output */
-
sigset_t ready_sigs; /* signals only accepted in ST_READY */
sigset_t lock_sigs; /* signals blocked for locking */
sigset_t sigchld_mask;
struct autofs_point ap;
+extern volatile int in_interrupt;
volatile struct pending_mount *junk_mounts = NULL;
@@ -490,6 +495,7 @@ static void sig_statemachine(int sig)
int save_errno = errno;
enum states next = ap.state;
+ in_interrupt++;
switch (sig) {
default: /* all the "can't happen" signals */
error("process %d got unexpected signal %d!", getpid(), sig);
@@ -521,6 +527,7 @@ static void sig_statemachine(int sig)
debug("sig %d switching from %d to %d", sig, ap.state, next);
errno = save_errno;
+ in_interrupt--;
}
static int send_ready(unsigned int wait_queue_token)
@@ -565,7 +572,7 @@ static enum states handle_child(int hang
/* Check to see if expire process finished */
if (pid == ap.exp_process) {
- int success, ret;
+ int success;
if (!WIFEXITED(status))
continue;
@@ -594,15 +601,8 @@ static enum states handle_child(int hang
case ST_SHUTDOWN_PENDING:
next = ST_SHUTDOWN;
- if (success) {
- ret = ioctl(ap.ioctlfd,
- AUTOFS_IOC_ASKUMOUNT, &status);
- if (!ret) {
- if (status)
- break;
- } else
- break;
- }
+ if (success)
+ break;
/* Failed shutdown returns to ready */
warn("can't shutdown: filesystem %s still busy",
@@ -661,6 +661,7 @@ static void sig_child(int sig)
int save_errno = errno;
enum states next;
+ in_interrupt++;
if (sig != SIGCHLD)
return;
@@ -669,6 +670,7 @@ static void sig_child(int sig)
nextstate(next);
errno = save_errno;
+ in_interrupt--;
}
static int st_ready(void)
@@ -1487,6 +1489,7 @@ static void sig_supervisor(int sig)
{
int save_errno = errno;
+ in_interrupt++;
switch (sig) {
default: /* all the signals not handled */
error("process %d got unexpected signal %d!", getpid(), sig);
@@ -1495,13 +1498,11 @@ static void sig_supervisor(int sig)
case SIGTERM:
case SIGUSR2:
- /* Tell everyone to finish up */
- signal_children(sig);
+ ap.state = ST_SHUTDOWN_PENDING;
break;
case SIGUSR1:
- /* Pass on the prune event and ignore self signal */
- signal_children(sig);
+ ap.state = ST_PRUNE;
break;
case SIGCHLD:
@@ -1509,20 +1510,18 @@ static void sig_supervisor(int sig)
break;
case SIGHUP:
- ap.lookup->lookup_ghost(ap.path, ap.ghost, 0,
ap.lookup->context);
-
/* Pass on the reread event and ignore self signal */
- kill(0, SIGHUP);
- discard_pending(SIGHUP);
-
+ ap.state = ST_READMAP;
break;
}
errno = save_errno;
+ in_interrupt--;
}
int supervisor(char *path)
{
unsigned int map = 0;
+ int ret;
ap.path = alloca(strlen(path) + 1);
strcpy(ap.path, path);
@@ -1538,6 +1537,37 @@ int supervisor(char *path)
setup_signals(sig_supervisor, sig_supervisor);
+ while (ap.state != ST_SHUTDOWN) {
+ switch (ap.state) {
+ case ST_READMAP:
+ st_readmap();
+ signal_children(SIGHUP);
+ ap.state = ST_READY;
+ break;
+ case ST_SHUTDOWN_PENDING:
+ ret = signal_children(SIGUSR2);
+ if (!ret) {
+ ap.state = ST_SHUTDOWN;
+ break;
+ }
+
+ /* Failed shutdown returns to ready */
+ warn("can't shutdown: filesystem %s still busy",
+ ap.path);
+ ap.state = ST_READY;
+ break;
+ case ST_PRUNE:
+ /* Pass on the prune event and ignore self signal */
+ signal_children(SIGUSR1);
+ ap.state = ST_READY;
+ break;
+ default:
+ ap.state = ST_READY;
+ break;
+ }
+ sleep(1);
+ }
+
while (waitpid(0, NULL, 0) > 0);
return 0;
@@ -1644,8 +1674,23 @@ int handle_mounts(char *path)
kill(my_pid, SIGSTOP);
while (ap.state != ST_SHUTDOWN) {
- if (handle_packet() && errno != EINTR)
- break;
+ if (handle_packet() && errno != EINTR) {
+ int ret, status = 0;
+
+ ret = ioctl(ap.ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status);
+ /*
+ * If the ioctl fails assume the kernel doesn't have
+ * AUTOFS_IOC_ASKUMOUNT and just continue.
+ */
+ if (!ret && status)
+ break;
+
+ /* Failed shutdown returns to ready */
+ warn("can't shutdown: filesystem %s still busy",
+ ap.path);
+ ap.state = ST_READY;
+ alarm(ap.exp_runfreq);
+ }
}
/* Mop up remaining kids */
diff -Nurp autofs-4.1.4.orig/include/automount.h
autofs-4.1.4/include/automount.h
--- autofs-4.1.4.orig/include/automount.h 2005-01-26 21:03:02.000000000
+0800
+++ autofs-4.1.4/include/automount.h 2005-04-17 21:07:27.000000000 +0800
@@ -109,7 +109,7 @@ struct autofs_point {
volatile pid_t exp_process; /* Process that is currently
expiring */
volatile struct pending_mount *mounts; /* Pending mount queue */
struct lookup_mod *lookup; /* Lookup module */
- enum states state;
+ volatile enum states state;
int state_pipe[2];
unsigned dir_created; /* Was a directory created for this
mount? */
@@ -283,24 +283,53 @@ int has_fstab_option(const char *path, c
int allow_owner_mount(const char *);
/* log notification */
-extern int do_verbose;
-extern int do_debug;
-
-#define info(msg, args...) \
-if (do_verbose || do_debug) \
- syslog(LOG_INFO, msg, ##args);
-
-#define warn(msg, args...) \
-if (do_verbose || do_debug) \
- syslog(LOG_WARNING, msg, ##args);
-
-#define error(msg, args...) syslog(LOG_ERR, msg, ##args);
-
-#define crit(msg, args...) syslog(LOG_CRIT, msg, ##args);
-
-#define debug(msg, args...) \
-if (do_debug) \
- syslog(LOG_DEBUG, msg, ##args);
+extern int do_verbose; /* Verbose feedback option */
+extern int do_debug; /* Enable full debug output */
+void safe_logger(int priority, const char *format, ...);
+
+#define debug(msg, args...) \
+do { \
+ if (do_debug) \
+ safe_logger(LOG_DEBUG, msg, ##args); \
+} while (0)
+
+#define info(msg, args...) \
+do { \
+ if (do_verbose || do_debug) \
+ safe_logger(LOG_INFO, msg, ##args); \
+} while (0)
+
+#define notice(msg, args...) \
+do { \
+ if (do_verbose || do_debug) \
+ safe_logger(LOG_NOTICE, msg, ##args); \
+} while (0)
+
+#define warn(msg, args...) \
+do { \
+ if (do_verbose || do_debug) \
+ safe_logger(LOG_WARNING, msg, ##args); \
+} while (0)
+
+#define error(msg, args...) \
+do { \
+ safe_logger(LOG_ERR, msg, ##args); \
+} while (0)
+
+#define crit(msg, args...) \
+do { \
+ safe_logger(LOG_CRIT, msg, ##args); \
+} while (0)
+
+#define alert(msg, args...) \
+do { \
+ safe_logger(LOG_ALERT, msg, ##args); \
+} while (0)
+
+#define emerg(msg, args...) \
+do { \
+ safe_logger(LOG_EMERG, msg, ##args); \
+} while (0)
#endif
diff -Nurp autofs-4.1.4.orig/lib/Makefile autofs-4.1.4/lib/Makefile
--- autofs-4.1.4.orig/lib/Makefile 2005-01-09 17:16:43.000000000 +0800
+++ autofs-4.1.4/lib/Makefile 2005-04-17 15:41:54.000000000 +0800
@@ -9,10 +9,12 @@ 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 \
+ safe_logger.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 \
+ safe_logger.o vsprintf.o
LIB = autofs.a
diff -Nurp autofs-4.1.4.orig/lib/safe_logger.c autofs-4.1.4/lib/safe_logger.c
--- autofs-4.1.4.orig/lib/safe_logger.c 1970-01-01 08:00:00.000000000 +0800
+++ autofs-4.1.4/lib/safe_logger.c 2005-04-17 21:22:52.000000000 +0800
@@ -0,0 +1,116 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * safe_logger.c - module to provide signal safe syslog
+ *
+ * Copyright 2005 Jeff Moyer <[EMAIL PROTECTED]> - All Rights Reserved
+ * Copyright 2005 Ian Kent <[EMAIL PROTECTED]> - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+
+int do_verbose = 0; /* Verbose feedback option */
+int do_debug = 0; /* Enable full debug output */
+
+#define LOGQUEUE_LINE_LEN 256
+#define LOGQUEUE_MAX 256
+
+struct log_queue {
+ int pri;
+ char buf[LOGQUEUE_LINE_LEN];
+};
+static struct log_queue logbuf[LOGQUEUE_MAX + 1];
+static int ringlen = 0;
+
+volatile int in_interrupt = 0; /* keeps us from logging in a signal handler */
+
+extern int vsnprintf_int(char *buf, size_t size, const char *fmt, va_list
args);
+
+static void block_signals(sigset_t *set)
+{
+ sigset_t allsigs;
+
+ sigfillset(&allsigs);
+ sigprocmask(SIG_BLOCK, &allsigs, set);
+}
+
+static void unblock_signals(sigset_t *set)
+{
+ sigprocmask(SIG_SETMASK, set, NULL);
+}
+
+static void flush_log(void)
+{
+ int i;
+
+ for (i = 0; i < ringlen; i++)
+ syslog(logbuf[i].pri, logbuf[i].buf);
+ ringlen = 0;
+}
+
+static void queue_syslog(int priority, const char *format, va_list args)
+{
+ struct log_queue *rp;
+ int written;
+ sigset_t set;
+
+ block_signals(&set);
+ if (ringlen >= LOGQUEUE_MAX) {
+ /* At least attempt to give some info */
+ ringlen = LOGQUEUE_MAX;
+ flush_log();
+ /* Last gasp message */
+ syslog(LOG_EMERG, "fatal: logbuffer overflow");
+ unblock_signals(&set);
+#ifdef DEBUG
+ /*
+ * We want to know if we are exceeding the max number of
+ * log entrise.
+ */
+ *(void *)0 = 0;
+#else
+ return;
+#endif
+ }
+ rp = &logbuf[ringlen];
+ ringlen++;
+ unblock_signals(&set);
+
+ rp->pri = priority;
+ written = vsnprintf_int(rp->buf, LOGQUEUE_LINE_LEN, format, args);
+ if (written >= LOGQUEUE_LINE_LEN)
+ rp->buf[LOGQUEUE_LINE_LEN - 1] = '\0';
+ else
+ rp->buf[written] = '\0';
+}
+
+void safe_logger(int priority, const char *format, ...)
+{
+ va_list args;
+ sigset_t set;
+
+ va_start(args, format);
+ if (in_interrupt)
+ queue_syslog(priority, format, args);
+ else {
+ block_signals(&set);
+ flush_log();
+ vsyslog(priority, format, args);
+ unblock_signals(&set);
+ }
+ va_end(args);
+}
+
diff -Nurp autofs-4.1.4.orig/lib/vsprintf.c autofs-4.1.4/lib/vsprintf.c
--- autofs-4.1.4.orig/lib/vsprintf.c 1970-01-01 08:00:00.000000000 +0800
+++ autofs-4.1.4/lib/vsprintf.c 2005-04-17 13:01:12.000000000 +0800
@@ -0,0 +1,594 @@
+/*
+ * 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;
+}
_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs