On Mon, 18 Apr 2005, Jeff Moyer wrote:
Okay, I've reviewed all parts except for the actual logging functions. I'm actually not convinced this is the right approach. The overhead of setting up and tearing down the signal mask is quite expensive. I fear that environments with a great number of mounts will fall over when debugging is turned on, and that is the very thing we are trying to save. Perhaps it is worth another look at a separate logging process.
I agree.
The buffering approach is not the best way to handle this.
I had a look around and found that the BSD folks have a reentrant syslog. I found several posts on lists discussing the use of non-reentrant functions, including syslog, in signal handlers. The responses claimed that their reentrant syslog would work.
I grabed the source from OpenBSD and tweeked it a bit to get it working.
I've used the kernel printf code from the existing patch and checked all the other function calls in glibc. It looks like it may well be signal safe.
I've also tried to rationalise the signal setup and take down a bit. I've also tried to address the things that you picked up previously.
So have a look at the attached patch.
Ian
diff -Nur 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-24 13:43:54.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 @@ -28,7 +28,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <syslog.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> @@ -38,13 +37,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 */ @@ -57,7 +75,7 @@ int kproto_sub_version = 0; /* Kernel protocol version used */
static int submount = 0; - + int do_verbose = 0; /* Verbose feedback option */ int do_debug = 0; /* Enable full debug output */
@@ -66,6 +84,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;
@@ -480,19 +501,25 @@
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 */
@@ -503,33 +530,36 @@ break;
case SIGUSR1: - assert(ap.state == ST_READY); + assert_r(slc, ap.state == ST_READY); nextstate(next = ST_PRUNE); break;
case SIGALRM: - assert(ap.state == ST_READY); + assert_r(slc, ap.state == ST_READY); nextstate(next = ST_EXPIRE); break;
case SIGHUP: - assert(ap.state == ST_READY); + assert_r(slc, ap.state == ST_READY); nextstate(next = ST_READMAP); 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; @@ -537,11 +567,14 @@
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; @@ -552,6 +585,8 @@ 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; @@ -559,13 +594,13 @@ 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));
/* Check to see if expire process finished */ if (pid == ap.exp_process) { - int success, ret; + int success;
if (!WIFEXITED(status)) continue; @@ -594,29 +629,23 @@
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", - 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);
@@ -632,7 +661,7 @@ 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)); @@ -673,10 +702,9 @@
static int st_ready(void) { - debug("st_ready(): state = %d\n", ap.state); + debug("st_ready(): state = %d", ap.state);
ap.state = ST_READY; - sigprocmask(SIG_UNBLOCK, &lock_sigs, NULL);
return 0; } @@ -796,6 +824,7 @@ default: debug("expire_proc: exp_proc=%d", f); ap.exp_process = f; + sigprocmask(SIG_SETMASK, &old, NULL); return EXP_STARTED; } } @@ -804,10 +833,15 @@ { int status;
+ assert(ap.state == ST_READY); + ap.state = ST_READMAP; + status = ap.lookup->lookup_ghost(ap.path, ap.ghost, 0, ap.lookup->context);
debug("st_readmap: status %d\n", status);
+ ap.state = ST_READY; + /* If I don't exist in the map any more then exit */ if (status == LKP_FAIL) return 0; @@ -822,15 +856,11 @@ info("prep_shutdown: state = %d\n", ap.state);
assert(ap.state == ST_READY || ap.state == ST_EXPIRE); + ap.state = ST_SHUTDOWN_PENDING;
/* Turn off timeouts */ alarm(0);
- /* Prevent any new mounts */ - sigprocmask(SIG_SETMASK, &lock_sigs, NULL); - - ap.state = ST_SHUTDOWN_PENDING; - /* Where're the boss, tell everyone to finish up */ if (getpid() == getpgrp()) signal_children(SIGUSR2); @@ -844,8 +874,9 @@ case EXP_ERROR: case EXP_PARTIAL: /* It didn't work: return to ready */ + ap.state = ST_READY; alarm(ap.exp_runfreq); - return st_ready(); + return 0;
case EXP_DONE: /* All expired: go straight to exit */ @@ -853,8 +884,6 @@ return 1;
case EXP_STARTED: - /* Wait until expiry process finishes */ - sigprocmask(SIG_SETMASK, &ready_sigs, NULL); return 0; } return 1; @@ -865,6 +894,7 @@ debug("st_prune(): state = %d\n", ap.state);
assert(ap.state == ST_READY); + ap.state = ST_PRUNE;
/* We're the boss, pass on the prune event */
if (getpid() == getpgrp()) @@ -878,11 +908,10 @@
case EXP_ERROR: case EXP_PARTIAL: + ap.state = ST_READY; return 1;
case EXP_STARTED: - ap.state = ST_PRUNE; - sigprocmask(SIG_SETMASK, &ready_sigs, NULL); return 0; } return 1; @@ -893,6 +922,7 @@ debug("st_expire(): state = %d\n", ap.state);
assert(ap.state == ST_READY); + ap.state = ST_EXPIRE;
switch (expire_proc(0)) { case EXP_DONE: @@ -902,12 +932,11 @@
case EXP_ERROR: case EXP_PARTIAL: + ap.state = ST_READY; alarm(ap.exp_runfreq); return 1;
case EXP_STARTED: - ap.state = ST_EXPIRE; - sigprocmask(SIG_SETMASK, &ready_sigs, NULL); return 0; } return 1; @@ -947,7 +976,7 @@ if (poll(fds, 2, -1) == -1) { if (errno == EINTR) continue; - syslog(LOG_ERR, "get_pkt: poll failed: %m"); + error("get_pkt: poll failed: %m"); return -1; }
@@ -958,8 +987,7 @@ if (fullread(ap.state_pipe[0], &next_state, sizeof(next_state))) continue;
- sigprocmask(SIG_BLOCK, &lock_sigs, &old); - + sigprocmask(SIG_BLOCK, &ready_sigs, &old); if (next_state != ap.state) { debug("get_pkt: state %d, next %d", ap.state, next_state); @@ -999,9 +1027,7 @@ next_state); } } - - if (ret) - sigprocmask(SIG_SETMASK, &old, NULL); + sigprocmask(SIG_SETMASK, &old, NULL);
if (ap.state == ST_SHUTDOWN) return -1; @@ -1484,24 +1510,25 @@
/* 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 */
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,12 +1536,8 @@ 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; @@ -1522,7 +1545,9 @@
int supervisor(char *path) { + sigset_t olds; unsigned int map = 0; + int ret;
ap.path = alloca(strlen(path) + 1); strcpy(ap.path, path); @@ -1536,8 +1561,46 @@ cleanup_exit(ap.path, 1); }
+ ap.state = ST_READY; setup_signals(sig_supervisor, sig_supervisor);
+ sigprocmask(SIG_BLOCK, &ready_sigs, &olds); + while (ap.state != ST_SHUTDOWN) { + switch (ap.state) { + case ST_READMAP: + ret = st_readmap(); + if (!ret) + /* Warn but try to continue anyway */ + warn("failed to read map"); + signal_children(SIGHUP); + ap.state = ST_READY; + break; + case ST_SHUTDOWN_PENDING: + ret = signal_children(SIGUSR2); + if (!ret) { + ap.state = ST_SHUTDOWN; + sigprocmask(SIG_SETMASK, &olds, NULL); + continue; + } + + /* 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; + } + sigsuspend(&olds); + } + sigprocmask(SIG_UNBLOCK, &ready_sigs, NULL); + while (waitpid(0, NULL, 0) > 0);
return 0; @@ -1644,8 +1707,32 @@ kill(my_pid, SIGSTOP);
while (ap.state != ST_SHUTDOWN) { - if (handle_packet() && errno != EINTR) - break; + if (handle_packet()) { + sigset_t olds; + int ret, status = 0; + + sigprocmask(SIG_BLOCK, &lock_sigs, &olds); + 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) { + sigprocmask(SIG_SETMASK, &olds, NULL); + break; + } + if (status) { + sigprocmask(SIG_SETMASK, &olds, NULL); + break; + } + + /* Failed shutdown returns to ready */ + warn("can't shutdown: filesystem %s still busy", + ap.path); + alarm(ap.exp_runfreq); + ap.state = ST_READY; + sigprocmask(SIG_SETMASK, &olds, NULL); + } }
/* Mop up remaining kids */ diff -Nur autofs-4.1.4.orig/daemon/module.c autofs-4.1.4/daemon/module.c --- autofs-4.1.4.orig/daemon/module.c 2004-01-30 00:01:22.000000000 +0800 +++ autofs-4.1.4/daemon/module.c 2005-04-23 19:45:36.000000000 +0800 @@ -14,7 +14,6 @@ * ----------------------------------------------------------------------- */
#include <stdio.h> -#include <syslog.h> #include <dlfcn.h> #include <string.h> #include <stdlib.h> diff -Nur autofs-4.1.4.orig/daemon/mount.c autofs-4.1.4/daemon/mount.c --- autofs-4.1.4.orig/daemon/mount.c 2004-11-17 22:38:27.000000000 +0800 +++ autofs-4.1.4/daemon/mount.c 2005-04-23 19:45:48.000000000 +0800 @@ -19,7 +19,6 @@ * * ----------------------------------------------------------------------- */
-#include <syslog.h> #include <stdlib.h> #include <string.h> #include "automount.h" diff -Nur autofs-4.1.4.orig/daemon/spawn.c autofs-4.1.4/daemon/spawn.c --- autofs-4.1.4.orig/daemon/spawn.c 2005-02-10 20:56:53.000000000 +0800 +++ autofs-4.1.4/daemon/spawn.c 2005-04-23 19:46:01.000000000 +0800 @@ -21,7 +21,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <syslog.h> #include <sys/types.h> #include <unistd.h> #include <time.h> diff -Nur 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-23 21:54:01.000000000 +0800 @@ -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)! @@ -283,24 +286,78 @@ 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); +extern int do_verbose; /* Verbose feedback option */ +extern int do_debug; /* Enable full debug output */
-#define crit(msg, args...) syslog(LOG_CRIT, msg, ##args); +/* Define non-reentrant logging macros */
-#define debug(msg, args...) \ -if (do_debug) \ - syslog(LOG_DEBUG, msg, ##args); +#define debug(msg, args...) \ +do { \ + if (do_debug) \ + syslog(LOG_DEBUG, msg, ##args); \ +} while (0) + +#define info(msg, args...) \ +do { \ + if (do_verbose || do_debug) \ + syslog(LOG_INFO, msg, ##args); \ +} while (0) + +#define notice(msg, args...) \ +do { \ + if (do_verbose || do_debug) \ + syslog(LOG_NOTICE, msg, ##args); \ +} while (0) + +#define warn(msg, args...) \ +do { \ + if (do_verbose || do_debug) \ + syslog(LOG_WARNING, msg, ##args); \ +} while (0) + +#define error(msg, args...) \ +do { \ + syslog(LOG_ERR, msg, ##args); \ +} while (0) + +#define crit(msg, args...) \ +do { \ + syslog(LOG_CRIT, msg, ##args); \ +} while (0) + +#define alert(msg, args...) \ +do { \ + syslog(LOG_ALERT, msg, ##args); \ +} while (0) + +#define emerg(msg, args...) \ +do { \ + syslog(LOG_EMERG, msg, ##args); \ +} while (0) + +/* 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 -Nur autofs-4.1.4.orig/include/syslog.h autofs-4.1.4/include/syslog.h --- autofs-4.1.4.orig/include/syslog.h 1970-01-01 08:00:00.000000000 +0800 +++ autofs-4.1.4/include/syslog.h 2005-04-24 01:00:58.000000000 +0800 @@ -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 -Nur 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-23 18:48:53.000000000 +0800 @@ -9,10 +9,12 @@ 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 -Nur autofs-4.1.4.orig/lib/cache.c autofs-4.1.4/lib/cache.c --- autofs-4.1.4.orig/lib/cache.c 2005-02-06 14:00:53.000000000 +0800 +++ autofs-4.1.4/lib/cache.c 2005-04-23 19:46:48.000000000 +0800 @@ -21,7 +21,6 @@ #include <string.h> #include <unistd.h> #include <ctype.h> -#include <syslog.h> #include <stdio.h> #include <fcntl.h> #include <sys/param.h> diff -Nur autofs-4.1.4.orig/lib/cat_path.c autofs-4.1.4/lib/cat_path.c --- autofs-4.1.4.orig/lib/cat_path.c 2005-04-06 23:14:23.000000000 +0800 +++ autofs-4.1.4/lib/cat_path.c 2005-04-23 19:47:59.000000000 +0800 @@ -16,7 +16,6 @@ #include <alloca.h> #include <string.h> #include <limits.h> -#include <syslog.h> #include <ctype.h>
/*
diff -Nur autofs-4.1.4.orig/lib/mounts.c autofs-4.1.4/lib/mounts.c
--- autofs-4.1.4.orig/lib/mounts.c 2005-01-17 23:09:28.000000000 +0800
+++ autofs-4.1.4/lib/mounts.c 2005-04-23 19:48:31.000000000 +0800
@@ -16,7 +16,6 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <syslog.h>
#include <mntent.h>
#include <limits.h>
#include <sys/types.h>
diff -Nur autofs-4.1.4.orig/lib/syslog.c autofs-4.1.4/lib/syslog.c
--- autofs-4.1.4.orig/lib/syslog.c 1970-01-01 08:00:00.000000000 +0800
+++ autofs-4.1.4/lib/syslog.c 2005-04-24 14:29:37.000000000 +0800
@@ -0,0 +1,383 @@
+#ident "$Id$"
+/*
+ * 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 -Nur 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-24 11:23:36.000000000 +0800
@@ -0,0 +1,619 @@
+#ident "$Id$"
+/*
+ * 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;
+}
+
_______________________________________________ autofs mailing list autofs@linux.kernel.org http://linux.kernel.org/mailman/listinfo/autofs