diff --git a/nfs-utils-1.2.0-proots-rel5.patch b/nfs-utils-1.2.0-proots-rel5.patch index d1eb411..2539d89 100644 --- a/nfs-utils-1.2.0-proots-rel5.patch +++ b/nfs-utils-1.2.0-proots-rel5.patch @@ -1,6 +1,6 @@ -diff -up nfs-utils-1.2.0/support/export/xtab.c.save nfs-utils-1.2.0/support/export/xtab.c ---- nfs-utils-1.2.0/support/export/xtab.c.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/support/export/xtab.c 2009-07-13 13:50:38.000000000 -0400 +diff -up nfs-utils-1.2.0/support/export/xtab.c.orig nfs-utils-1.2.0/support/export/xtab.c +--- nfs-utils-1.2.0/support/export/xtab.c.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/support/export/xtab.c 2009-08-17 07:33:13.000000000 -0400 @@ -19,7 +19,9 @@ #include "exportfs.h" #include "xio.h" @@ -29,9 +29,9 @@ diff -up nfs-utils-1.2.0/support/export/xtab.c.save nfs-utils-1.2.0/support/expo break; case 2: exp->m_exported = -1;/* may be exported */ -diff -up nfs-utils-1.2.0/support/include/exportfs.h.save nfs-utils-1.2.0/support/include/exportfs.h ---- nfs-utils-1.2.0/support/include/exportfs.h.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/support/include/exportfs.h 2009-07-13 13:49:51.000000000 -0400 +diff -up nfs-utils-1.2.0/support/include/exportfs.h.orig nfs-utils-1.2.0/support/include/exportfs.h +--- nfs-utils-1.2.0/support/include/exportfs.h.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/support/include/exportfs.h 2009-08-17 07:33:13.000000000 -0400 @@ -12,6 +12,17 @@ #include #include "nfslib.h" @@ -50,9 +50,9 @@ diff -up nfs-utils-1.2.0/support/include/exportfs.h.save nfs-utils-1.2.0/support enum { MCL_FQDN = 0, MCL_SUBNETWORK, -diff -up nfs-utils-1.2.0/support/include/nfs/export.h.save nfs-utils-1.2.0/support/include/nfs/export.h ---- nfs-utils-1.2.0/support/include/nfs/export.h.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/support/include/nfs/export.h 2009-07-13 13:49:51.000000000 -0400 +diff -up nfs-utils-1.2.0/support/include/nfs/export.h.orig nfs-utils-1.2.0/support/include/nfs/export.h +--- nfs-utils-1.2.0/support/include/nfs/export.h.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/support/include/nfs/export.h 2009-08-17 07:33:13.000000000 -0400 @@ -24,6 +24,7 @@ #define NFSEXP_FSID 0x2000 #define NFSEXP_CROSSMOUNT 0x4000 @@ -62,9 +62,9 @@ diff -up nfs-utils-1.2.0/support/include/nfs/export.h.save nfs-utils-1.2.0/suppo +#define NFSEXP_ALLFLAGS 0x1FFFF #endif /* _NSF_EXPORT_H */ -diff -up nfs-utils-1.2.0/support/include/nfslib.h.save nfs-utils-1.2.0/support/include/nfslib.h ---- nfs-utils-1.2.0/support/include/nfslib.h.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/support/include/nfslib.h 2009-07-13 13:49:51.000000000 -0400 +diff -up nfs-utils-1.2.0/support/include/nfslib.h.orig nfs-utils-1.2.0/support/include/nfslib.h +--- nfs-utils-1.2.0/support/include/nfslib.h.orig 2009-08-17 07:31:52.000000000 -0400 ++++ nfs-utils-1.2.0/support/include/nfslib.h 2009-08-17 07:33:13.000000000 -0400 @@ -88,6 +88,7 @@ struct exportent { int e_fslocmethod; char * e_fslocdata; @@ -74,8 +74,8 @@ diff -up nfs-utils-1.2.0/support/include/nfslib.h.save nfs-utils-1.2.0/support/i }; diff -up /dev/null nfs-utils-1.2.0/support/include/v4root.h ---- /dev/null 2009-07-13 07:44:43.606003629 -0400 -+++ nfs-utils-1.2.0/support/include/v4root.h 2009-07-13 13:49:57.000000000 -0400 +--- /dev/null 2009-08-13 17:25:29.612003011 -0400 ++++ nfs-utils-1.2.0/support/include/v4root.h 2009-08-17 07:33:13.000000000 -0400 @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2009 Red Hat @@ -97,9 +97,9 @@ diff -up /dev/null nfs-utils-1.2.0/support/include/v4root.h +extern void v4root_unset(void), v4root_set(void); + +#endif /* V4ROOT_H */ -diff -up nfs-utils-1.2.0/utils/mountd/auth.c.save nfs-utils-1.2.0/utils/mountd/auth.c ---- nfs-utils-1.2.0/utils/mountd/auth.c.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/utils/mountd/auth.c 2009-07-13 13:50:38.000000000 -0400 +diff -up nfs-utils-1.2.0/utils/mountd/auth.c.orig nfs-utils-1.2.0/utils/mountd/auth.c +--- nfs-utils-1.2.0/utils/mountd/auth.c.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/utils/mountd/auth.c 2009-08-17 07:33:13.000000000 -0400 @@ -20,6 +20,7 @@ #include "exportfs.h" #include "mountd.h" @@ -122,9 +122,9 @@ diff -up nfs-utils-1.2.0/utils/mountd/auth.c.save nfs-utils-1.2.0/utils/mountd/a ++counter; return counter; -diff -up nfs-utils-1.2.0/utils/mountd/cache.c.save nfs-utils-1.2.0/utils/mountd/cache.c ---- nfs-utils-1.2.0/utils/mountd/cache.c.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/utils/mountd/cache.c 2009-07-13 13:50:33.000000000 -0400 +diff -up nfs-utils-1.2.0/utils/mountd/cache.c.orig nfs-utils-1.2.0/utils/mountd/cache.c +--- nfs-utils-1.2.0/utils/mountd/cache.c.orig 2009-08-17 07:31:52.000000000 -0400 ++++ nfs-utils-1.2.0/utils/mountd/cache.c 2009-08-17 07:33:13.000000000 -0400 @@ -32,23 +32,12 @@ #include "xmalloc.h" #include "fsloc.h" @@ -196,16 +196,7 @@ diff -up nfs-utils-1.2.0/utils/mountd/cache.c.save nfs-utils-1.2.0/utils/mountd/ if (found) if (cache_export_ent(dom, found, found_path) < 0) found = 0; -@@ -590,7 +603,7 @@ static int dump_to_cache(FILE *f, char * - qword_printint(f, time(0)+30*60); - if (exp) { - int different_fs = strcmp(path, exp->e_path) != 0; -- -+ - if (different_fs) - qword_printint(f, exp->e_flags & ~NFSEXP_FSID); - else -@@ -631,6 +644,7 @@ void nfsd_export(FILE *f) +@@ -629,6 +642,7 @@ void nfsd_export(FILE *f) int found_type = 0; struct in_addr addr; struct hostent *he = NULL; @@ -213,7 +204,7 @@ diff -up nfs-utils-1.2.0/utils/mountd/cache.c.save nfs-utils-1.2.0/utils/mountd/ if (readline(fileno(f), &lbuf, &lbuflen) != 1) -@@ -665,10 +679,18 @@ void nfsd_export(FILE *f) +@@ -663,10 +677,18 @@ void nfsd_export(FILE *f) path[l] == '/' && is_mountpoint(path))) /* ok */; @@ -234,7 +225,7 @@ diff -up nfs-utils-1.2.0/utils/mountd/cache.c.save nfs-utils-1.2.0/utils/mountd/ if (use_ipaddr) { if (he == NULL) { if (!inet_aton(dom, &addr)) -@@ -707,17 +729,28 @@ void nfsd_export(FILE *f) +@@ -705,17 +727,28 @@ void nfsd_export(FILE *f) } if (found) { @@ -265,7 +256,7 @@ diff -up nfs-utils-1.2.0/utils/mountd/cache.c.save nfs-utils-1.2.0/utils/mountd/ if (dom) free(dom); if (path) free(path); if (he) free(he); -@@ -745,7 +778,9 @@ void cache_open(void) +@@ -743,7 +776,9 @@ void cache_open(void) if (!manage_gids && cachelist[i].cache_handle == auth_unix_gid) continue; sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name); @@ -276,9 +267,9 @@ diff -up nfs-utils-1.2.0/utils/mountd/cache.c.save nfs-utils-1.2.0/utils/mountd/ } } -diff -up nfs-utils-1.2.0/utils/mountd/Makefile.am.save nfs-utils-1.2.0/utils/mountd/Makefile.am ---- nfs-utils-1.2.0/utils/mountd/Makefile.am.save 2009-07-13 13:49:23.000000000 -0400 -+++ nfs-utils-1.2.0/utils/mountd/Makefile.am 2009-07-13 13:49:57.000000000 -0400 +diff -up nfs-utils-1.2.0/utils/mountd/Makefile.am.orig nfs-utils-1.2.0/utils/mountd/Makefile.am +--- nfs-utils-1.2.0/utils/mountd/Makefile.am.orig 2009-06-02 10:43:05.000000000 -0400 ++++ nfs-utils-1.2.0/utils/mountd/Makefile.am 2009-08-17 07:33:13.000000000 -0400 @@ -8,7 +8,7 @@ KPREFIX = @kprefix@ sbin_PROGRAMS = mountd @@ -289,8 +280,8 @@ diff -up nfs-utils-1.2.0/utils/mountd/Makefile.am.save nfs-utils-1.2.0/utils/mou ../../support/nfs/libnfs.a \ ../../support/misc/libmisc.a \ diff -up /dev/null nfs-utils-1.2.0/utils/mountd/v4root.c ---- /dev/null 2009-07-13 07:44:43.606003629 -0400 -+++ nfs-utils-1.2.0/utils/mountd/v4root.c 2009-07-13 13:50:44.000000000 -0400 +--- /dev/null 2009-08-13 17:25:29.612003011 -0400 ++++ nfs-utils-1.2.0/utils/mountd/v4root.c 2009-08-17 07:33:13.000000000 -0400 @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2009 Red Hat diff --git a/nfs-utils-1.2.1-rc4.patch b/nfs-utils-1.2.1-rc4.patch new file mode 100644 index 0000000..5cabcc5 --- /dev/null +++ b/nfs-utils-1.2.1-rc4.patch @@ -0,0 +1,3601 @@ +diff --git a/configure.ac b/configure.ac +index e0ca70e..1b653e4 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -136,6 +136,31 @@ AC_ARG_ENABLE(ipv6, + AC_SUBST(enable_ipv6) + AM_CONDITIONAL(CONFIG_IPV6, [test "$enable_ipv6" = "yes"]) + ++if test "$enable_mount" = yes; then ++ AC_ARG_ENABLE(mountconfig, ++ [AC_HELP_STRING([--enable-mountconfig], ++ [enable mount to use a configuration file])], ++ mountconfig=$enableval, ++ mountconfig=no) ++ if test "$enable_mountconfig" = yes; then ++ AC_DEFINE(MOUNT_CONFIG, 1, ++ [Define this if you want mount to read a configuration file]) ++ AC_ARG_WITH(mountfile, ++ [AC_HELP_STRING([--with-mountfile=filename], ++ [Using filename as the NFS mount options file [/etc/nfsmounts.conf]] ++ )], ++ mountfile=$withval, ++ mountfile=/etc/nfsmount.conf) ++ AC_SUBST(mountfile) ++ AC_DEFINE_UNQUOTED(MOUNTOPTS_CONFFILE, "$mountfile", ++ [This defines the location of the NFS mount configuration file]) ++ else ++ enable_mountconfig= ++ fi ++ AC_SUBST(enable_mountconfig) ++ AM_CONDITIONAL(MOUNT_CONFIG, [test "$enable_mountconfig" = "yes"]) ++fi ++ + dnl Check for TI-RPC library and headers + AC_LIBTIRPC + +diff --git a/support/include/Makefile.am b/support/include/Makefile.am +index 718abda..f5a77ec 100644 +--- a/support/include/Makefile.am ++++ b/support/include/Makefile.am +@@ -14,6 +14,7 @@ noinst_HEADERS = \ + xio.h \ + xlog.h \ + xmalloc.h \ +- xcommon.h ++ xcommon.h \ ++ conffile.h + + MAINTAINERCLEANFILES = Makefile.in +diff --git a/support/include/conffile.h b/support/include/conffile.h +new file mode 100644 +index 0000000..132a149 +--- /dev/null ++++ b/support/include/conffile.h +@@ -0,0 +1,77 @@ ++/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */ ++/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ ++ ++/* ++ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. ++ * Copyright (c) 2000, 2003 H�kan Olsson. 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. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. ++ */ ++ ++/* ++ * This code was written under funding by Ericsson Radio Systems. ++ */ ++ ++#ifndef _CONFFILE_H_ ++#define _CONFFILE_H_ ++ ++#include ++ ++struct conf_list_node { ++ TAILQ_ENTRY(conf_list_node) link; ++ char *field; ++}; ++ ++struct conf_list { ++ size_t cnt; ++ TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; ++}; ++ ++extern char *conf_path; ++ ++extern int conf_begin(void); ++extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *); ++extern int conf_end(int, int); ++extern void conf_free_list(struct conf_list *); ++extern struct sockaddr *conf_get_address(char *, char *); ++extern struct conf_list *conf_get_list(char *, char *); ++extern struct conf_list *conf_get_tag_list(char *); ++extern int conf_get_num(char *, char *, int); ++extern char *conf_get_str(char *, char *); ++extern char *conf_get_section(char *, char *, char *); ++extern void conf_init(void); ++extern int conf_match_num(char *, char *, int); ++extern void conf_reinit(void); ++extern int conf_remove(int, char *, char *); ++extern int conf_remove_section(int, char *); ++extern void conf_report(void); ++ ++/* ++ * Convert letter from upper case to lower case ++ */ ++static inline void upper2lower(char *str) ++{ ++ char c; ++ ++ while ((c = tolower(*str))) ++ *str++ = c; ++} ++#endif /* _CONFFILE_H_ */ +diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am +index 096f56d..e9462fc 100644 +--- a/support/nfs/Makefile.am ++++ b/support/nfs/Makefile.am +@@ -4,7 +4,7 @@ noinst_LIBRARIES = libnfs.a + libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ + xlog.c xcommon.c wildmat.c nfsclient.c \ + nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ +- svc_socket.c cacheio.c closeall.c nfs_mntent.c ++ svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c +new file mode 100644 +index 0000000..b277c2a +--- /dev/null ++++ b/support/nfs/conffile.c +@@ -0,0 +1,962 @@ ++/* $OpenBSD: conf.c,v 1.55 2003/06/03 14:28:16 ho Exp $ */ ++/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ ++ ++/* ++ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. ++ * Copyright (c) 2000, 2001, 2002 H�kan Olsson. 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. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. ++ */ ++ ++/* ++ * This code was written under funding by Ericsson Radio Systems. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "conffile.h" ++#include "xlog.h" ++ ++static void conf_load_defaults (int); ++static int conf_set(int , char *, char *, char *, ++ char *, int , int ); ++ ++struct conf_trans { ++ TAILQ_ENTRY (conf_trans) link; ++ int trans; ++ enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; ++ char *section; ++ char *arg; ++ char *tag; ++ char *value; ++ int override; ++ int is_default; ++}; ++ ++TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; ++ ++/* ++ * Radix-64 Encoding. ++ */ ++static const u_int8_t bin2asc[] ++ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ++ ++static const u_int8_t asc2bin[] = ++{ ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 255, 255, 255, 255, 255, ++ 255, 255, 255, 62, 255, 255, 255, 63, ++ 52, 53, 54, 55, 56, 57, 58, 59, ++ 60, 61, 255, 255, 255, 255, 255, 255, ++ 255, 0, 1, 2, 3, 4, 5, 6, ++ 7, 8, 9, 10, 11, 12, 13, 14, ++ 15, 16, 17, 18, 19, 20, 21, 22, ++ 23, 24, 25, 255, 255, 255, 255, 255, ++ 255, 26, 27, 28, 29, 30, 31, 32, ++ 33, 34, 35, 36, 37, 38, 39, 40, ++ 41, 42, 43, 44, 45, 46, 47, 48, ++ 49, 50, 51, 255, 255, 255, 255, 255 ++}; ++ ++struct conf_binding { ++ LIST_ENTRY (conf_binding) link; ++ char *section; ++ char *arg; ++ char *tag; ++ char *value; ++ int is_default; ++}; ++ ++char *conf_path; ++LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; ++ ++static char *conf_addr; ++ ++static __inline__ u_int8_t ++conf_hash(char *s) ++{ ++ u_int8_t hash = 0; ++ ++ while (*s) { ++ hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); ++ s++; ++ } ++ return hash; ++} ++ ++/* ++ * Insert a tag-value combination from LINE (the equal sign is at POS) ++ */ ++static int ++conf_remove_now(char *section, char *tag) ++{ ++ struct conf_binding *cb, *next; ++ ++ cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); ++ for (; cb; cb = next) { ++ next = LIST_NEXT(cb, link); ++ if (strcasecmp(cb->section, section) == 0 ++ && strcasecmp(cb->tag, tag) == 0) { ++ LIST_REMOVE(cb, link); ++ xlog(LOG_INFO,"[%s]:%s->%s removed", section, tag, cb->value); ++ free(cb->section); ++ free(cb->arg); ++ free(cb->tag); ++ free(cb->value); ++ free(cb); ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static int ++conf_remove_section_now(char *section) ++{ ++ struct conf_binding *cb, *next; ++ int unseen = 1; ++ ++ cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); ++ for (; cb; cb = next) { ++ next = LIST_NEXT(cb, link); ++ if (strcasecmp(cb->section, section) == 0) { ++ unseen = 0; ++ LIST_REMOVE(cb, link); ++ xlog(LOG_INFO, "[%s]:%s->%s removed", section, cb->tag, cb->value); ++ free(cb->section); ++ free(cb->arg); ++ free(cb->tag); ++ free(cb->value); ++ free(cb); ++ } ++ } ++ return unseen; ++} ++ ++/* ++ * Insert a tag-value combination from LINE (the equal sign is at POS) ++ * into SECTION of our configuration database. ++ */ ++static int ++conf_set_now(char *section, char *arg, char *tag, ++ char *value, int override, int is_default) ++{ ++ struct conf_binding *node = 0; ++ ++ if (override) ++ conf_remove_now(section, tag); ++ else if (conf_get_section(section, arg, tag)) { ++ if (!is_default) { ++ xlog(LOG_INFO, "conf_set: duplicate tag [%s]:%s, ignoring...\n", ++ section, tag); ++ } ++ return 1; ++ } ++ node = calloc(1, sizeof *node); ++ if (!node) { ++ xlog_warn("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node); ++ return 1; ++ } ++ node->section = strdup(section); ++ if (arg) ++ node->arg = strdup(arg); ++ node->tag = strdup(tag); ++ node->value = strdup(value); ++ node->is_default = is_default; ++ ++ LIST_INSERT_HEAD(&conf_bindings[conf_hash (section)], node, link); ++ return 0; ++} ++ ++/* ++ * Parse the line LINE of SZ bytes. Skip Comments, recognize section ++ * headers and feed tag-value pairs into our configuration database. ++ */ ++static void ++conf_parse_line(int trans, char *line, size_t sz) ++{ ++ char *val, *ptr; ++ size_t i; ++ int j; ++ static char *section = 0; ++ static char *arg = 0; ++ static int ln = 0; ++ ++ /* Lines starting with '#' or ';' are comments. */ ++ ln++; ++ /* Ignore blank lines */ ++ if (*line == '\0') ++ return; ++ ++ /* Strip off any leading blanks */ ++ while (isblank(*line)) ++ line++; ++ ++ if (*line == '#' || *line == ';') ++ return; ++ ++ /* '[section]' parsing... */ ++ if (*line == '[') { ++ line++; ++ /* Strip off any blanks after '[' */ ++ while (isblank(*line)) ++ line++; ++ for (i = 0; i < sz; i++) { ++ if (line[i] == ']') { ++ break; ++ } ++ } ++ if (section) ++ free(section); ++ if (i == sz) { ++ xlog_warn("config file error: line %d: " ++ "non-matched ']', ignoring until next section", ln); ++ section = 0; ++ return; ++ } ++ /* Strip off any blanks before ']' */ ++ val = line; ++ while (*val && !isblank(*val)) ++ val++, j++; ++ if (*val) ++ i = j; ++ section = malloc(i); ++ if (!section) { ++ xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, ++ (unsigned long)i); ++ return; ++ } ++ strncpy(section, line, i); ++ ++ if (arg) ++ free(arg); ++ arg = 0; ++ ++ ptr = strchr(val, '"'); ++ if (ptr == NULL) ++ return; ++ line = ++ptr; ++ while (*ptr && *ptr != '"') ++ ptr++; ++ if (*ptr == '\0') { ++ xlog_warn("config file error: line %d: " ++ "non-matched '\"', ignoring until next section", ln); ++ } else { ++ *ptr = '\0'; ++ arg = strdup(line); ++ if (!arg) ++ xlog_warn("conf_parse_line: %d: malloc arg failed", ln); ++ } ++ return; ++ } ++ ++ /* Deal with assignments. */ ++ for (i = 0; i < sz; i++) { ++ if (line[i] == '=') { ++ /* If no section, we are ignoring the lines. */ ++ if (!section) { ++ xlog_warn("config file error: line %d: " ++ "ignoring line due to no section", ln); ++ return; ++ } ++ line[strcspn (line, " \t=")] = '\0'; ++ val = line + i + 1 + strspn (line + i + 1, " \t"); ++ ++ /* Skip trailing comments, if any */ ++ for (j = 0; j < sz - (val - line); j++) { ++ if (val[j] == '#' || val[j] == ';') { ++ val[j] = '\0'; ++ break; ++ } ++ } ++ ++ /* Skip trailing whitespace, if any */ ++ for (j--; j > 0; j--) { ++ if (isspace(val[j])) ++ val[j] = '\0'; ++ else ++ break; ++ } ++ ++ /* XXX Perhaps should we not ignore errors? */ ++ conf_set(trans, section, arg, line, val, 0, 0); ++ return; ++ } ++ } ++ /* Other non-empty lines are weird. */ ++ i = strspn(line, " \t"); ++ if (line[i]) ++ xlog_warn("config file error: line %d:", ln); ++ ++ return; ++} ++ ++/* Parse the mapped configuration file. */ ++static void ++conf_parse(int trans, char *buf, size_t sz) ++{ ++ char *cp = buf; ++ char *bufend = buf + sz; ++ char *line; ++ ++ line = cp; ++ while (cp < bufend) { ++ if (*cp == '\n') { ++ /* Check for escaped newlines. */ ++ if (cp > buf && *(cp - 1) == '\\') ++ *(cp - 1) = *cp = ' '; ++ else { ++ *cp = '\0'; ++ conf_parse_line(trans, line, cp - line); ++ line = cp + 1; ++ } ++ } ++ cp++; ++ } ++ if (cp != line) ++ xlog_warn("conf_parse: last line non-terminated, ignored."); ++} ++ ++static void ++conf_load_defaults(int tr) ++{ ++ /* No defaults */ ++ return; ++} ++ ++void ++conf_init (void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) ++ LIST_INIT (&conf_bindings[i]); ++ ++ TAILQ_INIT (&conf_trans_queue); ++ conf_reinit(); ++} ++ ++/* Open the config file and map it into our address space, then parse it. */ ++void ++conf_reinit(void) ++{ ++ struct conf_binding *cb = 0; ++ int fd, trans; ++ unsigned int i; ++ size_t sz; ++ char *new_conf_addr = 0; ++ struct stat sb; ++ ++ if ((stat (conf_path, &sb) == 0) || (errno != ENOENT)) { ++ sz = sb.st_size; ++ fd = open (conf_path, O_RDONLY, 0); ++ if (fd == -1) { ++ xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path); ++ return; ++ } ++ ++ new_conf_addr = malloc(sz); ++ if (!new_conf_addr) { ++ xlog_warn("conf_reinit: malloc (%lu) failed", (unsigned long)sz); ++ goto fail; ++ } ++ ++ /* XXX I assume short reads won't happen here. */ ++ if (read (fd, new_conf_addr, sz) != (int)sz) { ++ xlog_warn("conf_reinit: read (%d, %p, %lu) failed", ++ fd, new_conf_addr, (unsigned long)sz); ++ goto fail; ++ } ++ close(fd); ++ ++ trans = conf_begin(); ++ /* XXX Should we not care about errors and rollback? */ ++ conf_parse(trans, new_conf_addr, sz); ++ } ++ else ++ trans = conf_begin(); ++ ++ /* Load default configuration values. */ ++ conf_load_defaults(trans); ++ ++ /* Free potential existing configuration. */ ++ if (conf_addr) { ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { ++ cb = LIST_FIRST (&conf_bindings[i]); ++ for (; cb; cb = LIST_FIRST (&conf_bindings[i])) ++ conf_remove_now(cb->section, cb->tag); ++ } ++ free (conf_addr); ++ } ++ ++ conf_end(trans, 1); ++ conf_addr = new_conf_addr; ++ return; ++ ++fail: ++ if (new_conf_addr) ++ free(new_conf_addr); ++ close (fd); ++} ++ ++/* ++ * Return the numeric value denoted by TAG in section SECTION or DEF ++ * if that tag does not exist. ++ */ ++int ++conf_get_num(char *section, char *tag, int def) ++{ ++ char *value = conf_get_str(section, tag); ++ ++ if (value) ++ return atoi(value); ++ ++ return def; ++} ++ ++/* Validate X according to the range denoted by TAG in section SECTION. */ ++int ++conf_match_num(char *section, char *tag, int x) ++{ ++ char *value = conf_get_str (section, tag); ++ int val, min, max, n; ++ ++ if (!value) ++ return 0; ++ n = sscanf (value, "%d,%d:%d", &val, &min, &max); ++ switch (n) { ++ case 1: ++ xlog(LOG_INFO, "conf_match_num: %s:%s %d==%d?", section, tag, val, x); ++ return x == val; ++ case 3: ++ xlog(LOG_INFO, "conf_match_num: %s:%s %d<=%d<=%d?", section, ++ tag, min, x, max); ++ return min <= x && max >= x; ++ default: ++ xlog(LOG_INFO, "conf_match_num: section %s tag %s: invalid number spec %s", ++ section, tag, value); ++ } ++ return 0; ++} ++ ++/* Return the string value denoted by TAG in section SECTION. */ ++char * ++conf_get_str(char *section, char *tag) ++{ ++ struct conf_binding *cb; ++ ++ cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); ++ for (; cb; cb = LIST_NEXT (cb, link)) { ++ if (strcasecmp (section, cb->section) == 0 ++ && strcasecmp (tag, cb->tag) == 0) ++ return cb->value; ++ } ++ return 0; ++} ++/* ++ * Find a section that may or may not have an argument ++ */ ++char * ++conf_get_section(char *section, char *arg, char *tag) ++{ ++ struct conf_binding *cb; ++ ++ cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); ++ for (; cb; cb = LIST_NEXT (cb, link)) { ++ if (strcasecmp(section, cb->section) != 0) ++ continue; ++ if (arg && strcasecmp(arg, cb->arg) != 0) ++ continue; ++ if (strcasecmp(tag, cb->tag) != 0) ++ continue; ++ return cb->value; ++ } ++ return 0; ++} ++ ++/* ++ * Build a list of string values out of the comma separated value denoted by ++ * TAG in SECTION. ++ */ ++struct conf_list * ++conf_get_list(char *section, char *tag) ++{ ++ char *liststr = 0, *p, *field, *t; ++ struct conf_list *list = 0; ++ struct conf_list_node *node; ++ ++ list = malloc (sizeof *list); ++ if (!list) ++ goto cleanup; ++ TAILQ_INIT (&list->fields); ++ list->cnt = 0; ++ liststr = conf_get_str(section, tag); ++ if (!liststr) ++ goto cleanup; ++ liststr = strdup (liststr); ++ if (!liststr) ++ goto cleanup; ++ p = liststr; ++ while ((field = strsep (&p, ",")) != NULL) { ++ /* Skip leading whitespace */ ++ while (isspace (*field)) ++ field++; ++ /* Skip trailing whitespace */ ++ if (p) { ++ for (t = p - 1; t > field && isspace (*t); t--) ++ *t = '\0'; ++ } ++ if (*field == '\0') { ++ xlog(LOG_INFO, "conf_get_list: empty field, ignoring..."); ++ continue; ++ } ++ list->cnt++; ++ node = calloc (1, sizeof *node); ++ if (!node) ++ goto cleanup; ++ node->field = strdup (field); ++ if (!node->field) { ++ free(node); ++ goto cleanup; ++ } ++ TAILQ_INSERT_TAIL (&list->fields, node, link); ++ } ++ free (liststr); ++ return list; ++ ++cleanup: ++ if (list) ++ conf_free_list(list); ++ if (liststr) ++ free(liststr); ++ return 0; ++} ++ ++struct conf_list * ++conf_get_tag_list(char *section) ++{ ++ struct conf_list *list = 0; ++ struct conf_list_node *node; ++ struct conf_binding *cb; ++ ++ list = malloc(sizeof *list); ++ if (!list) ++ goto cleanup; ++ TAILQ_INIT(&list->fields); ++ list->cnt = 0; ++ cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); ++ for (; cb; cb = LIST_NEXT(cb, link)) { ++ if (strcasecmp (section, cb->section) == 0) { ++ list->cnt++; ++ node = calloc(1, sizeof *node); ++ if (!node) ++ goto cleanup; ++ node->field = strdup(cb->tag); ++ if (!node->field) { ++ free(node); ++ goto cleanup; ++ } ++ TAILQ_INSERT_TAIL(&list->fields, node, link); ++ } ++ } ++ return list; ++ ++cleanup: ++ if (list) ++ conf_free_list(list); ++ return 0; ++} ++ ++/* Decode a PEM encoded buffer. */ ++int ++conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf) ++{ ++ u_int32_t c = 0; ++ u_int8_t c1, c2, c3, c4; ++ ++ while (*buf) { ++ if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) ++ return 0; ++ ++ buf++; ++ if (*buf > 127 || (c2 = asc2bin[*buf]) == 255) ++ return 0; ++ ++ buf++; ++ if (*buf == '=') { ++ c3 = c4 = 0; ++ c++; ++ ++ /* Check last four bit */ ++ if (c2 & 0xF) ++ return 0; ++ ++ if (strcmp((char *)buf, "==") == 0) ++ buf++; ++ else ++ return 0; ++ } else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255) ++ return 0; ++ else { ++ if (*++buf == '=') { ++ c4 = 0; ++ c += 2; ++ ++ /* Check last two bit */ ++ if (c3 & 3) ++ return 0; ++ ++ if (strcmp((char *)buf, "=")) ++ return 0; ++ } else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255) ++ return 0; ++ else ++ c += 3; ++ } ++ ++ buf++; ++ *out++ = (c1 << 2) | (c2 >> 4); ++ *out++ = (c2 << 4) | (c3 >> 2); ++ *out++ = (c3 << 6) | c4; ++ } ++ ++ *len = c; ++ return 1; ++} ++ ++void ++conf_free_list(struct conf_list *list) ++{ ++ struct conf_list_node *node = TAILQ_FIRST(&list->fields); ++ ++ while (node) { ++ TAILQ_REMOVE(&list->fields, node, link); ++ if (node->field) ++ free(node->field); ++ free (node); ++ node = TAILQ_FIRST(&list->fields); ++ } ++ free (list); ++} ++ ++int ++conf_begin(void) ++{ ++ static int seq = 0; ++ ++ return ++seq; ++} ++ ++static struct conf_trans * ++conf_trans_node(int transaction, enum conf_op op) ++{ ++ struct conf_trans *node; ++ ++ node = calloc (1, sizeof *node); ++ if (!node) { ++ xlog_warn("conf_trans_node: calloc (1, %lu) failed", ++ (unsigned long)sizeof *node); ++ return 0; ++ } ++ node->trans = transaction; ++ node->op = op; ++ TAILQ_INSERT_TAIL (&conf_trans_queue, node, link); ++ return node; ++} ++ ++/* Queue a set operation. */ ++static int ++conf_set(int transaction, char *section, char *arg, ++ char *tag, char *value, int override, int is_default) ++{ ++ struct conf_trans *node; ++ ++ node = conf_trans_node(transaction, CONF_SET); ++ if (!node) ++ return 1; ++ node->section = strdup(section); ++ if (!node->section) { ++ xlog_warn("conf_set: strdup(\"%s\") failed", section); ++ goto fail; ++ } ++ /* Make Section names case-insensitive */ ++ upper2lower(node->section); ++ ++ if (arg) { ++ node->arg = strdup(arg); ++ if (!node->arg) { ++ xlog_warn("conf_set: strdup(\"%s\") failed", arg); ++ goto fail; ++ } ++ } else ++ node->arg = NULL; ++ ++ node->tag = strdup(tag); ++ if (!node->tag) { ++ xlog_warn("conf_set: strdup(\"%s\") failed", tag); ++ goto fail; ++ } ++ node->value = strdup(value); ++ if (!node->value) { ++ xlog_warn("conf_set: strdup(\"%s\") failed", value); ++ goto fail; ++ } ++ node->override = override; ++ node->is_default = is_default; ++ return 0; ++ ++fail: ++ if (node->tag) ++ free(node->tag); ++ if (node->section) ++ free(node->section); ++ if (node) ++ free(node); ++ return 1; ++} ++ ++/* Queue a remove operation. */ ++int ++conf_remove(int transaction, char *section, char *tag) ++{ ++ struct conf_trans *node; ++ ++ node = conf_trans_node(transaction, CONF_REMOVE); ++ if (!node) ++ goto fail; ++ node->section = strdup(section); ++ if (!node->section) { ++ xlog_warn("conf_remove: strdup(\"%s\") failed", section); ++ goto fail; ++ } ++ node->tag = strdup(tag); ++ if (!node->tag) { ++ xlog_warn("conf_remove: strdup(\"%s\") failed", tag); ++ goto fail; ++ } ++ return 0; ++ ++fail: ++ if (node && node->section) ++ free (node->section); ++ if (node) ++ free (node); ++ return 1; ++} ++ ++/* Queue a remove section operation. */ ++int ++conf_remove_section(int transaction, char *section) ++{ ++ struct conf_trans *node; ++ ++ node = conf_trans_node(transaction, CONF_REMOVE_SECTION); ++ if (!node) ++ goto fail; ++ node->section = strdup(section); ++ if (!node->section) { ++ xlog_warn("conf_remove_section: strdup(\"%s\") failed", section); ++ goto fail; ++ } ++ return 0; ++ ++fail: ++ if (node) ++ free(node); ++ return 1; ++} ++ ++/* Execute all queued operations for this transaction. Cleanup. */ ++int ++conf_end(int transaction, int commit) ++{ ++ struct conf_trans *node, *next; ++ ++ for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { ++ next = TAILQ_NEXT(node, link); ++ if (node->trans == transaction) { ++ if (commit) { ++ switch (node->op) { ++ case CONF_SET: ++ conf_set_now(node->section, node->arg, ++ node->tag, node->value, node->override, ++ node->is_default); ++ break; ++ case CONF_REMOVE: ++ conf_remove_now(node->section, node->tag); ++ break; ++ case CONF_REMOVE_SECTION: ++ conf_remove_section_now(node->section); ++ break; ++ default: ++ xlog(LOG_INFO, "conf_end: unknown operation: %d", node->op); ++ } ++ } ++ TAILQ_REMOVE (&conf_trans_queue, node, link); ++ if (node->section) ++ free(node->section); ++ if (node->tag) ++ free(node->tag); ++ if (node->value) ++ free(node->value); ++ free (node); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Dump running configuration upon SIGUSR1. ++ * Configuration is "stored in reverse order", so reverse it again. ++ */ ++struct dumper { ++ char *s, *v; ++ struct dumper *next; ++}; ++ ++static void ++conf_report_dump(struct dumper *node) ++{ ++ /* Recursive, cleanup when we're done. */ ++ if (node->next) ++ conf_report_dump(node->next); ++ ++ if (node->v) ++ xlog(LOG_INFO, "%s=\t%s", node->s, node->v); ++ else if (node->s) { ++ xlog(LOG_INFO, "%s", node->s); ++ if (strlen(node->s) > 0) ++ free(node->s); ++ } ++ ++ free (node); ++} ++ ++void ++conf_report (void) ++{ ++ struct conf_binding *cb, *last = 0; ++ unsigned int i, len, diff_arg = 0; ++ char *current_section = (char *)0; ++ char *current_arg = (char *)0; ++ struct dumper *dumper, *dnode; ++ ++ dumper = dnode = (struct dumper *)calloc(1, sizeof *dumper); ++ if (!dumper) ++ goto mem_fail; ++ ++ xlog(LOG_INFO, "conf_report: dumping running configuration"); ++ ++ for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) ++ for (cb = LIST_FIRST(&conf_bindings[i]); cb; cb = LIST_NEXT(cb, link)) { ++ if (!cb->is_default) { ++ /* Make sure the Section arugment is the same */ ++ if (current_arg && current_section && cb->arg) { ++ if (strcmp(cb->section, current_section) == 0 && ++ strcmp(cb->arg, current_arg) != 0) ++ diff_arg = 1; ++ } ++ /* Dump this entry. */ ++ if (!current_section || strcmp(cb->section, current_section) ++ || diff_arg) { ++ if (current_section || diff_arg) { ++ len = strlen (current_section) + 3; ++ if (current_arg) ++ len += strlen(current_arg) + 3; ++ dnode->s = malloc(len); ++ if (!dnode->s) ++ goto mem_fail; ++ ++ if (current_arg) ++ snprintf(dnode->s, len, "[%s \"%s\"]", ++ current_section, current_arg); ++ else ++ snprintf(dnode->s, len, "[%s]", current_section); ++ ++ dnode->next = ++ (struct dumper *)calloc(1, sizeof (struct dumper)); ++ dnode = dnode->next; ++ if (!dnode) ++ goto mem_fail; ++ ++ dnode->s = ""; ++ dnode->next = ++ (struct dumper *)calloc(1, sizeof (struct dumper)); ++ dnode = dnode->next; ++ if (!dnode) ++ goto mem_fail; ++ } ++ current_section = cb->section; ++ current_arg = cb->arg; ++ diff_arg = 0; ++ } ++ dnode->s = cb->tag; ++ dnode->v = cb->value; ++ dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper)); ++ dnode = dnode->next; ++ if (!dnode) ++ goto mem_fail; ++ last = cb; ++ } ++ } ++ ++ if (last) { ++ len = strlen(last->section) + 3; ++ if (last->arg) ++ len += strlen(last->arg) + 3; ++ dnode->s = malloc(len); ++ if (!dnode->s) ++ goto mem_fail; ++ if (last->arg) ++ snprintf(dnode->s, len, "[%s \"%s\"]", last->section, last->arg); ++ else ++ snprintf(dnode->s, len, "[%s]", last->section); ++ } ++ conf_report_dump(dumper); ++ return; ++ ++mem_fail: ++ xlog_warn("conf_report: malloc/calloc failed"); ++ while ((dnode = dumper) != 0) { ++ dumper = dumper->next; ++ if (dnode->s) ++ free(dnode->s); ++ free(dnode); ++ } ++ return; ++} +diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am +index eb393df..4dabb3d 100644 +--- a/utils/idmapd/Makefile.am ++++ b/utils/idmapd/Makefile.am +@@ -14,7 +14,6 @@ EXTRA_DIST = \ + + idmapd_SOURCES = \ + atomicio.c \ +- cfg.c \ + idmapd.c \ + strlcat.c \ + strlcpy.c \ +diff --git a/utils/idmapd/cfg.c b/utils/idmapd/cfg.c +deleted file mode 100644 +index 16d392a..0000000 +--- a/utils/idmapd/cfg.c ++++ /dev/null +@@ -1,893 +0,0 @@ +-/* $OpenBSD: conf.c,v 1.55 2003/06/03 14:28:16 ho Exp $ */ +-/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ +- +-/* +- * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. +- * Copyright (c) 2000, 2001, 2002 H�kan Olsson. 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. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +- */ +- +-/* +- * This code was written under funding by Ericsson Radio Systems. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "cfg.h" +- +-static void conf_load_defaults (int); +-#if 0 +-static int conf_find_trans_xf (int, char *); +-#endif +- +-size_t strlcpy(char *, const char *, size_t); +- +-struct conf_trans { +- TAILQ_ENTRY (conf_trans) link; +- int trans; +- enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; +- char *section; +- char *tag; +- char *value; +- int override; +- int is_default; +-}; +- +-TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; +- +-/* +- * Radix-64 Encoding. +- */ +-const u_int8_t bin2asc[] +- = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +- +-const u_int8_t asc2bin[] = +-{ +- 255, 255, 255, 255, 255, 255, 255, 255, +- 255, 255, 255, 255, 255, 255, 255, 255, +- 255, 255, 255, 255, 255, 255, 255, 255, +- 255, 255, 255, 255, 255, 255, 255, 255, +- 255, 255, 255, 255, 255, 255, 255, 255, +- 255, 255, 255, 62, 255, 255, 255, 63, +- 52, 53, 54, 55, 56, 57, 58, 59, +- 60, 61, 255, 255, 255, 255, 255, 255, +- 255, 0, 1, 2, 3, 4, 5, 6, +- 7, 8, 9, 10, 11, 12, 13, 14, +- 15, 16, 17, 18, 19, 20, 21, 22, +- 23, 24, 25, 255, 255, 255, 255, 255, +- 255, 26, 27, 28, 29, 30, 31, 32, +- 33, 34, 35, 36, 37, 38, 39, 40, +- 41, 42, 43, 44, 45, 46, 47, 48, +- 49, 50, 51, 255, 255, 255, 255, 255 +-}; +- +-struct conf_binding { +- LIST_ENTRY (conf_binding) link; +- char *section; +- char *tag; +- char *value; +- int is_default; +-}; +- +-char *conf_path; +-LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; +- +-static char *conf_addr; +- +-static __inline__ u_int8_t +-conf_hash (char *s) +-{ +- u_int8_t hash = 0; +- +- while (*s) +- { +- hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); +- s++; +- } +- return hash; +-} +- +-/* +- * Insert a tag-value combination from LINE (the equal sign is at POS) +- */ +-static int +-conf_remove_now (char *section, char *tag) +-{ +- struct conf_binding *cb, *next; +- +- for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) +- { +- next = LIST_NEXT (cb, link); +- if (strcasecmp (cb->section, section) == 0 +- && strcasecmp (cb->tag, tag) == 0) +- { +- LIST_REMOVE (cb, link); +- warnx("[%s]:%s->%s removed", section, tag, cb->value); +- free (cb->section); +- free (cb->tag); +- free (cb->value); +- free (cb); +- return 0; +- } +- } +- return 1; +-} +- +-static int +-conf_remove_section_now (char *section) +-{ +- struct conf_binding *cb, *next; +- int unseen = 1; +- +- for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) +- { +- next = LIST_NEXT (cb, link); +- if (strcasecmp (cb->section, section) == 0) +- { +- unseen = 0; +- LIST_REMOVE (cb, link); +- warnx("[%s]:%s->%s removed", section, cb->tag, cb->value); +- free (cb->section); +- free (cb->tag); +- free (cb->value); +- free (cb); +- } +- } +- return unseen; +-} +- +-/* +- * Insert a tag-value combination from LINE (the equal sign is at POS) +- * into SECTION of our configuration database. +- */ +-static int +-conf_set_now (char *section, char *tag, char *value, int override, +- int is_default) +-{ +- struct conf_binding *node = 0; +- +- if (override) +- conf_remove_now (section, tag); +- else if (conf_get_str (section, tag)) +- { +- if (!is_default) +- warnx("conf_set: duplicate tag [%s]:%s, ignoring...\n", section, tag); +- return 1; +- } +- +- node = calloc (1, sizeof *node); +- if (!node) +- { +- warnx("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node); +- return 1; +- } +- node->section = strdup (section); +- node->tag = strdup (tag); +- node->value = strdup (value); +- node->is_default = is_default; +- +- LIST_INSERT_HEAD (&conf_bindings[conf_hash (section)], node, link); +- return 0; +-} +- +-/* +- * Parse the line LINE of SZ bytes. Skip Comments, recognize section +- * headers and feed tag-value pairs into our configuration database. +- */ +-static void +-conf_parse_line (int trans, char *line, size_t sz) +-{ +- char *val; +- size_t i; +- int j; +- static char *section = 0; +- static int ln = 0; +- +- ln++; +- +- /* Lines starting with '#' or ';' are comments. */ +- if (*line == '#' || *line == ';') +- return; +- +- /* '[section]' parsing... */ +- if (*line == '[') +- { +- for (i = 1; i < sz; i++) +- if (line[i] == ']') +- break; +- if (section) +- free (section); +- if (i == sz) +- { +- warnx("conf_parse_line: %d:" +- "non-matched ']', ignoring until next section", ln); +- section = 0; +- return; +- } +- section = malloc (i); +- if (!section) +- { +- warnx("conf_parse_line: %d: malloc (%lu) failed", ln, +- (unsigned long)i); +- return; +- } +- strlcpy (section, line + 1, i); +- return; +- } +- +- /* Deal with assignments. */ +- for (i = 0; i < sz; i++) +- if (line[i] == '=') +- { +- /* If no section, we are ignoring the lines. */ +- if (!section) +- { +- warnx("conf_parse_line: %d: ignoring line due to no section", ln); +- return; +- } +- line[strcspn (line, " \t=")] = '\0'; +- val = line + i + 1 + strspn (line + i + 1, " \t"); +- /* Skip trailing whitespace, if any */ +- for (j = sz - (val - line) - 1; j > 0 && isspace (val[j]); j--) +- val[j] = '\0'; +- /* XXX Perhaps should we not ignore errors? */ +- conf_set (trans, section, line, val, 0, 0); +- return; +- } +- +- /* Other non-empty lines are weird. */ +- i = strspn (line, " \t"); +- if (line[i]) +- warnx("conf_parse_line: %d: syntax error", ln); +- +- return; +-} +- +-/* Parse the mapped configuration file. */ +-static void +-conf_parse (int trans, char *buf, size_t sz) +-{ +- char *cp = buf; +- char *bufend = buf + sz; +- char *line; +- +- line = cp; +- while (cp < bufend) +- { +- if (*cp == '\n') +- { +- /* Check for escaped newlines. */ +- if (cp > buf && *(cp - 1) == '\\') +- *(cp - 1) = *cp = ' '; +- else +- { +- *cp = '\0'; +- conf_parse_line (trans, line, cp - line); +- line = cp + 1; +- } +- } +- cp++; +- } +- if (cp != line) +- warnx("conf_parse: last line non-terminated, ignored."); +-} +- +-static void +-conf_load_defaults (int tr) +-{ +- /* No defaults */ +- return; +-} +- +-void +-conf_init (void) +-{ +- unsigned int i; +- +- for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) +- LIST_INIT (&conf_bindings[i]); +- TAILQ_INIT (&conf_trans_queue); +- conf_reinit (); +-} +- +-/* Open the config file and map it into our address space, then parse it. */ +-void +-conf_reinit (void) +-{ +- struct conf_binding *cb = 0; +- int fd, trans; +- unsigned int i; +- size_t sz; +- char *new_conf_addr = 0; +- struct stat sb; +- +- if ((stat (conf_path, &sb) == 0) || (errno != ENOENT)) +- { +- sz = sb.st_size; +- fd = open (conf_path, O_RDONLY, 0); +- if (fd == -1) +- { +- warnx("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path); +- return; +- } +- +- new_conf_addr = malloc (sz); +- if (!new_conf_addr) +- { +- warnx("conf_reinit: malloc (%lu) failed", (unsigned long)sz); +- goto fail; +- } +- +- /* XXX I assume short reads won't happen here. */ +- if (read (fd, new_conf_addr, sz) != (int)sz) +- { +- warnx("conf_reinit: read (%d, %p, %lu) failed", +- fd, new_conf_addr, (unsigned long)sz); +- goto fail; +- } +- close (fd); +- +- trans = conf_begin (); +- +- /* XXX Should we not care about errors and rollback? */ +- conf_parse (trans, new_conf_addr, sz); +- } +- else +- trans = conf_begin (); +- +- /* Load default configuration values. */ +- conf_load_defaults (trans); +- +- /* Free potential existing configuration. */ +- if (conf_addr) +- { +- for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) +- for (cb = LIST_FIRST (&conf_bindings[i]); cb; +- cb = LIST_FIRST (&conf_bindings[i])) +- conf_remove_now (cb->section, cb->tag); +- free (conf_addr); +- } +- +- conf_end (trans, 1); +- conf_addr = new_conf_addr; +- return; +- +- fail: +- if (new_conf_addr) +- free (new_conf_addr); +- close (fd); +-} +- +-/* +- * Return the numeric value denoted by TAG in section SECTION or DEF +- * if that tag does not exist. +- */ +-int +-conf_get_num (char *section, char *tag, int def) +-{ +- char *value = conf_get_str (section, tag); +- +- if (value) +- return atoi (value); +- return def; +-} +- +-/* Validate X according to the range denoted by TAG in section SECTION. */ +-int +-conf_match_num (char *section, char *tag, int x) +-{ +- char *value = conf_get_str (section, tag); +- int val, min, max, n; +- +- if (!value) +- return 0; +- n = sscanf (value, "%d,%d:%d", &val, &min, &max); +- switch (n) +- { +- case 1: +- warnx("conf_match_num: %s:%s %d==%d?", section, tag, val, x); +- return x == val; +- case 3: +- warnx("conf_match_num: %s:%s %d<=%d<=%d?", section, tag, min, x, max); +- return min <= x && max >= x; +- default: +- warnx("conf_match_num: section %s tag %s: invalid number spec %s", +- section, tag, value); +- } +- return 0; +-} +- +-/* Return the string value denoted by TAG in section SECTION. */ +-char * +-conf_get_str (char *section, char *tag) +-{ +- struct conf_binding *cb; +- +- for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; +- cb = LIST_NEXT (cb, link)) +- if (strcasecmp (section, cb->section) == 0 +- && strcasecmp (tag, cb->tag) == 0) +- { +- return cb->value; +- } +- return 0; +-} +- +-/* +- * Build a list of string values out of the comma separated value denoted by +- * TAG in SECTION. +- */ +-struct conf_list * +-conf_get_list (char *section, char *tag) +-{ +- char *liststr = 0, *p, *field, *t; +- struct conf_list *list = 0; +- struct conf_list_node *node; +- +- list = malloc (sizeof *list); +- if (!list) +- goto cleanup; +- TAILQ_INIT (&list->fields); +- list->cnt = 0; +- liststr = conf_get_str (section, tag); +- if (!liststr) +- goto cleanup; +- liststr = strdup (liststr); +- if (!liststr) +- goto cleanup; +- p = liststr; +- while ((field = strsep (&p, ",")) != NULL) +- { +- /* Skip leading whitespace */ +- while (isspace (*field)) +- field++; +- /* Skip trailing whitespace */ +- if (p) +- for (t = p - 1; t > field && isspace (*t); t--) +- *t = '\0'; +- if (*field == '\0') +- { +- warnx("conf_get_list: empty field, ignoring..."); +- continue; +- } +- list->cnt++; +- node = calloc (1, sizeof *node); +- if (!node) +- goto cleanup; +- node->field = strdup (field); +- if (!node->field) { +- free(node); +- goto cleanup; +- } +- TAILQ_INSERT_TAIL (&list->fields, node, link); +- } +- free (liststr); +- return list; +- +- cleanup: +- if (list) +- conf_free_list (list); +- if (liststr) +- free (liststr); +- return 0; +-} +- +-struct conf_list * +-conf_get_tag_list (char *section) +-{ +- struct conf_list *list = 0; +- struct conf_list_node *node; +- struct conf_binding *cb; +- +- list = malloc (sizeof *list); +- if (!list) +- goto cleanup; +- TAILQ_INIT (&list->fields); +- list->cnt = 0; +- for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; +- cb = LIST_NEXT (cb, link)) +- if (strcasecmp (section, cb->section) == 0) +- { +- list->cnt++; +- node = calloc (1, sizeof *node); +- if (!node) +- goto cleanup; +- node->field = strdup (cb->tag); +- if (!node->field) { +- free(node); +- goto cleanup; +- } +- TAILQ_INSERT_TAIL (&list->fields, node, link); +- } +- return list; +- +- cleanup: +- if (list) +- conf_free_list (list); +- return 0; +-} +- +-/* Decode a PEM encoded buffer. */ +-int +-conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf) +-{ +- u_int32_t c = 0; +- u_int8_t c1, c2, c3, c4; +- +- while (*buf) +- { +- if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) +- return 0; +- buf++; +- +- if (*buf > 127 || (c2 = asc2bin[*buf]) == 255) +- return 0; +- buf++; +- +- if (*buf == '=') +- { +- c3 = c4 = 0; +- c++; +- +- /* Check last four bit */ +- if (c2 & 0xF) +- return 0; +- +- if (strcmp ((char *)buf, "==") == 0) +- buf++; +- else +- return 0; +- } +- else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255) +- return 0; +- else +- { +- if (*++buf == '=') +- { +- c4 = 0; +- c += 2; +- +- /* Check last two bit */ +- if (c3 & 3) +- return 0; +- +- if (strcmp ((char *)buf, "=")) +- return 0; +- +- } +- else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255) +- return 0; +- else +- c += 3; +- } +- +- buf++; +- *out++ = (c1 << 2) | (c2 >> 4); +- *out++ = (c2 << 4) | (c3 >> 2); +- *out++ = (c3 << 6) | c4; +- } +- +- *len = c; +- return 1; +- +-} +- +-void +-conf_free_list (struct conf_list *list) +-{ +- struct conf_list_node *node = TAILQ_FIRST (&list->fields); +- +- while (node) +- { +- TAILQ_REMOVE (&list->fields, node, link); +- if (node->field) +- free (node->field); +- free (node); +- node = TAILQ_FIRST (&list->fields); +- } +- free (list); +-} +- +-int +-conf_begin (void) +-{ +- static int seq = 0; +- +- return ++seq; +-} +- +-static struct conf_trans * +-conf_trans_node (int transaction, enum conf_op op) +-{ +- struct conf_trans *node; +- +- node = calloc (1, sizeof *node); +- if (!node) +- { +- warnx("conf_trans_node: calloc (1, %lu) failed", +- (unsigned long)sizeof *node); +- return 0; +- } +- node->trans = transaction; +- node->op = op; +- TAILQ_INSERT_TAIL (&conf_trans_queue, node, link); +- return node; +-} +- +-/* Queue a set operation. */ +-int +-conf_set (int transaction, char *section, char *tag, char *value, int override, +- int is_default) +-{ +- struct conf_trans *node; +- +- node = conf_trans_node (transaction, CONF_SET); +- if (!node) +- return 1; +- node->section = strdup (section); +- if (!node->section) +- { +- warnx("conf_set: strdup (\"%s\") failed", section); +- goto fail; +- } +- node->tag = strdup (tag); +- if (!node->tag) +- { +- warnx("conf_set: strdup (\"%s\") failed", tag); +- goto fail; +- } +- node->value = strdup (value); +- if (!node->value) +- { +- warnx("conf_set: strdup (\"%s\") failed", value); +- goto fail; +- } +- node->override = override; +- node->is_default = is_default; +- return 0; +- +- fail: +- if (node->tag) +- free (node->tag); +- if (node->section) +- free (node->section); +- if (node) +- free (node); +- return 1; +-} +- +-/* Queue a remove operation. */ +-int +-conf_remove (int transaction, char *section, char *tag) +-{ +- struct conf_trans *node; +- +- node = conf_trans_node (transaction, CONF_REMOVE); +- if (!node) +- goto fail; +- node->section = strdup (section); +- if (!node->section) +- { +- warnx("conf_remove: strdup (\"%s\") failed", section); +- goto fail; +- } +- node->tag = strdup (tag); +- if (!node->tag) +- { +- warnx("conf_remove: strdup (\"%s\") failed", tag); +- goto fail; +- } +- return 0; +- +- fail: +- if (node && node->section) +- free (node->section); +- if (node) +- free (node); +- return 1; +-} +- +-/* Queue a remove section operation. */ +-int +-conf_remove_section (int transaction, char *section) +-{ +- struct conf_trans *node; +- +- node = conf_trans_node (transaction, CONF_REMOVE_SECTION); +- if (!node) +- goto fail; +- node->section = strdup (section); +- if (!node->section) +- { +- warnx("conf_remove_section: strdup (\"%s\") failed", section); +- goto fail; +- } +- return 0; +- +- fail: +- if (node) +- free (node); +- return 1; +-} +- +-/* Execute all queued operations for this transaction. Cleanup. */ +-int +-conf_end (int transaction, int commit) +-{ +- struct conf_trans *node, *next; +- +- for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next) +- { +- next = TAILQ_NEXT (node, link); +- if (node->trans == transaction) +- { +- if (commit) +- switch (node->op) +- { +- case CONF_SET: +- conf_set_now (node->section, node->tag, node->value, +- node->override, node->is_default); +- break; +- case CONF_REMOVE: +- conf_remove_now (node->section, node->tag); +- break; +- case CONF_REMOVE_SECTION: +- conf_remove_section_now (node->section); +- break; +- default: +- warnx("conf_end: unknown operation: %d", node->op); +- } +- TAILQ_REMOVE (&conf_trans_queue, node, link); +- if (node->section) +- free (node->section); +- if (node->tag) +- free (node->tag); +- if (node->value) +- free (node->value); +- free (node); +- } +- } +- return 0; +-} +- +-/* +- * Dump running configuration upon SIGUSR1. +- * Configuration is "stored in reverse order", so reverse it again. +- */ +-struct dumper { +- char *s, *v; +- struct dumper *next; +-}; +- +-static void +-conf_report_dump (struct dumper *node) +-{ +- /* Recursive, cleanup when we're done. */ +- +- if (node->next) +- conf_report_dump (node->next); +- +- if (node->v) +- warnx("%s=\t%s", node->s, node->v); +- else if (node->s) +- { +- warnx("%s", node->s); +- if (strlen (node->s) > 0) +- free (node->s); +- } +- +- free (node); +-} +- +-void +-conf_report (void) +-{ +- struct conf_binding *cb, *last = 0; +- unsigned int i, len; +- char *current_section = (char *)0; +- struct dumper *dumper, *dnode; +- +- dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper); +- if (!dumper) +- goto mem_fail; +- +- warnx("conf_report: dumping running configuration"); +- +- for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) +- for (cb = LIST_FIRST (&conf_bindings[i]); cb; +- cb = LIST_NEXT (cb, link)) +- { +- if (!cb->is_default) +- { +- /* Dump this entry. */ +- if (!current_section || strcmp (cb->section, current_section)) +- { +- if (current_section) +- { +- len = strlen (current_section) + 3; +- dnode->s = malloc (len); +- if (!dnode->s) +- goto mem_fail; +- +- snprintf (dnode->s, len, "[%s]", current_section); +- dnode->next +- = (struct dumper *)calloc (1, sizeof (struct dumper)); +- dnode = dnode->next; +- if (!dnode) +- goto mem_fail; +- +- dnode->s = ""; +- dnode->next +- = (struct dumper *)calloc (1, sizeof (struct dumper)); +- dnode = dnode->next; +- if (!dnode) +- goto mem_fail; +- } +- current_section = cb->section; +- } +- dnode->s = cb->tag; +- dnode->v = cb->value; +- dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper)); +- dnode = dnode->next; +- if (!dnode) +- goto mem_fail; +- last = cb; +- } +- } +- +- if (last) +- { +- len = strlen (last->section) + 3; +- dnode->s = malloc (len); +- if (!dnode->s) +- goto mem_fail; +- snprintf (dnode->s, len, "[%s]", last->section); +- } +- +- conf_report_dump (dumper); +- +- return; +- +- mem_fail: +- warnx("conf_report: malloc/calloc failed"); +- while ((dnode = dumper) != 0) +- { +- dumper = dumper->next; +- if (dnode->s) +- free (dnode->s); +- free (dnode); +- } +- return; +-} +diff --git a/utils/idmapd/cfg.h b/utils/idmapd/cfg.h +deleted file mode 100644 +index c1ca940..0000000 +--- a/utils/idmapd/cfg.h ++++ /dev/null +@@ -1,67 +0,0 @@ +-/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */ +-/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ +- +-/* +- * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. +- * Copyright (c) 2000, 2003 H�kan Olsson. 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. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. +- */ +- +-/* +- * This code was written under funding by Ericsson Radio Systems. +- */ +- +-#ifndef _CONF_H_ +-#define _CONF_H_ +- +-#include "queue.h" +- +-struct conf_list_node { +- TAILQ_ENTRY(conf_list_node) link; +- char *field; +-}; +- +-struct conf_list { +- size_t cnt; +- TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; +-}; +- +-extern char *conf_path; +- +-extern int conf_begin(void); +-extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *); +-extern int conf_end(int, int); +-extern void conf_free_list(struct conf_list *); +-extern struct sockaddr *conf_get_address(char *, char *); +-extern struct conf_list *conf_get_list(char *, char *); +-extern struct conf_list *conf_get_tag_list(char *); +-extern int conf_get_num(char *, char *, int); +-extern char *conf_get_str(char *, char *); +-extern void conf_init(void); +-extern int conf_match_num(char *, char *, int); +-extern void conf_reinit(void); +-extern int conf_remove(int, char *, char *); +-extern int conf_remove_section(int, char *); +-extern int conf_set(int, char *, char *, char *, int, int); +-extern void conf_report(void); +- +-#endif /* _CONF_H_ */ +diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c +index 9cbe96c..65a6a2a 100644 +--- a/utils/idmapd/idmapd.c ++++ b/utils/idmapd/idmapd.c +@@ -66,7 +66,7 @@ + #endif /* HAVE_CONFIG_H */ + + #include "xlog.h" +-#include "cfg.h" ++#include "conffile.h" + #include "queue.h" + #include "nfslib.h" + +@@ -156,7 +156,7 @@ static char *nobodyuser, *nobodygroup; + static uid_t nobodyuid; + static gid_t nobodygid; + +-/* Used by cfg.c */ ++/* Used by conffile.c in libnfs.a */ + char *conf_path; + + static int +diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am +index 459fa45..299384a 100644 +--- a/utils/mount/Makefile.am ++++ b/utils/mount/Makefile.am +@@ -15,7 +15,14 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \ + nfsumount.c \ + mount_constants.h error.h network.h fstab.h token.h \ + parse_opt.h parse_dev.h \ +- nfs4_mount.h nfs_mount4.h stropts.h version.h ++ nfs4_mount.h nfs_mount4.h stropts.h version.h \ ++ mount_config.h ++ ++if MOUNT_CONFIG ++mount_nfs_SOURCES += configfile.c ++man5_MANS += nfsmount.conf.man ++EXTRA_DIST += nfsmount.conf ++endif + + mount_nfs_LDADD = ../../support/nfs/libnfs.a \ + ../../support/export/libexport.a +diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c +new file mode 100644 +index 0000000..e347b0e +--- /dev/null ++++ b/utils/mount/configfile.c +@@ -0,0 +1,320 @@ ++/* ++ * configfile.c -- mount configuration file manipulation ++ * Copyright (C) 2008 Red Hat, Inc ++ * ++ * - Routines use to create mount options from the mount ++ * configuration file. ++ * ++ * 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; either version 2, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "xlog.h" ++#include "conffile.h" ++ ++#define KBYTES(x) ((x) * (1024)) ++#define MEGABYTES(x) ((x) * (1048576)) ++#define GIGABYTES(x) ((x) * (1073741824)) ++ ++#ifndef NFSMOUNT_GLOBAL_OPTS ++#define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options" ++#endif ++ ++#ifndef NFSMOUNT_MOUNTPOINT ++#define NFSMOUNT_MOUNTPOINT "MountPoint" ++#endif ++ ++#ifndef NFSMOUNT_SERVER ++#define NFSMOUNT_SERVER "Server" ++#endif ++ ++#ifndef MOUNTOPTS_CONFFILE ++#define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf" ++#endif ++char *conf_path = MOUNTOPTS_CONFFILE; ++enum { ++ MNT_NOARG=0, ++ MNT_INTARG, ++ MNT_STRARG, ++ MNT_SPEC, ++ MNT_UNSET ++}; ++struct mnt_alias { ++ char *alias; ++ char *opt; ++ int argtype; ++} mnt_alias_tab[] = { ++ {"background", "bg", MNT_NOARG}, ++ {"foreground", "fg", MNT_NOARG}, ++ {"sloppy", "sloppy", MNT_NOARG}, ++}; ++int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); ++ ++/* ++ * See if the option is an alias, if so return the ++ * real mount option along with the argument type. ++ */ ++inline static ++char *mountopts_alias(char *opt, int *argtype) ++{ ++ int i; ++ ++ *argtype = MNT_UNSET; ++ for (i=0; i < mnt_alias_sz; i++) { ++ if (strcasecmp(opt, mnt_alias_tab[i].alias) != 0) ++ continue; ++ *argtype = mnt_alias_tab[i].argtype; ++ return mnt_alias_tab[i].opt; ++ } ++ /* Make option names case-insensitive */ ++ upper2lower(opt); ++ ++ return opt; ++} ++/* ++ * Convert numeric strings that end with 'k', 'm' or 'g' ++ * into numeric strings with the real value. ++ * Meaning '8k' becomes '8094'. ++ */ ++char *mountopts_convert(char *value) ++{ ++ unsigned long long factor, num; ++ static char buf[64]; ++ char *ch; ++ ++ ch = &value[strlen(value)-1]; ++ switch (tolower(*ch)) { ++ case 'k': ++ factor = KBYTES(1); ++ break; ++ case 'm': ++ factor = MEGABYTES(1); ++ break; ++ case 'g': ++ factor = GIGABYTES(1); ++ break; ++ default: ++ return value; ++ } ++ *ch = '\0'; ++ if (strncmp(value, "0x", 2) == 0) { ++ num = strtol(value, (char **)NULL, 16); ++ } else if (strncmp(value, "0", 1) == 0) { ++ num = strtol(value, (char **)NULL, 8); ++ } else { ++ num = strtol(value, (char **)NULL, 10); ++ } ++ num *= factor; ++ snprintf(buf, 64, "%lld", num); ++ ++ return buf; ++} ++ ++struct entry { ++ SLIST_ENTRY(entry) entries; ++ char *opt; ++}; ++static SLIST_HEAD(shead, entry) head = SLIST_HEAD_INITIALIZER(head); ++static int list_size; ++ ++/* ++ * Add option to the link list ++ */ ++inline static void ++add_entry(char *opt) ++{ ++ struct entry *entry; ++ ++ entry = calloc(1, sizeof(struct entry)); ++ if (entry == NULL) { ++ xlog_warn("Unable calloc memory for mount configs"); ++ return; ++ } ++ entry->opt = strdup(opt); ++ if (entry->opt == NULL) { ++ xlog_warn("Unable calloc memory for mount opts"); ++ free(entry); ++ return; ++ } ++ SLIST_INSERT_HEAD(&head, entry, entries); ++} ++/* ++ * See if the given entry exists if the link list, ++ * if so return that entry ++ */ ++inline static ++char *lookup_entry(char *opt) ++{ ++ struct entry *entry; ++ ++ SLIST_FOREACH(entry, &head, entries) { ++ if (strcasecmp(entry->opt, opt) == 0) ++ return opt; ++ } ++ return NULL; ++} ++/* ++ * Free all entries on the link list ++ */ ++inline static ++void free_all(void) ++{ ++ struct entry *entry; ++ ++ while (!SLIST_EMPTY(&head)) { ++ entry = SLIST_FIRST(&head); ++ SLIST_REMOVE_HEAD(&head, entries); ++ free(entry->opt); ++ free(entry); ++ } ++} ++/* ++ * Parse the given section of the configuration ++ * file to if there are any mount options set. ++ * If so, added them to link list. ++ */ ++static void ++conf_parse_mntopts(char *section, char *arg, char *opts) ++{ ++ struct conf_list *list; ++ struct conf_list_node *node; ++ char buf[BUFSIZ], *value, *field; ++ char *nvalue, *ptr; ++ int argtype; ++ ++ list = conf_get_tag_list(section); ++ TAILQ_FOREACH(node, &list->fields, link) { ++ /* ++ * Do not overwrite options if already exists ++ */ ++ snprintf(buf, BUFSIZ, "%s=", node->field); ++ if (opts && strcasestr(opts, buf) != NULL) ++ continue; ++ if (lookup_entry(node->field) != NULL) ++ continue; ++ buf[0] = '\0'; ++ value = conf_get_section(section, arg, node->field); ++ if (value == NULL) ++ continue; ++ field = mountopts_alias(node->field, &argtype); ++ if (strcasecmp(value, "false") == 0) { ++ if (argtype != MNT_NOARG) ++ snprintf(buf, BUFSIZ, "no%s", field); ++ } else if (strcasecmp(value, "true") == 0) { ++ snprintf(buf, BUFSIZ, "%s", field); ++ } else { ++ nvalue = strdup(value); ++ ptr = mountopts_convert(nvalue); ++ snprintf(buf, BUFSIZ, "%s=%s", field, ptr); ++ free(nvalue); ++ } ++ if (buf[0] == '\0') ++ continue; ++ /* ++ * Keep a running tally of the list size adding ++ * one for the ',' that will be appened later ++ */ ++ list_size += strlen(buf) + 1; ++ add_entry(buf); ++ } ++ conf_free_list(list); ++} ++ ++/* ++ * Concatenate options from the configuration file with the ++ * given options by building a link list of options from the ++ * different sections in the conf file. Options that exists ++ * in the either the given options or link list are not ++ * overwritten so it matter which when each section is ++ * parsed. ++ */ ++char *conf_get_mntopts(char *spec, char *mount_point, ++ char *mount_opts) ++{ ++ struct entry *entry; ++ char *ptr, *server, *config_opts; ++ int optlen = 0; ++ ++ SLIST_INIT(&head); ++ list_size = 0; ++ /* ++ * First see if there are any mount options relative ++ * to the mount point. ++ */ ++ conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, mount_opts); ++ ++ /* ++ * Next, see if there are any mount options relative ++ * to the server ++ */ ++ server = strdup(spec); ++ if (server == NULL) { ++ xlog_warn("conf_get_mountops: Unable calloc memory for server"); ++ free_all(); ++ return mount_opts; ++ } ++ if ((ptr = strchr(server, ':')) != NULL) ++ *ptr='\0'; ++ conf_parse_mntopts(NFSMOUNT_SERVER, server, mount_opts); ++ free(server); ++ ++ /* ++ * Finally process all the global mount options. ++ */ ++ conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts); ++ ++ /* ++ * If no mount options were found in the configuration file ++ * just return what was passed in . ++ */ ++ if (SLIST_EMPTY(&head)) ++ return mount_opts; ++ ++ /* ++ * Found options in the configuration file. So ++ * concatenate the configuration options with the ++ * options that were passed in ++ */ ++ if (mount_opts) ++ optlen = strlen(mount_opts); ++ ++ /* list_size + optlen + ',' + '\0' */ ++ config_opts = calloc(1, (list_size+optlen+2)); ++ if (server == NULL) { ++ xlog_warn("conf_get_mountops: Unable calloc memory for config_opts"); ++ free_all(); ++ return mount_opts; ++ } ++ if (mount_opts) { ++ strcpy(config_opts, mount_opts); ++ strcat(config_opts, ","); ++ } ++ SLIST_FOREACH(entry, &head, entries) { ++ strcat(config_opts, entry->opt); ++ strcat(config_opts, ","); ++ } ++ *(strrchr(config_opts, ',')) = '\0'; ++ ++ free_all(); ++ if (mount_opts) ++ free(mount_opts); ++ ++ return config_opts; ++} +diff --git a/utils/mount/mount.c b/utils/mount/mount.c +index a668cd9..355df79 100644 +--- a/utils/mount/mount.c ++++ b/utils/mount/mount.c +@@ -37,6 +37,7 @@ + #include "xcommon.h" + #include "nls.h" + #include "mount_constants.h" ++#include "mount_config.h" + #include "nfs_paths.h" + #include "nfs_mntent.h" + +@@ -474,6 +475,8 @@ int main(int argc, char *argv[]) + spec = argv[1]; + mount_point = argv[2]; + ++ mount_config_init(progname); ++ + argv[2] = argv[0]; /* so that getopt error messages are correct */ + while ((c = getopt_long(argc - 2, argv + 2, "rvVwfno:hs", + longopts, NULL)) != -1) { +@@ -559,6 +562,10 @@ int main(int argc, char *argv[]) + mnt_err = EX_USAGE; + goto out; + } ++ /* ++ * Concatenate mount options from the configuration file ++ */ ++ mount_opts = mount_config_opts(spec, mount_point, mount_opts); + + parse_opts(mount_opts, &flags, &extra_opts); + +diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h +new file mode 100644 +index 0000000..9a885a9 +--- /dev/null ++++ b/utils/mount/mount_config.h +@@ -0,0 +1,48 @@ ++#ifndef _LINUX_MOUNT__CONFIG_H ++#define _LINUX_MOUNT_CONFIG__H ++/* ++ * mount_config.h -- mount configuration file routines ++ * Copyright (C) 2008 Red Hat, Inc ++ * ++ * 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; either version 2, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++inline void mount_config_init(char *); ++ ++#ifdef MOUNT_CONFIG ++#include "conffile.h" ++extern char *conf_get_mntopts(char *, char *, char *); ++ ++inline void mount_config_init(char *program) ++{ ++ xlog_open(program); ++ /* ++ * Read the the default mount options ++ */ ++ conf_init(); ++} ++inline char *mount_config_opts(char *spec, ++ char *mount_point, char *mount_opts) ++{ ++ return conf_get_mntopts(spec, mount_point, mount_opts); ++} ++#else /* MOUNT_CONFIG */ ++ ++inline void mount_config_init(char *program) { } ++ ++inline char *mount_config_opts(char *spec, ++ char *mount_point, char *mount_opts) ++{ ++ return mount_opts; ++} ++#endif /* MOUNT_CONFIG */ ++#endif +diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man +index 13de524..2299637 100644 +--- a/utils/mount/nfs.man ++++ b/utils/mount/nfs.man +@@ -28,7 +28,7 @@ The + file describes how + .BR mount (8) + should assemble a system's file name hierarchy +-from various independent file systems ++from various independent file systems + (including file systems exported by NFS servers). + Each line in the + .I /etc/fstab +@@ -56,7 +56,7 @@ by NFS, thus conventionally each contain the digit zero. For example: + .P + The server's hostname and export pathname + are separated by a colon, while +-the mount options are separated by commas. The remaining fields ++the mount options are separated by commas. The remaining fields + are separated by blanks or tabs. + The server's hostname can be an unqualified hostname, + a fully qualified domain name, +@@ -70,17 +70,16 @@ The + and + .B nfs4 + file system types share similar mount options, +-which are described below. ++which are described below. + .SH "MOUNT OPTIONS" +-Refer to ++Refer to + .BR mount (8) + for a description of generic mount options +-available for all file systems. If you do not need to +-specify any mount options, use the generic option ++available for all file systems. If you do not need to ++specify any mount options, use the generic option + .B defaults + in + .IR /etc/fstab . +-. + .DT + .SS "Valid options for either the nfs or nfs4 file system type" + These options are valid to use when mounting either +@@ -100,7 +99,7 @@ option is specified), NFS requests are retried indefinitely. + If the + .B soft + option is specified, then the NFS client fails an NFS request +-after ++after + .B retrans + retransmissions have been sent, + causing the NFS client to return an error +@@ -119,8 +118,8 @@ option may mitigate some of the risks of using the + option. + .TP 1.5i + .BI timeo= n +-The time (in tenths of a second) the NFS client waits for a +-response before it retries an NFS request. If this ++The time (in tenths of a second) the NFS client waits for a ++response before it retries an NFS request. If this + option is not specified, requests are retried every + 60 seconds for NFS over TCP. + The NFS client does not perform any kind of timeout backoff +@@ -128,7 +127,7 @@ for NFS over TCP. + .IP + However, for NFS over UDP, the client uses an adaptive + algorithm to estimate an appropriate timeout value for frequently used +-request types (such as READ and WRITE requests), but uses the ++request types (such as READ and WRITE requests), but uses the + .B timeo + setting for infrequently used request types (such as FSINFO requests). + If the +@@ -141,13 +140,13 @@ up to a maximum timeout length of 60 seconds. + .TP 1.5i + .BI retrans= n + The number of times the NFS client retries a request before +-it attempts further recovery action. If the ++it attempts further recovery action. If the + .B retrans +-option is not specified, the NFS client tries each request ++option is not specified, the NFS client tries each request + three times. + .IP + The NFS client generates a "server not responding" message +-after ++after + .B retrans + retries, then attempts further recovery (depending on whether the + .B hard +@@ -166,21 +165,21 @@ is 1,048,576 bytes (one megabyte). + The + .B rsize + value is a positive integral multiple of 1024. +-Specified ++Specified + .B rsize + values lower than 1024 are replaced with 4096; values larger than + 1048576 are replaced with 1048576. If a specified value is within the supported +-range but not a multiple of 1024, it is rounded down to the nearest ++range but not a multiple of 1024, it is rounded down to the nearest + multiple of 1024. + .IP + If an + .B rsize +-value is not specified, or if the specified +-.B rsize ++value is not specified, or if the specified ++.B rsize + value is larger than the maximum that either client or server can support, + the client and server negotiate the largest + .B rsize +-value that they can both support. ++value that they can both support. + .IP + The + .B rsize +@@ -197,7 +196,7 @@ file. + .BI wsize= n + The maximum number of bytes per network WRITE request + that the NFS client can send when writing data to a file +-on an NFS server. The actual data payload size of each ++on an NFS server. The actual data payload size of each + NFS WRITE request is equal to + or smaller than the + .B wsize +@@ -207,19 +206,19 @@ is 1,048,576 bytes (one megabyte). + Similar to + .B rsize + , the +-.B wsize ++.B wsize + value is a positive integral multiple of 1024. +-Specified ++Specified + .B wsize + values lower than 1024 are replaced with 4096; values larger than + 1048576 are replaced with 1048576. If a specified value is within the supported +-range but not a multiple of 1024, it is rounded down to the nearest ++range but not a multiple of 1024, it is rounded down to the nearest + multiple of 1024. + .IP + If a + .B wsize +-value is not specified, or if the specified +-.B wsize ++value is not specified, or if the specified ++.B wsize + value is larger than the maximum that either client or server can support, + the client and server negotiate the largest + .B wsize +@@ -235,31 +234,31 @@ file. However, the effective + .B wsize + value negotiated by the client and server is reported in the + .I /proc/mounts +-file. ++file. + .TP 1.5i + .BR ac " / " noac +-Selects whether the client may cache file attributes. If neither +-option is specified (or if ++Selects whether the client may cache file attributes. If neither ++option is specified (or if + .B ac +-is specified), the client caches file +-attributes. ++is specified), the client caches file ++attributes. + .IP +-To improve performance, NFS clients cache file +-attributes. Every few seconds, an NFS client checks the server's version of each +-file's attributes for updates. Changes that occur on the server in +-those small intervals remain undetected until the client checks the +-server again. The ++To improve performance, NFS clients cache file ++attributes. Every few seconds, an NFS client checks the server's version of each ++file's attributes for updates. Changes that occur on the server in ++those small intervals remain undetected until the client checks the ++server again. The + .B noac +-option prevents clients from caching file +-attributes so that applications can more quickly detect file changes ++option prevents clients from caching file ++attributes so that applications can more quickly detect file changes + on the server. + .IP +-In addition to preventing the client from caching file attributes, +-the ++In addition to preventing the client from caching file attributes, ++the + .B noac +-option forces application writes to become synchronous so +-that local changes to a file become visible on the server +-immediately. That way, other clients can quickly detect recent ++option forces application writes to become synchronous so ++that local changes to a file become visible on the server ++immediately. That way, other clients can quickly detect recent + writes when they check the file's attributes. + .IP + Using the +@@ -383,20 +382,20 @@ Refer to the SECURITY CONSIDERATIONS section for details. + .TP 1.5i + .BR sharecache " / " nosharecache + Determines how the client's data cache and attribute cache are shared +-when mounting the same export more than once concurrently. Using the +-same cache reduces memory requirements on the client and presents +-identical file contents to applications when the same remote file is ++when mounting the same export more than once concurrently. Using the ++same cache reduces memory requirements on the client and presents ++identical file contents to applications when the same remote file is + accessed via different mount points. + .IP +-If neither option is specified, or if the ++If neither option is specified, or if the + .B sharecache +-option is +-specified, then a single cache is used for all mount points that +-access the same export. If the ++option is ++specified, then a single cache is used for all mount points that ++access the same export. If the + .B nosharecache +-option is specified, +-then that mount point gets a unique cache. Note that when data and +-attribute caches are shared, the mount options from the first mount ++option is specified, ++then that mount point gets a unique cache. Note that when data and ++attribute caches are shared, the mount options from the first mount + point take effect for subsequent concurrent mounts of the same export. + .IP + As of kernel 2.6.18, the behavior specified by +@@ -422,6 +421,49 @@ NFS mount points allowed on a client, but NFS servers must be configured + to allow clients to connect via non-privileged source ports. + .IP + Refer to the SECURITY CONSIDERATIONS section for important details. ++.TP 1.5i ++.BI lookupcache= mode ++Specifies how the kernel manages its cache of directory entries ++for a given mount point. ++.I mode ++can be one of ++.BR all , ++.BR none , ++.BR pos , ++or ++.BR positive . ++This option is supported in kernels 2.6.28 and later. ++.IP ++The Linux NFS client caches the result of all NFS LOOKUP requests. ++If the requested directory entry exists on the server, ++the result is referred to as ++.IR positive . ++If the requested directory entry does not exist on the server, ++the result is referred to as ++.IR negative . ++.IP ++If this option is not specified, or if ++.B all ++is specified, the client assumes both types of directory cache entries ++are valid until their parent directory's cached attributes expire. ++.IP ++If ++.BR pos " or " positive ++is specified, the client assumes positive entries are valid ++until their parent directory's cached attributes expire, but ++always revalidates negative entires before an application ++can use them. ++.IP ++If ++.B none ++is specified, ++the client revalidates both types of directory cache entries ++before an application can use them. ++This permits quick detection of files that were created or removed ++by other clients, but can impact application and server performance. ++.IP ++The DATA AND METADATA COHERENCE section contains a ++detailed discussion of these trade-offs. + .SS "Valid options for the nfs file system type" + Use these options, along with the options in the above subsection, + for mounting the +@@ -446,9 +488,9 @@ In addition to controlling how the NFS client transmits requests to + the server, this mount option also controls how the + .BR mount (8) + command communicates with the server's rpcbind and mountd services. +-Specifying ++Specifying + .B proto=tcp +-forces all traffic from the ++forces all traffic from the + .BR mount (8) + command and the NFS client to use TCP. + Specifying +@@ -574,9 +616,9 @@ It is included for compatibility with other operating systems. + .TP 1.5i + .BR lock " / " nolock + Selects whether to use the NLM sideband protocol to lock files on the server. +-If neither option is specified (or if +-.B lock +-is specified), NLM locking is used for this mount point. ++If neither option is specified (or if ++.B lock ++is specified), NLM locking is used for this mount point. + When using the + .B nolock + option, applications can lock files, +@@ -598,13 +640,13 @@ that do not support the NLM protocol. + .TP 1.5i + .BR intr " / " nointr + Selects whether to allow signals to interrupt file operations +-on this mount point. If neither option +-is specified (or if ++on this mount point. If neither option ++is specified (or if + .B nointr + is specified), + signals do not interrupt NFS file operations. If +-.B intr +-is specified, system calls return EINTR if an in-progress NFS operation is interrupted by ++.B intr ++is specified, system calls return EINTR if an in-progress NFS operation is interrupted by + a signal. + .IP + Using the +@@ -622,13 +664,13 @@ compatibility with older kernels. + .TP 1.5i + .BR cto " / " nocto + Selects whether to use close-to-open cache coherence semantics. +-If neither option is specified (or if ++If neither option is specified (or if + .B cto + is specified), the client uses close-to-open +-cache coherence semantics. If the +-.B nocto ++cache coherence semantics. If the ++.B nocto + option is specified, the client uses a non-standard heuristic to determine when +-files on the server have changed. ++files on the server have changed. + .IP + Using the + .B nocto +@@ -640,13 +682,13 @@ of this option in more detail. + .BR acl " / " noacl + Selects whether to use the NFSACL sideband protocol on this mount point. + The NFSACL sideband protocol is a proprietary protocol +-implemented in Solaris that manages Access Control Lists. NFSACL was never ++implemented in Solaris that manages Access Control Lists. NFSACL was never + made a standard part of the NFS protocol specification. + .IP +-If neither ++If neither + .B acl +-nor +-.B noacl ++nor ++.B noacl + option is specified, + the NFS client negotiates with the server + to see if the NFSACL protocol is supported, +@@ -660,7 +702,7 @@ Selects whether to use NFS version 3 READDIRPLUS requests. + If this option is not specified, the NFS client uses READDIRPLUS requests + on NFS version 3 mounts to read small directories. + Some applications perform better if the client uses only READDIR requests +-for all directories. ++for all directories. + .SS "Valid options for the nfs4 file system type" + Use these options, along with the options in the first subsection above, + for mounting the +@@ -676,8 +718,8 @@ can be either + or + .BR tcp . + All NFS version 4 servers are required to support TCP, +-so if this mount option is not specified, the NFS version 4 client +-uses the TCP transport protocol. ++so if this mount option is not specified, the NFS version 4 client ++uses the TCP transport protocol. + Refer to the TRANSPORT METHODS section for more details. + .TP 1.5i + .BI port= n +@@ -700,12 +742,12 @@ or the server's NFS service is not available on the advertised port. + .TP 1.5i + .BR intr " / " nointr + Selects whether to allow signals to interrupt file operations +-on this mount point. If neither option is specified (or if +-.B intr +-is specified), system calls return EINTR if an in-progress NFS operation +-is interrupted by a signal. If ++on this mount point. If neither option is specified (or if ++.B intr ++is specified), system calls return EINTR if an in-progress NFS operation ++is interrupted by a signal. If + .B nointr +-is specified, signals do not ++is specified, signals do not + interrupt NFS operations. + .IP + Using the +@@ -727,7 +769,7 @@ for NFS directories on this mount point. + If neither + .B cto + nor +-.B nocto ++.B nocto + is specified, + the default is to use close-to-open cache coherence + semantics for directories. +@@ -737,11 +779,11 @@ The DATA AND METADATA COHERENCE section discusses + the behavior of this option in more detail. + .TP 1.5i + .BI clientaddr= n.n.n.n +-Specifies a single IPv4 address (in dotted-quad form) +-that the NFS client advertises to allow servers +-to perform NFS version 4 callback requests against +-files on this mount point. If the server is unable to +-establish callback connections to clients, performance ++Specifies a single IPv4 address (in dotted-quad form) ++that the NFS client advertises to allow servers ++to perform NFS version 4 callback requests against ++files on this mount point. If the server is unable to ++establish callback connections to clients, performance + may degrade, or accesses to files may temporarily hang. + .IP + If this option is not specified, the +@@ -751,7 +793,14 @@ The automatic discovery process is not perfect, however. + In the presence of multiple client network interfaces, + special routing policies, + or atypical network topologies, +-the exact address to use for callbacks may be nontrivial to determine. ++the exact address to use for callbacks may be nontrivial to determine. ++.SH MOUNT CONFIGURATION FILE ++If the mount command is configured to do so, all of the mount options ++described in the previous section can also be configured in the ++.I /etc/nfsmount.conf ++file. See ++.BR nfsmount.conf(5) ++for details. + .SH EXAMPLES + To mount an export using NFS version 2, + use the +@@ -824,33 +873,33 @@ and data transfer size settings for a mount point. + In some cases, however, it pays to specify + these settings explicitly using mount options. + .P +-Traditionally, NFS clients used the UDP transport exclusively for +-transmitting requests to servers. Though its implementation is +-simple, NFS over UDP has many limitations that prevent smooth +-operation and good performance in some common deployment +-environments. Even an insignificant packet loss rate results in the +-loss of whole NFS requests; as such, retransmit timeouts are usually +-in the subsecond range to allow clients to recover quickly from +-dropped requests, but this can result in extraneous network traffic ++Traditionally, NFS clients used the UDP transport exclusively for ++transmitting requests to servers. Though its implementation is ++simple, NFS over UDP has many limitations that prevent smooth ++operation and good performance in some common deployment ++environments. Even an insignificant packet loss rate results in the ++loss of whole NFS requests; as such, retransmit timeouts are usually ++in the subsecond range to allow clients to recover quickly from ++dropped requests, but this can result in extraneous network traffic + and server load. + .P +-However, UDP can be quite effective in specialized settings where +-the network’s MTU is large relative to NFS’s data transfer size (such +-as network environments that enable jumbo Ethernet frames). In such +-environments, trimming the +-.B rsize +-and +-.B wsize +-settings so that each +-NFS read or write request fits in just a few network frames (or even +-in a single frame) is advised. This reduces the probability that +-the loss of a single MTU-sized network frame results in the loss of ++However, UDP can be quite effective in specialized settings where ++the networks MTU is large relative to NFSs data transfer size (such ++as network environments that enable jumbo Ethernet frames). In such ++environments, trimming the ++.B rsize ++and ++.B wsize ++settings so that each ++NFS read or write request fits in just a few network frames (or even ++in a single frame) is advised. This reduces the probability that ++the loss of a single MTU-sized network frame results in the loss of + an entire large read or write request. + .P +-TCP is the default transport protocol used for all modern NFS ++TCP is the default transport protocol used for all modern NFS + implementations. It performs well in almost every conceivable +-network environment and provides excellent guarantees against data +-corruption caused by network unreliability. TCP is often a ++network environment and provides excellent guarantees against data ++corruption caused by network unreliability. TCP is often a + requirement for mounting a server through a network firewall. + .P + Under normal circumstances, networks drop packets much more +@@ -861,11 +910,11 @@ After the client exhausts its retransmits (the value of the + .B retrans + mount option), it assumes a network partition has occurred, + and attempts to reconnect to the server on a fresh socket. Since +-TCP itself makes network data transfer reliable, ++TCP itself makes network data transfer reliable, + .B rsize +-and ++and + .B wsize +-can safely be allowed to default to the largest values supported by ++can safely be allowed to default to the largest values supported by + both client and server, independent of the network's MTU size. + .SS "Using the mountproto mount option" + This section applies only to NFS version 2 and version 3 mounts +@@ -950,8 +999,8 @@ Some modern cluster file systems provide + perfect cache coherence among their clients. + Perfect cache coherence among disparate NFS clients + is expensive to achieve, especially on wide area networks. +-As such, NFS settles for weaker cache coherence that +-satisfies the requirements of most file sharing types. Normally, ++As such, NFS settles for weaker cache coherence that ++satisfies the requirements of most file sharing types. Normally, + file sharing is completely sequential: + first client A opens a file, writes something to it, then closes it; + then client B opens the same file, and reads the changes. +@@ -985,7 +1034,7 @@ it is still difficult to tell whether it was + that client's updates or some other client's updates + that altered the file. + .SS "Attribute caching" +-Use the ++Use the + .B noac + mount option to achieve attribute cache coherence + among multiple clients. +@@ -1014,14 +1063,67 @@ The NFS protocol is not designed to support + true cluster file system cache coherence + without some type of application serialization. + If absolute cache coherence among clients is required, +-applications should use file locking. Alternatively, applications ++applications should use file locking. Alternatively, applications + can also open their files with the O_DIRECT flag + to disable data caching entirely. ++.SS "Directory entry caching" ++The Linux NFS client caches the result of all NFS LOOKUP requests. ++If the requested directory entry exists on the server, ++the result is referred to as a ++.IR positive " lookup result. ++If the requested directory entry does not exist on the server ++(that is, the server returned ENOENT), ++the result is referred to as ++.IR negative " lookup result. ++.P ++To detect when directory entries have been added or removed ++on the server, ++the Linux NFS client watches a directory's mtime. ++If the client detects a change in a directory's mtime, ++the client drops all cached LOOKUP results for that directory. ++Since the directory's mtime is a cached attribute, it may ++take some time before a client notices it has changed. ++See the descriptions of the ++.BR acdirmin ", " acdirmax ", and " noac ++mount options for more information about ++how long a directory's mtime is cached. ++.P ++Caching directory entries improves the performance of applications that ++do not share files with applications on other clients. ++Using cached information about directories can interfere ++with applications that run concurrently on multiple clients and ++need to detect the creation or removal of files quickly, however. ++The ++.B lookupcache ++mount option allows some tuning of directory entry caching behavior. ++.P ++Before kernel release 2.6.28, ++the Linux NFS client tracked only positive lookup results. ++This permitted applications to detect new directory entries ++created by other clients quickly while still providing some of the ++performance benefits of caching. ++If an application depends on the previous lookup caching behavior ++of the Linux NFS client, you can use ++.BR lookupcache=positive . ++.P ++If the client ignores its cache and validates every application ++lookup request with the server, ++that client can immediately detect when a new directory ++entry has been either created or removed by another client. ++You can specify this behavior using ++.BR lookupcache=none . ++The extra NFS requests needed if the client does not ++cache directory entries can exact a performance penalty. ++Disabling lookup caching ++should result in less of a performance penalty than using ++.BR noac , ++and has no effect on how the NFS client caches the attributes of files. ++.P + .SS "The sync mount option" + The NFS client treats the + .B sync + mount option differently than some other file systems +-(refer to ++(refer to + .BR mount (8) + for a description of the generic + .B sync +@@ -1032,16 +1134,16 @@ If neither + .B sync + nor + .B async +-is specified (or if the +-.B async ++is specified (or if the ++.B async + option is specified), + the NFS client delays sending application + writes to the server +-until any of these events occur: ++until any of these events occur: + .IP + Memory pressure forces reclamation of system memory resources. + .IP +-An application flushes file data explicitly with ++An application flushes file data explicitly with + .BR sync (2), + .BR msync (2), + or +@@ -1069,7 +1171,7 @@ but at a significant performance cost. + Applications can use the O_SYNC open flag to force application + writes to individual files to go to the server immediately without + the use of the +-.B sync ++.B sync + mount option. + .SS "Using file locks with NFS" + The Network Lock Manager protocol is a separate sideband protocol +@@ -1104,15 +1206,15 @@ mount option. NLM locking must be disabled with the + .B nolock + option when using NFS to mount + .I /var +-because +-.I /var ++because ++.I /var + contains files used by the NLM implementation on Linux. + .P + Specifying the + .B nolock + option may also be advised to improve the performance + of a proprietary application which runs on a single client +-and uses file locks extensively. ++and uses file locks extensively. + .SS "NFS version 4 caching features" + The data and metadata caching behavior of NFS version 4 + clients is similar to that of earlier versions. +@@ -1196,7 +1298,7 @@ authentication, and in-transit data protection. + The NFS version 4 specification mandates NFSv4 ACLs, + RPCGSS authentication, and RPCGSS security flavors + that provide per-RPC integrity checking and encryption. +-Because NFS version 4 combines the ++Because NFS version 4 combines the + function of the sideband protocols into the main NFS protocol, + the new security features apply to all NFS version 4 operations + including mounting, file locking, and so on. +@@ -1210,11 +1312,11 @@ that is in effect on a given NFS mount point. + Specifying + .B sec=krb5 + provides cryptographic proof of a user's identity in each RPC request. +-This provides strong verification of the identity of users ++This provides strong verification of the identity of users + accessing data on the server. + Note that additional configuration besides adding this mount option + is required in order to enable Kerberos security. +-Refer to the ++Refer to the + .BR rpc.gssd (8) + man page for details. + .P +@@ -1299,15 +1401,15 @@ filter rules. + It is still possible to mount an NFS server through a firewall, + though some of the + .BR mount (8) +-command's automatic service endpoint discovery mechanisms may not work; this ++command's automatic service endpoint discovery mechanisms may not work; this + requires you to provide specific endpoint details via NFS mount options. + .P + NFS servers normally run a portmapper or rpcbind daemon to advertise +-their service endpoints to clients. Clients use the rpcbind daemon to determine: ++their service endpoints to clients. Clients use the rpcbind daemon to determine: + .IP + What network port each RPC-based service is using + .IP +-What transport protocols each RPC-based service supports ++What transport protocols each RPC-based service supports + .P + The rpcbind daemon uses a well-known port number (111) to help clients find a service endpoint. + Although NFS often uses a standard port number (2049), +@@ -1339,9 +1441,9 @@ of the NFS version 3 specification, however. + .P + The NFS version 4 specification mandates a new version + of Access Control Lists that are semantically richer than POSIX ACLs. +-NFS version 4 ACLs are not fully compatible with POSIX ACLs; as such, ++NFS version 4 ACLs are not fully compatible with POSIX ACLs; as such, + some translation between the two is required +-in an environment that mixes POSIX ACLs and NFS version 4. ++in an environment that mixes POSIX ACLs and NFS version 4. + .SH FILES + .TP 1.5i + .I /etc/fstab +@@ -1418,4 +1520,4 @@ RFC 1833 for the RPC bind specification. + .br + RFC 2203 for the RPCSEC GSS API protocol specification. + .br +-RFC 3530 for the NFS version 4 specification. ++RFC 3530 for the NFS version 4 specification. +diff --git a/utils/mount/nfsmount.conf b/utils/mount/nfsmount.conf +new file mode 100644 +index 0000000..f9fcfcb +--- /dev/null ++++ b/utils/mount/nfsmount.conf +@@ -0,0 +1,120 @@ ++# ++# /etc/nfsmount.conf - see nfsmount.conf(5) for details ++# ++# This is an NFS mount configuration file. This file can be broken ++# up into three different sections: Mount, Server and Global ++# ++# [ MountPoint "Mount_point" ] ++# This section defines all the mount options that ++# should be used on a particular mount point. The '' ++# string need to be an exact match of the path in the mount ++# command. Example: ++# [ MountPoint "/export/home" ] ++# background=True ++# Would cause all mount to /export/home would be done in ++# the background ++# ++# [ Server "Server_Name" ] ++# This section defines all the mount options that ++# should be used on mounts to a particular NFS server. ++# Example: ++# [ Server "nfsserver.foo.com" ] ++# rsize=32k ++# wsize=32k ++# All reads and writes to the 'nfsserver.foo.com' server ++# will be done with 32k (32768 bytes) block sizes. ++# ++#[ NFSMount_Global_Options ] ++# This statically named section defines global mount ++# options that can be applied on all NFS mount. ++# ++# Protocol Version [2,3] ++# Nfsvers=3 ++# Network Transport [Udp,Tcp,Rdma] ++# Proto=Tcp ++# ++# The number of times a request will be retired before ++# generating a timeout ++# Retrans=2 ++# ++# The number of minutes that will retry mount ++# Retry=2 ++# ++# The minimum time (in seconds) file attributes are cached ++# acregmin=30 ++# ++# The Maximum time (in seconds) file attributes are cached ++# acregmin=60 ++# ++# The minimum time (in seconds) directory attributes are cached ++# acregmin=30 ++# ++# The Maximum time (in seconds) directory attributes are cached ++# acregmin=60 ++# ++# Enable Access Control Lists ++# Acl=False ++# ++# Enable Attribute Caching ++# Ac=True ++# ++# Do mounts in background (i.e. asynchronously) ++# Background=False ++# ++# Close-To-Open cache coherence ++# Cto=True ++# ++# Do mounts in foreground (i.e. synchronously) ++# Foreground=True ++# ++# How to handle times out from servers (Hard is STRONGLY suggested) ++# Hard=True ++# Soft=False ++# ++# Enable File Locking ++# Lock=True ++# ++# Enable READDIRPLUS on NFS version 3 mounts ++# Rdirplus=True ++# ++# Maximum Read Size (in Bytes) ++# Rsize=8k ++# ++# Maximum Write Size (in Bytes) ++# Wsize=8k ++# ++# Maximum Server Block Size (in Bytes) ++# Bsize=8k ++# ++# Ignore unknown mount options ++# Sloppy=False ++# ++# Share Data and Attribute Caches ++# Sharecache=True ++# ++# The amount of time, in tenths of a seconds, the client ++# will wait for a response from the server before retransmitting ++# the request. ++# Timeo=600 ++# ++# Sets all attributes times to the same time (in seconds) ++# actimeo=30 ++# ++# Server Mountd port mountport ++# mountport=4001 ++# ++# Server Mountd Protocol ++# mountproto=tcp ++# ++# Server Mountd Version ++# mounvers=3 ++# ++# Server Mountd Host ++# mounthost=hostname ++# ++# Server Port ++# Port=2049 ++# ++# RPCGSS security flavors ++# [none, sys, krb5, krb5i, krb5p ] ++# Sec=sys +diff --git a/utils/mount/nfsmount.conf.man b/utils/mount/nfsmount.conf.man +new file mode 100644 +index 0000000..12a3fe7 +--- /dev/null ++++ b/utils/mount/nfsmount.conf.man +@@ -0,0 +1,87 @@ ++.\"@(#)nfsmount.conf.5" ++.TH NFSMOUNT.CONF 5 "9 Mar 2008" ++.SH NAME ++nfsmount.conf - Configuration file for NFS mounts ++.SH SYNOPSIS ++Configuration file for NFS mounts that allows options ++to be set globally, per server or per mount point. ++.SH DESCRIPTION ++The configuration file is made up of multiple sections ++followed by variables associated with that section. ++A section is defined by a string enclosed by ++.BR [ ++and ++.BR ] ++branches. ++Variables are assignment statements that assign values ++to particular variables using the ++.BR = ++operator, as in ++.BR Proto=Tcp . ++Sections are broken up into three basic categories: ++Global options, Server options and Mount Point options. ++.HP ++.B [ NFSMount_Global_Options ] ++- This statically named section ++defines all of the global mount options that can be ++applied to every NFS mount. ++.HP ++.B [ Server \(lqServer_Name\(rq ] ++- This section defines all the mount options that should ++be used on mounts to a particular NFS server. The ++.I \(lqServer_Name\(rq ++strings needs to be surrounded by '\(lq' and ++be an exact match of the server name used in the ++.B mount ++command. ++.HP ++.B [ MountPoint \(lqMount_Point\(rq ] ++- This section defines all the mount options that ++should be used on a particular mount point. ++The ++.I \(lqMount_Point\(rq ++string needs to be surrounded by '\(lq' and be an ++exact match of the mount point used in the ++.BR mount ++command. ++.SH EXAMPLES ++.PP ++These are some example lines of how sections and variables ++are defined in the configuration file. ++.PP ++[ NFSMount_Global_Options ] ++.br ++ Proto=Tcp ++.RS ++.HP ++The TCP protocol will be used on every NFS mount. ++.HP ++.RE ++[ Server \(lqnfsserver.foo.com\(rq ] ++.br ++ rsize=32k ++.br ++ wsize=32k ++.HP ++.RS ++A 33k (32768 bytes) block size will be used as the read and write ++size on all mounts to the 'nfsserver.foo.com' server. ++.HP ++.RE ++.BR ++[ MountPoint \(lq/export/home\(rq ] ++.br ++ Background=True ++.RS ++.HP ++All mounts to the '/export/home' export will be performed in ++the background (i.e. done asynchronously). ++.HP ++.SH FILES ++.TP 10n ++.I /etc/nfsmount.conf ++Default NFS mount configuration file ++.PD ++.SH SEE ALSO ++.BR nfs (5), ++.BR mount (8), +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index 9bbbfb3..e4e2f22 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -564,7 +564,7 @@ static void write_fsloc(FILE *f, struct exportent *ep, char *path) + release_replicas(servers); + } + +-static void write_secinfo(FILE *f, struct exportent *ep) ++static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask) + { + struct sec_entry *p; + +@@ -578,7 +578,7 @@ static void write_secinfo(FILE *f, struct exportent *ep) + qword_printint(f, p - ep->e_secinfo); + for (p = ep->e_secinfo; p->flav; p++) { + qword_printint(f, p->flav->fnum); +- qword_printint(f, p->flags); ++ qword_printint(f, p->flags & flag_mask); + } + + } +@@ -590,16 +590,14 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex + qword_printint(f, time(0)+30*60); + if (exp) { + int different_fs = strcmp(path, exp->e_path) != 0; +- +- if (different_fs) +- qword_printint(f, exp->e_flags & ~NFSEXP_FSID); +- else +- qword_printint(f, exp->e_flags); ++ int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; ++ ++ qword_printint(f, exp->e_flags & flag_mask); + qword_printint(f, exp->e_anonuid); + qword_printint(f, exp->e_anongid); + qword_printint(f, exp->e_fsid); + write_fsloc(f, exp, path); +- write_secinfo(f, exp); ++ write_secinfo(f, exp, flag_mask); + if (exp->e_uuid == NULL || different_fs) { + char u[16]; + if (get_uuid(path, NULL, 16, u)) { +diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c +index 7e9f327..fa46d5d 100644 +--- a/utils/nfsstat/nfsstat.c ++++ b/utils/nfsstat/nfsstat.c +@@ -30,8 +30,8 @@ static unsigned int cltproc2info[20], cltproc2info_old[20]; /* NFSv2 call counts + static unsigned int srvproc3info[24], srvproc3info_old[24]; /* NFSv3 call counts ([0] == 22) */ + static unsigned int cltproc3info[24], cltproc3info_old[24]; /* NFSv3 call counts ([0] == 22) */ + static unsigned int srvproc4info[4], srvproc4info_old[4]; /* NFSv4 call counts ([0] == 2) */ +-static unsigned int cltproc4info[37], cltproc4info_old[37]; /* NFSv4 call counts ([0] == 35) */ +-static unsigned int srvproc4opsinfo[42], srvproc4opsinfo_old[42]; /* NFSv4 call counts ([0] == 40) */ ++static unsigned int cltproc4info[49], cltproc4info_old[49]; /* NFSv4 call counts ([0] == 35) */ ++static unsigned int srvproc4opsinfo[61], srvproc4opsinfo_old[61]; /* NFSv4 call counts ([0] == 40) */ + static unsigned int srvnetinfo[5], srvnetinfo_old[5]; /* 0 # of received packets + * 1 UDP packets + * 2 TCP packets +@@ -93,24 +93,58 @@ static const char * nfssrvproc4name[2] = { + "compound", + }; + +-static const char * nfscltproc4name[35] = { ++static const char * nfscltproc4name[47] = { + "null", "read", "write", "commit", "open", "open_conf", + "open_noat", "open_dgrd", "close", "setattr", "fsinfo", "renew", + "setclntid", "confirm", "lock", + "lockt", "locku", "access", "getattr", "lookup", "lookup_root", + "remove", "rename", "link", "symlink", "create", "pathconf", + "statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl", +- "setacl", "fs_locations" ++ "setacl", "fs_locations", ++ /* nfsv4.1 client ops */ ++ "exchange_id", ++ "create_ses", ++ "destroy_ses", ++ "sequence", ++ "get_lease_t", ++ "layoutget", ++ "layoutcommit", ++ "layoutreturn", ++ "getdevlist", ++ "getdevinfo", ++ /* nfsv4.1 pnfs client ops to data server only */ ++ "ds_write", ++ "ds_commit", + }; + +-static const char * nfssrvproc4opname[40] = { ++static const char * nfssrvproc4opname[59] = { + "op0-unused", "op1-unused", "op2-future", "access", "close", "commit", + "create", "delegpurge", "delegreturn", "getattr", "getfh", "link", + "lock", "lockt", "locku", "lookup", "lookup_root", "nverify", + "open", "openattr", "open_conf", "open_dgrd", "putfh", "putpubfh", + "putrootfh", "read", "readdir", "readlink", "remove", "rename", + "renew", "restorefh", "savefh", "secinfo", "setattr", "setcltid", +- "setcltidconf", "verify", "write", "rellockowner" ++ "setcltidconf", "verify", "write", "rellockowner", ++ /* nfsv4.1 server ops */ ++ "bc_ctl", ++ "bind_conn", ++ "exchange_id", ++ "create_ses", ++ "destroy_ses", ++ "free_stateid", ++ "getdirdeleg", ++ "getdevinfo", ++ "getdevlist", ++ "layoutcommit", ++ "layoutget", ++ "layoutreturn", ++ "secinfononam", ++ "sequence", ++ "set_ssv", ++ "test_stateid", ++ "want_deleg", ++ "destroy_clid", ++ "reclaim_comp", + }; + + #define LABEL_srvnet "Server packet stats:\n" diff --git a/nfs-utils.spec b/nfs-utils.spec index f571341..8c0f31f 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.2.0 -Release: 9%{?dist} +Release: 10%{?dist} Epoch: 1 # group all 32bit related archs @@ -24,8 +24,10 @@ Patch02: nfs-utils-1.1.0-exp-subtree-warn-off.patch Patch100: nfs-utils-1.2.1-rc1.patch Patch101: nfs-utils-1.2.1-rc2.patch -Patch102: nfs-utils-1.2.0-proots-rel5.patch -Patch103: nfs-utils-1.2.1-rc3.patch +Patch102: nfs-utils-1.2.1-rc3.patch +Patch103: nfs-utils-1.2.1-rc4.patch + +Patch200: nfs-utils-1.2.0-proots-rel5.patch Group: System Environment/Daemons Provides: exportfs = %{epoch}:%{version}-%{release} @@ -82,6 +84,8 @@ This package also contains the mount.nfs and umount.nfs program. %patch102 -p1 %patch103 -p1 +%patch200 -p1 + # Remove .orig files find . -name "*.orig" | xargs rm -f @@ -101,7 +105,8 @@ CFLAGS="`echo $RPM_OPT_FLAGS $ARCH_OPT_FLAGS $PIE -D_FILE_OFFSET_BITS=64`" CFLAGS="$CFLAGS" \ CPPFLAGS="$DEFINES" \ LDFLAGS="-pie" \ - --enable-mount + --enable-mount \ + --enable-mountconfig make all @@ -118,6 +123,7 @@ install -m 755 %{SOURCE12} $RPM_BUILD_ROOT/etc/rc.d/init.d/rpcidmapd install -m 755 %{SOURCE13} $RPM_BUILD_ROOT/etc/rc.d/init.d/rpcgssd install -m 755 %{SOURCE14} $RPM_BUILD_ROOT/etc/rc.d/init.d/rpcsvcgssd install -m 644 %{SOURCE15} $RPM_BUILD_ROOT/etc/sysconfig/nfs +install -m 644 utils/mount/nfsmount.conf $RPM_BUILD_ROOT/etc mkdir -p $RPM_BUILD_ROOT/var/lib/nfs/rpc_pipefs @@ -215,6 +221,7 @@ fi %config /etc/rc.d/init.d/rpcgssd %config /etc/rc.d/init.d/rpcsvcgssd %config(noreplace) /etc/sysconfig/nfs +%config(noreplace) /etc/nfsmount.conf %dir /var/lib/nfs/v4recovery %dir /var/lib/nfs/rpc_pipefs %dir /var/lib/nfs @@ -249,6 +256,14 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Mon Aug 17 2009 Steve Dickson 1.2.0-10 +- Added upstream 1.2.1-rc4 patch + - Fix bug when both crossmnt + - nfs(5): Add description of lookupcache mount option + - nfs(5): Remove trailing blanks + - Added nfs41 support to nfssat + - Added support for mount to us a configuration file. + * Fri Aug 14 2009 Steve Dickson 1.2.0-9 - Added upstream 1.2.1-rc3 patch - Add IPv6 support to nfsd