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 autofs@linux.kernel.org http://linux.kernel.org/mailman/listinfo/autofs