All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch 0/10] NFS Mount Configuration File (Vers 3)
@ 2009-08-06 18:38 Steve Dickson
  2009-08-06 18:40 ` [Patch 1/10] " Steve Dickson
                   ` (8 more replies)
  0 siblings, 9 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:38 UTC (permalink / raw)
  To: Linux NFS Mailing list; +Cc: Linux NFSv4 mailing list

Hello,

Here is the latest version of these patches. In the version
the following changes were made:

   1) Section headers how have an argument to them. Similar
      to [Server "foobar" ] or [MountPoint "/export"]
   
   2) Only the Section names are now case-less. Its up to
      the caller of the parsing routines to deal with case
      sensitivity of the data.


Here are the pointers to the two previous versions which
will explain the who, what and whys:  

http://marc.info/?l=linux-nfs&m=123663164305546&w=2
http://marc.info/?l=linux-nfs&m=124931114811175&w=2


This entire patch set is available at:
    http://people.redhat.com/steved/mount-conf/ver03/

and on the 'mount_conf-ver03' branch on my experimental git tree:
    git://linux-nfs.org/~steved/nfs-utils-exp.git

Comments?

steved.

_______________________________________________
NFSv4 mailing list
NFSv4@linux-nfs.org
http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [Patch 1/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
@ 2009-08-06 18:40 ` Steve Dickson
  2009-08-07  8:06   ` Benny Halevy
       [not found] ` <4A7B2324.9090406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:40 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit 196abf012b67c3dd13cd805566dd1ebb58719b54
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 15:47:05 2009 -0400

    Move idmapd's configuration file parsing routines into
    the shared libnfs.a library, making them available to\
    other daemons and programs.
    =

    Signed-off-by: Steve Dickson <steved@redhat.com>

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 =3D \
 	xio.h \
 	xlog.h \
 	xmalloc.h \
-	xcommon.h
+	xcommon.h \
+	conffile.h
 =

 MAINTAINERCLEANFILES =3D Makefile.in
diff --git a/support/include/conffile.h b/support/include/conffile.h
new file mode 100644
index 0000000..3309788
--- /dev/null
+++ b/support/include/conffile.h
@@ -0,0 +1,67 @@
+/* $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=E5kan 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 WARRANTI=
ES
+ * 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 US=
E,
+ * 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 <sys/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				/* _CONFFILE_H_ */
diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am
index 86f52a1..63e1800 100644
--- a/support/nfs/Makefile.am
+++ b/support/nfs/Makefile.am
@@ -4,7 +4,7 @@ noinst_LIBRARIES =3D libnfs.a
 libnfs_a_SOURCES =3D exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \
 		   xlog.c xcommon.c wildmat.c nfssvc.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 =3D Makefile.in
 =

diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
new file mode 100644
index 0000000..c5f9fa7
--- /dev/null
+++ b/support/nfs/conffile.c
@@ -0,0 +1,850 @@
+/*	$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 rese=
rved.
+ * Copyright (c) 2000, 2001, 2002 H=E5kan 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 WARRANTI=
ES
+ * 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 US=
E,
+ * 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 <sys/param.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+#include <syslog.h>
+
+#include "conffile.h"
+#include "xlog.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.
+ */
+static const u_int8_t bin2asc[]
+  =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const u_int8_t asc2bin[] =3D
+{
+  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 =3D 0;
+
+	while (*s) {
+		hash =3D ((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 =3D LIST_FIRST(&conf_bindings[conf_hash (section)]);
+	for (; cb; cb =3D next) {
+		next =3D LIST_NEXT(cb, link);
+		if (strcasecmp(cb->section, section) =3D=3D 0
+				&& strcasecmp(cb->tag, tag) =3D=3D 0) {
+			LIST_REMOVE(cb, link);
+			xlog(LOG_INFO,"[%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 =3D 1;
+
+	cb =3D LIST_FIRST(&conf_bindings[conf_hash (section)]);
+	for (; cb; cb =3D next) {
+		next =3D LIST_NEXT(cb, link);
+		if (strcasecmp(cb->section, section) =3D=3D 0) {
+			unseen =3D 0;
+			LIST_REMOVE(cb, link);
+			xlog(LOG_INFO, "[%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 =3D 0;
+
+	if (override)
+		conf_remove_now(section, tag);
+	else if (conf_get_str(section, tag)) {
+		if (!is_default) {
+			xlog(LOG_INFO, "conf_set: duplicate tag [%s]:%s, ignoring...\n", =

+				section, tag);
+		}
+		return 1;
+	}
+
+	node =3D calloc(1, sizeof *node);
+	if (!node) {
+		xlog_warn("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *nod=
e);
+		return 1;
+	}
+	node->section =3D strdup(section);
+	node->tag =3D strdup(tag);
+	node->value =3D strdup(value);
+	node->is_default =3D 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 =3D 0;
+	static int ln =3D 0;
+
+	/* Lines starting with '#' or ';' are comments.  */
+	ln++;
+	if (*line =3D=3D '#' || *line =3D=3D ';')
+		return;
+
+	/* '[section]' parsing...  */
+	if (*line =3D=3D '[') {
+		for (i =3D 1; i < sz; i++)
+			if (line[i] =3D=3D ']')
+				break;
+		if (section)
+			free (section);
+		if (i =3D=3D sz) {
+			xlog_warn("conf_parse_line: %d:"
+ 				"non-matched ']', ignoring until next section", ln);
+			section =3D 0;
+			return;
+		}
+		section =3D malloc(i);
+		if (!section) {
+			xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln,
+						(unsigned long)i);
+			return;
+		}
+		strlcpy(section, line + 1, i);
+		return;
+	}
+
+	/* Deal with assignments.  */
+	for (i =3D 0; i < sz; i++) {
+		if (line[i] =3D=3D '=3D') {
+			/* If no section, we are ignoring the lines.  */
+			if (!section) {
+				xlog_warn("conf_parse_line: %d: ignoring line due to no section", =

+					ln);
+				return;
+			}
+			line[strcspn (line, " \t=3D")] =3D '\0';
+			val =3D line + i + 1 + strspn (line + i + 1, " \t");
+			/* Skip trailing whitespace, if any */
+			for (j =3D sz - (val - line) - 1; j > 0 && isspace(val[j]); j--)
+				val[j] =3D '\0';
+			/* XXX Perhaps should we not ignore errors?  */
+			conf_set(trans, section, line, val, 0, 0);
+			return;
+		}
+	}
+	/* Other non-empty lines are weird.  */
+	i =3D strspn(line, " \t");
+	if (line[i])
+		xlog_warn("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 =3D buf;
+	char *bufend =3D buf + sz;
+	char *line;
+
+	line =3D cp;
+	while (cp < bufend) {
+		if (*cp =3D=3D '\n') {
+			/* Check for escaped newlines.  */
+			if (cp > buf && *(cp - 1) =3D=3D '\\')
+				*(cp - 1) =3D *cp =3D ' ';
+			else {
+				*cp =3D '\0';
+				conf_parse_line(trans, line, cp - line);
+				line =3D cp + 1;
+			}
+		}
+		cp++;
+	}
+	if (cp !=3D 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 =3D 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 =3D 0;
+	int fd, trans;
+	unsigned int i;
+	size_t sz;
+	char *new_conf_addr =3D 0;
+	struct stat sb;
+
+	if ((stat (conf_path, &sb) =3D=3D 0) || (errno !=3D ENOENT)) {
+		sz =3D sb.st_size;
+		fd =3D open (conf_path, O_RDONLY, 0);
+		if (fd =3D=3D -1) {
+			xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path);
+			return;
+		}
+
+		new_conf_addr =3D 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) !=3D (int)sz) {
+			xlog_warn("conf_reinit: read (%d, %p, %lu) failed",
+   				fd, new_conf_addr, (unsigned long)sz);
+			goto fail;
+		}
+		close(fd);
+
+		trans =3D conf_begin();
+		/* XXX Should we not care about errors and rollback?  */
+		conf_parse(trans, new_conf_addr, sz);
+	}
+	else
+		trans =3D conf_begin();
+
+	/* Load default configuration values.  */
+	conf_load_defaults(trans);
+
+	/* Free potential existing configuration.  */
+	if (conf_addr) {
+		for (i =3D 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) {
+			cb =3D LIST_FIRST (&conf_bindings[i]);
+			for (; cb; cb =3D LIST_FIRST (&conf_bindings[i]))
+				conf_remove_now(cb->section, cb->tag);
+		}
+		free (conf_addr);
+	}
+
+	conf_end(trans, 1);
+	conf_addr =3D 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 =3D 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 =3D conf_get_str (section, tag);
+	int val, min, max, n;
+
+	if (!value)
+		return 0;
+	n =3D sscanf (value, "%d,%d:%d", &val, &min, &max);
+	switch (n) {
+	case 1:
+		xlog(LOG_INFO, "conf_match_num: %s:%s %d=3D=3D%d?", section, tag, val, x=
);
+		return x =3D=3D val;
+	case 3:
+		xlog(LOG_INFO, "conf_match_num: %s:%s %d<=3D%d<=3D%d?", section, =

+			tag, min, x, max);
+		return min <=3D x && max >=3D 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 =3D LIST_FIRST (&conf_bindings[conf_hash (section)]);
+	for (; cb; cb =3D LIST_NEXT (cb, link)) {
+		if (strcasecmp (section, cb->section) =3D=3D 0
+				&& strcasecmp (tag, cb->tag) =3D=3D 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 =3D 0, *p, *field, *t;
+	struct conf_list *list =3D 0;
+	struct conf_list_node *node;
+
+	list =3D malloc (sizeof *list);
+	if (!list)
+		goto cleanup;
+	TAILQ_INIT (&list->fields);
+	list->cnt =3D 0;
+	liststr =3D conf_get_str(section, tag);
+	if (!liststr)
+		goto cleanup;
+	liststr =3D strdup (liststr);
+	if (!liststr)
+		goto cleanup;
+	p =3D liststr;
+	while ((field =3D strsep (&p, ",")) !=3D NULL) {
+		/* Skip leading whitespace */
+		while (isspace (*field))
+			field++;
+		/* Skip trailing whitespace */
+		if (p) {
+			for (t =3D p - 1; t > field && isspace (*t); t--)
+				*t =3D '\0';
+		}
+		if (*field =3D=3D '\0') {
+			xlog(LOG_INFO, "conf_get_list: empty field, ignoring...");
+			continue;
+		}
+		list->cnt++;
+		node =3D calloc (1, sizeof *node);
+		if (!node)
+			goto cleanup;
+		node->field =3D 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 =3D 0;
+	struct conf_list_node *node;
+	struct conf_binding *cb;
+
+	list =3D malloc(sizeof *list);
+	if (!list)
+		goto cleanup;
+	TAILQ_INIT(&list->fields);
+	list->cnt =3D 0;
+	cb =3D LIST_FIRST(&conf_bindings[conf_hash (section)]);
+	for (; cb; cb =3D LIST_NEXT(cb, link)) {
+		if (strcasecmp (section, cb->section) =3D=3D 0) {
+			list->cnt++;
+			node =3D calloc(1, sizeof *node);
+			if (!node)
+				goto cleanup;
+			node->field =3D 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 =3D 0;
+	u_int8_t c1, c2, c3, c4;
+
+	while (*buf) {
+		if (*buf > 127 || (c1 =3D asc2bin[*buf]) =3D=3D 255)
+			return 0;
+
+		buf++;
+		if (*buf > 127 || (c2 =3D asc2bin[*buf]) =3D=3D 255)
+			return 0;
+
+		buf++;
+		if (*buf =3D=3D '=3D') {
+			c3 =3D c4 =3D 0;
+			c++;
+
+			/* Check last four bit */
+			if (c2 & 0xF)
+				return 0;
+
+			if (strcmp((char *)buf, "=3D=3D") =3D=3D 0)
+				buf++;
+			else
+				return 0;
+		} else if (*buf > 127 || (c3 =3D asc2bin[*buf]) =3D=3D 255)
+			return 0;
+		else {
+			if (*++buf =3D=3D '=3D') {
+				c4 =3D 0;
+				c +=3D 2;
+
+				/* Check last two bit */
+				if (c3 & 3)
+					return 0;
+
+			if (strcmp((char *)buf, "=3D"))
+				return 0;
+			} else if (*buf > 127 || (c4 =3D asc2bin[*buf]) =3D=3D 255)
+				return 0;
+			else
+				c +=3D 3;
+		}
+
+		buf++;
+		*out++ =3D (c1 << 2) | (c2 >> 4);
+		*out++ =3D (c2 << 4) | (c3 >> 2);
+		*out++ =3D (c3 << 6) | c4;
+	}
+
+	*len =3D c;
+	return 1;
+}
+
+void
+conf_free_list(struct conf_list *list)
+{
+	struct conf_list_node *node =3D TAILQ_FIRST(&list->fields);
+
+	while (node) {
+		TAILQ_REMOVE(&list->fields, node, link);
+		if (node->field)
+			free(node->field);
+		free (node);
+		node =3D TAILQ_FIRST(&list->fields);
+	}
+	free (list);
+}
+
+int
+conf_begin(void)
+{
+  static int seq =3D 0;
+
+  return ++seq;
+}
+
+static struct conf_trans *
+conf_trans_node(int transaction, enum conf_op op)
+{
+	struct conf_trans *node;
+
+	node =3D calloc (1, sizeof *node);
+	if (!node) {
+		xlog_warn("conf_trans_node: calloc (1, %lu) failed",
+		(unsigned long)sizeof *node);
+		return 0;
+	}
+	node->trans =3D transaction;
+	node->op =3D 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 =3D conf_trans_node(transaction, CONF_SET);
+	if (!node)
+		return 1;
+	node->section =3D strdup(section);
+	if (!node->section) {
+		xlog_warn("conf_set: strdup(\"%s\") failed", section);
+		goto fail;
+	}
+	node->tag =3D strdup(tag);
+	if (!node->tag) {
+		xlog_warn("conf_set: strdup(\"%s\") failed", tag);
+		goto fail;
+	}
+	node->value =3D strdup(value);
+	if (!node->value) {
+		xlog_warn("conf_set: strdup(\"%s\") failed", value);
+		goto fail;
+	}
+	node->override =3D override;
+	node->is_default =3D 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 =3D conf_trans_node(transaction, CONF_REMOVE);
+	if (!node)
+		goto fail;
+	node->section =3D strdup(section);
+	if (!node->section) {
+		xlog_warn("conf_remove: strdup(\"%s\") failed", section);
+		goto fail;
+	}
+	node->tag =3D 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 =3D conf_trans_node(transaction, CONF_REMOVE_SECTION);
+	if (!node)
+		goto fail;
+	node->section =3D 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 =3D TAILQ_FIRST(&conf_trans_queue); node; node =3D next) {
+		next =3D TAILQ_NEXT(node, link);
+		if (node->trans =3D=3D 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:
+					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=3D\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 =3D 0;
+	unsigned int i, len;
+	char *current_section =3D (char *)0;
+	struct dumper *dumper, *dnode;
+
+	dumper =3D dnode =3D (struct dumper *)calloc(1, sizeof *dumper);
+	if (!dumper)
+		goto mem_fail;
+
+	xlog(LOG_INFO, "conf_report: dumping running configuration");
+
+	for (i =3D 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
+		for (cb =3D LIST_FIRST(&conf_bindings[i]); cb; cb =3D LIST_NEXT(cb, link=
)) {
+			if (!cb->is_default) {
+				/* Dump this entry.  */
+				if (!current_section || strcmp(cb->section, current_section)) {
+					if (current_section) {
+						len =3D strlen (current_section) + 3;
+						dnode->s =3D malloc(len);
+						if (!dnode->s)
+							goto mem_fail;
+
+						snprintf(dnode->s, len, "[%s]", current_section);
+						dnode->next =3D =

+							(struct dumper *)calloc(1, sizeof (struct dumper));
+						dnode =3D dnode->next;
+						if (!dnode)
+							goto mem_fail;
+
+						dnode->s =3D "";
+						dnode->next =3D =

+							(struct dumper *)calloc(1, sizeof (struct dumper));
+						dnode =3D dnode->next;
+						if (!dnode)
+						goto mem_fail;
+					}
+					current_section =3D cb->section;
+				}
+				dnode->s =3D cb->tag;
+				dnode->v =3D cb->value;
+				dnode->next =3D (struct dumper *)calloc (1, sizeof (struct dumper));
+				dnode =3D dnode->next;
+				if (!dnode)
+					goto mem_fail;
+				last =3D cb;
+		}
+	}
+
+	if (last) {
+		len =3D strlen(last->section) + 3;
+		dnode->s =3D malloc(len);
+		if (!dnode->s)
+			goto mem_fail;
+		snprintf(dnode->s, len, "[%s]", last->section);
+	}
+	conf_report_dump(dumper);
+	return;
+
+mem_fail:
+	xlog_warn("conf_report: malloc/calloc failed");
+	while ((dnode =3D dumper) !=3D 0) {
+		dumper =3D 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 =3D \
 =

 idmapd_SOURCES =3D \
 	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 rese=
rved.
- * Copyright (c) 2000, 2001, 2002 H=E5kan 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 WARRANTI=
ES
- * 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 US=
E,
- * 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 <sys/param.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <err.h>
-
-#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[]
-  =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-const u_int8_t asc2bin[] =3D
-{
-  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 =3D 0;
-
-  while (*s)
-    {
-      hash =3D ((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 =3D LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb =3D=
 next)
-    {
-      next =3D LIST_NEXT (cb, link);
-      if (strcasecmp (cb->section, section) =3D=3D 0
-	  && strcasecmp (cb->tag, tag) =3D=3D 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 =3D 1;
-
-  for (cb =3D LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb =3D=
 next)
-    {
-      next =3D LIST_NEXT (cb, link);
-      if (strcasecmp (cb->section, section) =3D=3D 0)
-	{
-	  unseen =3D 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 =3D 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 =3D calloc (1, sizeof *node);
-  if (!node)
-    {
-      warnx("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *nod=
e);
-      return 1;
-    }
-  node->section =3D strdup (section);
-  node->tag =3D strdup (tag);
-  node->value =3D strdup (value);
-  node->is_default =3D 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 =3D 0;
-  static int ln =3D 0;
-
-  ln++;
-
-  /* Lines starting with '#' or ';' are comments.  */
-  if (*line =3D=3D '#' || *line =3D=3D ';')
-    return;
-
-  /* '[section]' parsing...  */
-  if (*line =3D=3D '[')
-    {
-      for (i =3D 1; i < sz; i++)
-	if (line[i] =3D=3D ']')
-	  break;
-      if (section)
-	free (section);
-      if (i =3D=3D sz)
-	{
-	  warnx("conf_parse_line: %d:"
-		     "non-matched ']', ignoring until next section", ln);
-	  section =3D 0;
-	  return;
-	}
-      section =3D 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 =3D 0; i < sz; i++)
-    if (line[i] =3D=3D '=3D')
-      {
-	/* 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=3D")] =3D '\0';
-	val =3D line + i + 1 + strspn (line + i + 1, " \t");
-	/* Skip trailing whitespace, if any */
-	for (j =3D sz - (val - line) - 1; j > 0 && isspace (val[j]); j--)
-	  val[j] =3D '\0';
-	/* XXX Perhaps should we not ignore errors?  */
-	conf_set (trans, section, line, val, 0, 0);
-	return;
-      }
-
-  /* Other non-empty lines are weird.  */
-  i =3D 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 =3D buf;
-  char *bufend =3D buf + sz;
-  char *line;
-
-  line =3D cp;
-  while (cp < bufend)
-    {
-      if (*cp =3D=3D '\n')
-	{
-	  /* Check for escaped newlines.  */
-	  if (cp > buf && *(cp - 1) =3D=3D '\\')
-	    *(cp - 1) =3D *cp =3D ' ';
-	  else
-	    {
-	      *cp =3D '\0';
-	      conf_parse_line (trans, line, cp - line);
-	      line =3D cp + 1;
-	    }
-	}
-      cp++;
-    }
-  if (cp !=3D 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 =3D 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 =3D 0;
-  int fd, trans;
-  unsigned int i;
-  size_t sz;
-  char *new_conf_addr =3D 0;
-  struct stat sb;
-
-  if ((stat (conf_path, &sb) =3D=3D 0) || (errno !=3D ENOENT))
-    {
-      sz =3D sb.st_size;
-      fd =3D open (conf_path, O_RDONLY, 0);
-      if (fd =3D=3D -1)
-        {
-	  warnx("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path);
-	  return;
-	}
-
-      new_conf_addr =3D 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) !=3D (int)sz)
-        {
-	    warnx("conf_reinit: read (%d, %p, %lu) failed",
-		       fd, new_conf_addr, (unsigned long)sz);
-	    goto fail;
-	}
-      close (fd);
-
-      trans =3D conf_begin ();
-
-      /* XXX Should we not care about errors and rollback?  */
-      conf_parse (trans, new_conf_addr, sz);
-    }
-  else
-    trans =3D conf_begin ();
-
-  /* Load default configuration values.  */
-  conf_load_defaults (trans);
-
-  /* Free potential existing configuration.  */
-  if (conf_addr)
-    {
-      for (i =3D 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i+=
+)
-	for (cb =3D LIST_FIRST (&conf_bindings[i]); cb;
-	     cb =3D LIST_FIRST (&conf_bindings[i]))
-	  conf_remove_now (cb->section, cb->tag);
-      free (conf_addr);
-    }
-
-  conf_end (trans, 1);
-  conf_addr =3D 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 =3D 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 =3D conf_get_str (section, tag);
-  int val, min, max, n;
-
-  if (!value)
-    return 0;
-  n =3D sscanf (value, "%d,%d:%d", &val, &min, &max);
-  switch (n)
-    {
-    case 1:
-      warnx("conf_match_num: %s:%s %d=3D=3D%d?", section, tag, val, x);
-      return x =3D=3D val;
-    case 3:
-      warnx("conf_match_num: %s:%s %d<=3D%d<=3D%d?", section, tag, min, x,=
 max);
-      return min <=3D x && max >=3D 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 =3D LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
-       cb =3D LIST_NEXT (cb, link))
-    if (strcasecmp (section, cb->section) =3D=3D 0
-	&& strcasecmp (tag, cb->tag) =3D=3D 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 =3D 0, *p, *field, *t;
-  struct conf_list *list =3D 0;
-  struct conf_list_node *node;
-
-  list =3D malloc (sizeof *list);
-  if (!list)
-    goto cleanup;
-  TAILQ_INIT (&list->fields);
-  list->cnt =3D 0;
-  liststr =3D conf_get_str (section, tag);
-  if (!liststr)
-    goto cleanup;
-  liststr =3D strdup (liststr);
-  if (!liststr)
-    goto cleanup;
-  p =3D liststr;
-  while ((field =3D strsep (&p, ",")) !=3D NULL)
-    {
-      /* Skip leading whitespace */
-      while (isspace (*field))
-	field++;
-      /* Skip trailing whitespace */
-      if (p)
-	for (t =3D p - 1; t > field && isspace (*t); t--)
-	  *t =3D '\0';
-      if (*field =3D=3D '\0')
-	{
-	  warnx("conf_get_list: empty field, ignoring...");
-	  continue;
-	}
-      list->cnt++;
-      node =3D calloc (1, sizeof *node);
-      if (!node)
-	goto cleanup;
-      node->field =3D 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 =3D 0;
-  struct conf_list_node *node;
-  struct conf_binding *cb;
-
-  list =3D malloc (sizeof *list);
-  if (!list)
-    goto cleanup;
-  TAILQ_INIT (&list->fields);
-  list->cnt =3D 0;
-  for (cb =3D LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
-       cb =3D LIST_NEXT (cb, link))
-    if (strcasecmp (section, cb->section) =3D=3D 0)
-      {
-	list->cnt++;
-	node =3D calloc (1, sizeof *node);
-	if (!node)
-	  goto cleanup;
-	node->field =3D 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 =3D 0;
-  u_int8_t c1, c2, c3, c4;
-
-  while (*buf)
-    {
-      if (*buf > 127 || (c1 =3D asc2bin[*buf]) =3D=3D 255)
-	return 0;
-      buf++;
-
-      if (*buf > 127 || (c2 =3D asc2bin[*buf]) =3D=3D 255)
-	return 0;
-      buf++;
-
-      if (*buf =3D=3D '=3D')
-	{
-	  c3 =3D c4 =3D 0;
-	  c++;
-
-	  /* Check last four bit */
-	  if (c2 & 0xF)
-	    return 0;
-
-	  if (strcmp ((char *)buf, "=3D=3D") =3D=3D 0)
-	    buf++;
-	  else
-	    return 0;
-	}
-      else if (*buf > 127 || (c3 =3D asc2bin[*buf]) =3D=3D 255)
-	return 0;
-      else
-	{
-	  if (*++buf =3D=3D '=3D')
-	    {
-	      c4 =3D 0;
-	      c +=3D 2;
-
-	      /* Check last two bit */
-	      if (c3 & 3)
-		return 0;
-
-	      if (strcmp ((char *)buf, "=3D"))
-		return 0;
-
-	    }
-	  else if (*buf > 127 || (c4 =3D asc2bin[*buf]) =3D=3D 255)
-	      return 0;
-	  else
-	      c +=3D 3;
-	}
-
-      buf++;
-      *out++ =3D (c1 << 2) | (c2 >> 4);
-      *out++ =3D (c2 << 4) | (c3 >> 2);
-      *out++ =3D (c3 << 6) | c4;
-    }
-
-  *len =3D c;
-  return 1;
-
-}
-
-void
-conf_free_list (struct conf_list *list)
-{
-  struct conf_list_node *node =3D TAILQ_FIRST (&list->fields);
-
-  while (node)
-    {
-      TAILQ_REMOVE (&list->fields, node, link);
-      if (node->field)
-	free (node->field);
-      free (node);
-      node =3D TAILQ_FIRST (&list->fields);
-    }
-  free (list);
-}
-
-int
-conf_begin (void)
-{
-  static int seq =3D 0;
-
-  return ++seq;
-}
-
-static struct conf_trans *
-conf_trans_node (int transaction, enum conf_op op)
-{
-  struct conf_trans *node;
-
-  node =3D calloc (1, sizeof *node);
-  if (!node)
-    {
-      warnx("conf_trans_node: calloc (1, %lu) failed",
-	(unsigned long)sizeof *node);
-      return 0;
-    }
-  node->trans =3D transaction;
-  node->op =3D 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 over=
ride,
-	  int is_default)
-{
-  struct conf_trans *node;
-
-  node =3D conf_trans_node (transaction, CONF_SET);
-  if (!node)
-    return 1;
-  node->section =3D strdup (section);
-  if (!node->section)
-    {
-      warnx("conf_set: strdup (\"%s\") failed", section);
-      goto fail;
-    }
-  node->tag =3D strdup (tag);
-  if (!node->tag)
-    {
-      warnx("conf_set: strdup (\"%s\") failed", tag);
-      goto fail;
-    }
-  node->value =3D strdup (value);
-  if (!node->value)
-    {
-      warnx("conf_set: strdup (\"%s\") failed", value);
-      goto fail;
-    }
-  node->override =3D override;
-  node->is_default =3D 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 =3D conf_trans_node (transaction, CONF_REMOVE);
-  if (!node)
-    goto fail;
-  node->section =3D strdup (section);
-  if (!node->section)
-    {
-      warnx("conf_remove: strdup (\"%s\") failed", section);
-      goto fail;
-    }
-  node->tag =3D 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 =3D conf_trans_node (transaction, CONF_REMOVE_SECTION);
-  if (!node)
-    goto fail;
-  node->section =3D 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 =3D TAILQ_FIRST (&conf_trans_queue); node; node =3D next)
-    {
-      next =3D TAILQ_NEXT (node, link);
-      if (node->trans =3D=3D 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=3D\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 =3D 0;
-  unsigned int i, len;
-  char *current_section =3D (char *)0;
-  struct dumper *dumper, *dnode;
-
-  dumper =3D dnode =3D (struct dumper *)calloc (1, sizeof *dumper);
-  if (!dumper)
-    goto mem_fail;
-
-  warnx("conf_report: dumping running configuration");
-
-  for (i =3D 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
-    for (cb =3D LIST_FIRST (&conf_bindings[i]); cb;
-	 cb =3D LIST_NEXT (cb, link))
-      {
-	if (!cb->is_default)
-	  {
-	    /* Dump this entry.  */
-	    if (!current_section || strcmp (cb->section, current_section))
-	      {
-		if (current_section)
-		  {
-		    len =3D strlen (current_section) + 3;
-		    dnode->s =3D malloc (len);
-		    if (!dnode->s)
-		      goto mem_fail;
-
-		    snprintf (dnode->s, len, "[%s]", current_section);
-		    dnode->next
-		      =3D (struct dumper *)calloc (1, sizeof (struct dumper));
-		    dnode =3D dnode->next;
-		    if (!dnode)
-		      goto mem_fail;
-
-		    dnode->s =3D "";
-		    dnode->next
-		      =3D (struct dumper *)calloc (1, sizeof (struct dumper));
-		    dnode =3D dnode->next;
-		    if (!dnode)
-		      goto mem_fail;
-		  }
-		current_section =3D cb->section;
-	      }
-	    dnode->s =3D cb->tag;
-	    dnode->v =3D cb->value;
-	    dnode->next =3D (struct dumper *)calloc (1, sizeof (struct dumper));
-	    dnode =3D dnode->next;
-	    if (!dnode)
-	      goto mem_fail;
-	    last =3D cb;
-	  }
-      }
-
-  if (last)
-    {
-      len =3D strlen (last->section) + 3;
-      dnode->s =3D 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 =3D dumper) !=3D 0)
-    {
-      dumper =3D 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=E5kan 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 WARRANTI=
ES
- * 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 US=
E,
- * 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

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 2/10] NFS Mount Configuration File (Vers 3)
       [not found] ` <4A7B2324.9090406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
@ 2009-08-06 18:41   ` Steve Dickson
       [not found]     ` <4A7B23D2.6080900-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  2009-08-06 18:44   ` [Patch 5/10] " Steve Dickson
  2009-08-06 18:47   ` [Patch 8/10] " Steve Dickson
  2 siblings, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:41 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit f6f4d0b872c01eaffbcb4c3919f13237aa8678e1
Author: Steve Dickson <steved@redhat.com>
Date:   Mon Mar 9 13:55:25 2009 -0400

    Taught conf_parse_line() to ignore spaces in the
     '[section]' parsing and before the assignment statements
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index c5f9fa7..5f491eb 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -50,11 +50,6 @@
 #include "xlog.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;
@@ -219,26 +214,48 @@ conf_parse_line(int trans, char *line, size_t sz)
 	if (*line == '#' || *line == ';')
 		return;
 
+	/* Ignore blank lines */
+	if (*line == '\0')
+		return;
+
+	/* Strip off any leading blanks */
+	while (isblank(*line)) 
+		line++;
+
 	/* '[section]' parsing...  */
 	if (*line == '[') {
-		for (i = 1; i < sz; i++)
-			if (line[i] == ']')
+		line++;
+		/* Strip off any blanks after '[' */
+		while (isblank(*line)) 
+			line++;
+
+		for (i = 0; i < sz; i++) {
+			if (line[i] == ']') {
 				break;
+			}
+		}
 		if (section)
-			free (section);
+			free(section);
 		if (i == sz) {
 			xlog_warn("conf_parse_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;
 		}
-		strlcpy(section, line + 1, i);
+		strncpy(section, line, i);
 		return;
 	}
 


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 3/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
  2009-08-06 18:40 ` [Patch 1/10] " Steve Dickson
       [not found] ` <4A7B2324.9090406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
@ 2009-08-06 18:42 ` Steve Dickson
  2009-08-07  7:38   ` Benny Halevy
  2009-08-06 18:43 ` [Patch 4/10] " Steve Dickson
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:42 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit 3d08862cfebb9fb8a360d362bb9e5e761e6b1fb5
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 15:53:36 2009 -0400

    Make Section names case-insensitive which should
    help in locating them resulting in make the config
    files a bit less error prone
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index 5f491eb..a8b8037 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -116,6 +116,18 @@ conf_hash(char *s)
 }
 
 /*
+ * Convert letter from upper case to lower case
+ */
+static inline void upper2lower(char *str)
+{
+	char *ptr = str;
+
+	while (*ptr) 
+		*ptr++ = tolower(*ptr);
+}
+
+
+/*
  * Insert a tag-value combination from LINE (the equal sign is at POS)
  */
 static int
@@ -654,6 +666,9 @@ conf_set(int transaction, char *section, char *tag,
 		xlog_warn("conf_set: strdup(\"%s\") failed", section);
 		goto fail;
 	}
+	/* Make Section names case-insensitive */
+	upper2lower(node->section);
+
 	node->tag = strdup(tag);
 	if (!node->tag) {
 		xlog_warn("conf_set: strdup(\"%s\") failed", tag);

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 4/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
                   ` (2 preceding siblings ...)
  2009-08-06 18:42 ` [Patch 3/10] " Steve Dickson
@ 2009-08-06 18:43 ` Steve Dickson
  2009-08-06 18:45 ` [Patch 6/10] " Steve Dickson
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:43 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit fede9b293a8faf6c4214f6dabdb1d8664929901d
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 16:02:33 2009 -0400

    Added an conditional argument to the Section names
    with the format being:
       [ Section <"argument"> ]
    This will help group similar functioning Section
    together. The argument is conditional but must be
    surrounded by the '"' characters.
    
    The new conf_get_section() interface can used
    to locate a Section by its Section name and/or
    argument.
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/support/include/conffile.h b/support/include/conffile.h
index 3309788..b263581 100644
--- a/support/include/conffile.h
+++ b/support/include/conffile.h
@@ -56,12 +56,12 @@ 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 int      conf_set(int, char *, char *, char *, int, int);
 extern void     conf_report(void);
 
 #endif				/* _CONFFILE_H_ */
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index a8b8037..97dc88a 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -50,12 +50,15 @@
 #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;
@@ -93,6 +96,7 @@ static const u_int8_t asc2bin[] =
 struct conf_binding {
   LIST_ENTRY (conf_binding) link;
   char *section;
+  char *arg;
   char *tag;
   char *value;
   int is_default;
@@ -143,6 +147,7 @@ conf_remove_now(char *section, char *tag)
 			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);
@@ -166,6 +171,7 @@ conf_remove_section_now(char *section)
 			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);
@@ -179,27 +185,28 @@ conf_remove_section_now(char *section)
  * into SECTION of our configuration database.
  */
 static int
-conf_set_now(char *section, char *tag, char *value, int override,
-	      int is_default)
+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_str(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;
@@ -215,10 +222,11 @@ conf_set_now(char *section, char *tag, char *value, int override,
 static void
 conf_parse_line(int trans, char *line, size_t sz)
 {
-	char *val;
+	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.  */
@@ -240,7 +248,6 @@ conf_parse_line(int trans, char *line, size_t sz)
 		/* Strip off any blanks after '[' */
 		while (isblank(*line)) 
 			line++;
-
 		for (i = 0; i < sz; i++) {
 			if (line[i] == ']') {
 				break;
@@ -260,7 +267,6 @@ conf_parse_line(int trans, char *line, size_t sz)
 			val++, j++;
 		if (*val)
 			i = j;
-
 		section = malloc(i);
 		if (!section) {
 			xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln,
@@ -268,6 +274,26 @@ conf_parse_line(int trans, char *line, size_t sz)
 			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("conf_parse_line: 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;
 	}
 
@@ -286,7 +312,7 @@ conf_parse_line(int trans, char *line, size_t sz)
 			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);
+			conf_set(trans, section, arg, line, val, 0, 0);
 			return;
 		}
 	}
@@ -460,6 +486,26 @@ conf_get_str(char *section, char *tag)
 	}
 	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
@@ -652,9 +698,9 @@ conf_trans_node(int transaction, enum conf_op op)
 }
 
 /* Queue a set operation.  */
-int
-conf_set(int transaction, char *section, char *tag, 
-	char *value, int override, int is_default)
+static int
+conf_set(int transaction, char *section, char *arg,
+	char *tag, char *value, int override, int is_default)
 {
 	struct conf_trans *node;
 
@@ -669,6 +715,15 @@ conf_set(int transaction, char *section, char *tag,
 	/* 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);
@@ -756,8 +811,9 @@ conf_end(int transaction, int commit)
 			if (commit) {
 				switch (node->op) {
 				case CONF_SET:
-					conf_set_now(node->section, node->tag, node->value,
-					node->override, node->is_default);
+					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);
@@ -813,8 +869,9 @@ void
 conf_report (void)
 {
 	struct conf_binding *cb, *last = 0;
-	unsigned int i, len;
+	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);
@@ -826,15 +883,29 @@ conf_report (void)
 	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)) {
-					if (current_section) {
+				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;
 
-						snprintf(dnode->s, len, "[%s]", current_section);
+						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;
@@ -849,6 +920,8 @@ conf_report (void)
 						goto mem_fail;
 					}
 					current_section = cb->section;
+					current_arg = cb->arg;
+					diff_arg = 0;
 				}
 				dnode->s = cb->tag;
 				dnode->v = cb->value;
@@ -862,10 +935,15 @@ conf_report (void)
 
 	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;
-		snprintf(dnode->s, len, "[%s]", last->section);
+		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;

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 5/10] NFS Mount Configuration File (Vers 3)
       [not found] ` <4A7B2324.9090406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  2009-08-06 18:41   ` [Patch 2/10] " Steve Dickson
@ 2009-08-06 18:44   ` Steve Dickson
  2009-08-06 18:47   ` [Patch 8/10] " Steve Dickson
  2 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:44 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit a534e4fef0ee59a33548aa9a342dad588ae605df
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 16:10:01 2009 -0400

    Adds '--enable-mountconfig' configuration flag that will
    enabled mount to read from a configuration file.
    The default value is disabled (or no)
    
    Adds '--with-mountfile' configuration flag that is used when
    mountconf is enabled to define the configuration file name.
    The default is /etc/nfsmount.conf.
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

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
 


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 6/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
                   ` (3 preceding siblings ...)
  2009-08-06 18:43 ` [Patch 4/10] " Steve Dickson
@ 2009-08-06 18:45 ` Steve Dickson
  2009-08-06 20:44   ` Chuck Lever
  2009-08-06 18:46 ` [Patch 7/10] " Steve Dickson
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:45 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit 8e88dd908d8b5ff07649c375ff638ee6ca964ead
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 16:17:38 2009 -0400

    Support routines used to read sections from the configuration file
    and parse them into comma separated mount options.
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index 459fa45..a1b56ca 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -17,6 +17,10 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 		    parse_opt.h parse_dev.h \
 		    nfs4_mount.h nfs_mount4.h stropts.h version.h
 
+if MOUNT_CONFIG
+mount_nfs_SOURCES += configfile.c
+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..cad8c52
--- /dev/null
+++ b/utils/mount/configfile.c
@@ -0,0 +1,317 @@
+/*
+ * configfile.c -- mount configuration file manipulation 
+ * Copyright (C) 2008 Red Hat, Inc <nfs@redhat.com>
+ *
+ * - 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 <config.h>
+#endif
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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  "MountPoint"
+#define NFSMOUNT_MOUNTPOINT "MountPoint"
+#endif
+
+#ifndef NFSMOUNT_SERVER "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;
+	}
+	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 && strstr(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;
+}

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 7/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
                   ` (4 preceding siblings ...)
  2009-08-06 18:45 ` [Patch 6/10] " Steve Dickson
@ 2009-08-06 18:46 ` Steve Dickson
       [not found]   ` <4A7B2515.2040304-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  2009-08-06 18:48 ` [Patch 9/10] " Steve Dickson
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:46 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit eab66bd02db90965d1cbf4e100a274a4e3e6e29e
Author: Steve Dickson <steved@redhat.com>
Date:   Sun Aug 2 12:37:19 2009 -0400

    Added hooks to the mount command that allow
    mount options to be set in a configuration file
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/utils/mount/mount.c b/utils/mount/mount.c
index a668cd9..30d087e 100644
--- a/utils/mount/mount.c
+++ b/utils/mount/mount.c
@@ -47,6 +47,11 @@
 #include "stropts.h"
 #include "version.h"
 
+#ifdef MOUNT_CONFIG
+#include "conffile.h"
+extern char *conf_get_mntopts(char *, char *, char *);
+#endif
+
 char *progname;
 int nfs_mount_data_version;
 int nomtab;
@@ -474,6 +479,13 @@ int main(int argc, char *argv[])
 	spec = argv[1];
 	mount_point = argv[2];
 
+#ifdef MOUNT_CONFIG
+	/*
+	 * Read the the default mount options
+	 */
+	conf_init();
+#endif
+
 	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 +571,12 @@ int main(int argc, char *argv[])
 		mnt_err = EX_USAGE;
 		goto out;
 	}
+#ifdef MOUNT_CONFIG
+	/*
+	 * Concatenate mount options from the configuration file
+	 */
+	mount_opts = conf_get_mntopts(spec, mount_point, mount_opts);
+#endif
 
 	parse_opts(mount_opts, &flags, &extra_opts);

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 8/10] NFS Mount Configuration File (Vers 3)
       [not found] ` <4A7B2324.9090406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  2009-08-06 18:41   ` [Patch 2/10] " Steve Dickson
  2009-08-06 18:44   ` [Patch 5/10] " Steve Dickson
@ 2009-08-06 18:47   ` Steve Dickson
  2 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:47 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit eba88370ed83a3bbfe5f4b1ef85b64da702b5e84
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 17:04:00 2009 -0400

    The new nfsmount.conf(5) man page and the update to
    the nfs(5) man page
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index a1b56ca..5c1e5ad 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -19,6 +19,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 
 if MOUNT_CONFIG
 mount_nfs_SOURCES += configfile.c
+man5_MANS += nfsmount.conf.man
 endif
 
 mount_nfs_LDADD = ../../support/nfs/libnfs.a \
diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
index 13de524..72538d1 100644
--- a/utils/mount/nfs.man
+++ b/utils/mount/nfs.man
@@ -752,6 +752,51 @@ 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. 
+.SH MOUNT CONFIGURATION FILE
+All of the mount options described in the previous section can also be configured in
+the 
+.I /etc/nfsmount.conf 
+file. This configuration file is made up of three
+different sections: Global, Server and MountPoint. See 
+.BR nfsmount.conf(5)
+for details.
+.PP
+The mount command parses section in a particular order, and will not use
+options that were set in previous sections.  The order of precedence is as follows:
+
+.B Command line option 
+.RS
+options set on the command line will always be used.
+.RE
+.B Mount Point options
+.RS
+options set in the 
+.B [MountPoint \(lqMount_Point\(rq]
+section will be used only if they are not specified 
+on the command line. 
+.I \(lqMount_Point\(rq 
+must be surrounded by \(lq and must be the exact same 
+character string given on the mount command line as
+the mount point.
+.RE
+.B Server options
+.RS
+options set in the 
+.B [Server \(lqServer_Name\(rq] 
+section will be used if they are not specified on the 
+command  line or in the mount point section.
+.I \(lqServer_Name\(rq 
+must be surrounded by \(lq and must be the exact same 
+character string given on the mount command line as 
+the server name.
+.RE
+.B Global options 
+.RS
+options set in the 
+.B [NFSMount_Global_Options] 
+will be used if they are not specified on the command line, mount point 
+section, or the server section.
+.RE
 .SH EXAMPLES
 To mount an export using NFS version 2,
 use the
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),


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 9/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
                   ` (5 preceding siblings ...)
  2009-08-06 18:46 ` [Patch 7/10] " Steve Dickson
@ 2009-08-06 18:48 ` Steve Dickson
  2009-08-06 18:49 ` [Patch 10/10] " Steve Dickson
  2009-08-17 13:12 ` [Patch 0/10] " Steve Dickson
  8 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:48 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit 6fe11af2fe9eacf785bf71f34251569bff197ebe
Author: Steve Dickson <steved@redhat.com>
Date:   Wed Aug 5 17:07:21 2009 -0400

    The example nfsmount.conf file
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index 5c1e5ad..451ec90 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -20,6 +20,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 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 \
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 '<Mount_Point>'
+# 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

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Patch 10/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
                   ` (6 preceding siblings ...)
  2009-08-06 18:48 ` [Patch 9/10] " Steve Dickson
@ 2009-08-06 18:49 ` Steve Dickson
  2009-08-17 13:12 ` [Patch 0/10] " Steve Dickson
  8 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-06 18:49 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

commit 8157fe02ca0d056eb58ba94e8dabd14ead29d2fd
Author: Steve Dickson <steved@redhat.com>
Date:   Thu Aug 6 13:11:00 2009 -0400

    Now that only the Section names are case-insensitive
    the mount code has to make sure the the mount
    options given to the kernel are in the correct
    case.
    
    Fixed a couple of warnings on #ifndefs
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/support/include/conffile.h b/support/include/conffile.h
index b263581..6fc5d60 100644
--- a/support/include/conffile.h
+++ b/support/include/conffile.h
@@ -64,4 +64,14 @@ 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 *ptr = str;
+
+	while (*ptr) 
+		*ptr++ = tolower(*ptr);
+}
 #endif				/* _CONFFILE_H_ */
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index 97dc88a..b19b739 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -120,18 +120,6 @@ conf_hash(char *s)
 }
 
 /*
- * Convert letter from upper case to lower case
- */
-static inline void upper2lower(char *str)
-{
-	char *ptr = str;
-
-	while (*ptr) 
-		*ptr++ = tolower(*ptr);
-}
-
-
-/*
  * Insert a tag-value combination from LINE (the equal sign is at POS)
  */
 static int
diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
index cad8c52..e347b0e 100644
--- a/utils/mount/configfile.c
+++ b/utils/mount/configfile.c
@@ -37,11 +37,11 @@
 #define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options"
 #endif
 
-#ifndef NFSMOUNT_MOUNTPOINT  "MountPoint"
+#ifndef NFSMOUNT_MOUNTPOINT
 #define NFSMOUNT_MOUNTPOINT "MountPoint"
 #endif
 
-#ifndef NFSMOUNT_SERVER "Server"
+#ifndef NFSMOUNT_SERVER
 #define NFSMOUNT_SERVER "Server"
 #endif
 
@@ -83,6 +83,9 @@ char *mountopts_alias(char *opt, int *argtype)
 		*argtype = mnt_alias_tab[i].argtype;
 		return mnt_alias_tab[i].opt;
 	}
+	/* Make option names case-insensitive */
+	upper2lower(opt);
+
 	return opt;
 }
 /*
@@ -202,7 +205,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
 		 * Do not overwrite options if already exists 
 		 */
 		snprintf(buf, BUFSIZ, "%s=", node->field);
-		if (opts && strstr(opts, buf) != NULL)
+		if (opts && strcasestr(opts, buf) != NULL)
 			continue;
 		if (lookup_entry(node->field) != NULL)
 			continue;

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Patch 7/10] NFS Mount Configuration File (Vers 3)
       [not found]   ` <4A7B2515.2040304-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
@ 2009-08-06 20:35     ` Chuck Lever
  2009-08-07 17:17       ` Steve Dickson
  2009-08-07 18:37       ` Steve Dickson
  0 siblings, 2 replies; 26+ messages in thread
From: Chuck Lever @ 2009-08-06 20:35 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

How come the short descriptions (Subject:) for all of these patches  
are identical?

On Aug 6, 2009, at 2:46 PM, Steve Dickson wrote:
> commit eab66bd02db90965d1cbf4e100a274a4e3e6e29e
> Author: Steve Dickson <steved@redhat.com>
> Date:   Sun Aug 2 12:37:19 2009 -0400
>
>    Added hooks to the mount command that allow
>    mount options to be set in a configuration file
>
>    Signed-off-by: Steve Dickson <steved@redhat.com>
>
> diff --git a/utils/mount/mount.c b/utils/mount/mount.c
> index a668cd9..30d087e 100644
> --- a/utils/mount/mount.c
> +++ b/utils/mount/mount.c
> @@ -47,6 +47,11 @@
> #include "stropts.h"
> #include "version.h"
>
> +#ifdef MOUNT_CONFIG
> +#include "conffile.h"
> +extern char *conf_get_mntopts(char *, char *, char *);

Can this forward declaration be added to conffile.h ?

> +#endif
> +
> char *progname;
> int nfs_mount_data_version;
> int nomtab;
> @@ -474,6 +479,13 @@ int main(int argc, char *argv[])
> 	spec = argv[1];
> 	mount_point = argv[2];
>
> +#ifdef MOUNT_CONFIG
> +	/*
> +	 * Read the the default mount options
> +	 */
> +	conf_init();
> +#endif

It would be cleaner if the #ifdefs were moved to conf_init() (and  
above, for the #include, and below, into conf_get_mntopts()).  If  
MOUNT_CONFIG isn't set, then configfile.o would just contain stubs,  
but it would then always be built.

Otherwise, we end up with each new feature adding #ifdefs in the  
mainline code, and eventually it becomes unreadable.

> +
> 	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 +571,12 @@ int main(int argc, char *argv[])
> 		mnt_err = EX_USAGE;
> 		goto out;
> 	}
> +#ifdef MOUNT_CONFIG
> +	/*
> +	 * Concatenate mount options from the configuration file
> +	 */
> +	mount_opts = conf_get_mntopts(spec, mount_point, mount_opts);
> +#endif
>
> 	parse_opts(mount_opts, &flags, &extra_opts);

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 6/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:45 ` [Patch 6/10] " Steve Dickson
@ 2009-08-06 20:44   ` Chuck Lever
  2009-08-07 17:34     ` Steve Dickson
  0 siblings, 1 reply; 26+ messages in thread
From: Chuck Lever @ 2009-08-06 20:44 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list


On Aug 6, 2009, at 2:45 PM, Steve Dickson wrote:

> commit 8e88dd908d8b5ff07649c375ff638ee6ca964ead
> Author: Steve Dickson <steved@redhat.com>
> Date:   Wed Aug 5 16:17:38 2009 -0400
>
>    Support routines used to read sections from the configuration file
>    and parse them into comma separated mount options.
>
>    Signed-off-by: Steve Dickson <steved@redhat.com>
>
> diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
> index 459fa45..a1b56ca 100644
> --- a/utils/mount/Makefile.am
> +++ b/utils/mount/Makefile.am
> @@ -17,6 +17,10 @@ mount_nfs_SOURCES = mount.c error.c network.c  
> fstab.c token.c \
> 		    parse_opt.h parse_dev.h \
> 		    nfs4_mount.h nfs_mount4.h stropts.h version.h
>
> +if MOUNT_CONFIG
> +mount_nfs_SOURCES += configfile.c
> +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..cad8c52
> --- /dev/null
> +++ b/utils/mount/configfile.c
> @@ -0,0 +1,317 @@
> +/*
> + * configfile.c -- mount configuration file manipulation
> + * Copyright (C) 2008 Red Hat, Inc <nfs@redhat.com>
> + *
> + * - 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 <config.h>
> +#endif
> +#include <sys/types.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <ctype.h>
> +
> +#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  "MountPoint"
> +#define NFSMOUNT_MOUNTPOINT "MountPoint"
> +#endif
> +
> +#ifndef NFSMOUNT_SERVER "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;
> +	}
> +	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 && strstr(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;
> +}

Seems to me the text-based mount option parser routines (parse_opt. 
[ch]) already does a lot of this.  It can break up a string into a  
linked list of options, handle quoted commas properly, catenate  
options to the list, and flatten the list back into a C string.

Wouldn't it be easier to adapt that code rather than adding new code  
that does nearly the same thing?  It would save you a lot of C string  
manipulation, and reuse working code.

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 3/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:42 ` [Patch 3/10] " Steve Dickson
@ 2009-08-07  7:38   ` Benny Halevy
  2009-08-07 17:13     ` Steve Dickson
  2009-08-07 18:35     ` Steve Dickson
  0 siblings, 2 replies; 26+ messages in thread
From: Benny Halevy @ 2009-08-07  7:38 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On Aug. 06, 2009, 21:42 +0300, Steve Dickson <SteveD@redhat.com> wrote:
> commit 3d08862cfebb9fb8a360d362bb9e5e761e6b1fb5
> Author: Steve Dickson <steved@redhat.com>
> Date:   Wed Aug 5 15:53:36 2009 -0400
> 
>     Make Section names case-insensitive which should
>     help in locating them resulting in make the config
>     files a bit less error prone
>     
>     Signed-off-by: Steve Dickson <steved@redhat.com>
> 
> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
> index 5f491eb..a8b8037 100644
> --- a/support/nfs/conffile.c
> +++ b/support/nfs/conffile.c
> @@ -116,6 +116,18 @@ conf_hash(char *s)
>  }
>  
>  /*
> + * Convert letter from upper case to lower case
> + */
> +static inline void upper2lower(char *str)
> +{
> +	char *ptr = str;
> +
> +	while (*ptr) 
> +		*ptr++ = tolower(*ptr);
> +}
> +

nit: to optimize this function a tiny bit you can also do:

static inline void upper2lower(char *str)
{
	char c;

	while ((c = tolower(*str)))
		*str++ = c;
}

Benny

> +
> +/*
>   * Insert a tag-value combination from LINE (the equal sign is at POS)
>   */
>  static int
> @@ -654,6 +666,9 @@ conf_set(int transaction, char *section, char *tag,
>  		xlog_warn("conf_set: strdup(\"%s\") failed", section);
>  		goto fail;
>  	}
> +	/* Make Section names case-insensitive */
> +	upper2lower(node->section);
> +
>  	node->tag = strdup(tag);
>  	if (!node->tag) {
>  		xlog_warn("conf_set: strdup(\"%s\") failed", tag);
> 
> _______________________________________________
> NFSv4 mailing list
> NFSv4@linux-nfs.org
> http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 1/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:40 ` [Patch 1/10] " Steve Dickson
@ 2009-08-07  8:06   ` Benny Halevy
  2009-08-07 17:09     ` Steve Dickson
  0 siblings, 1 reply; 26+ messages in thread
From: Benny Halevy @ 2009-08-07  8:06 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On Aug. 06, 2009, 21:40 +0300, Steve Dickson <SteveD@redhat.com> wrote:
<snip>


> +/*
> + * 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;
> +
> +	/* Lines starting with '#' or ';' are comments.  */
> +	ln++;
> +	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) {
> +			xlog_warn("conf_parse_line: %d:"
> + 				"non-matched ']', ignoring until next section", ln);
> +			section = 0;
> +			return;
> +		}
> +		section = malloc(i);
> +		if (!section) {
> +			xlog_warn("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) {
> +				xlog_warn("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';

Should we break on the first non space?
This will allow spaces in the value...
Should we skip trailing comments as well (';' in particular)? I.e.:

			/* 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;
			}

Benny

> +			/* 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])
> +		xlog_warn("conf_parse_line: %d: syntax error", ln);
> +
> +	return;
> +}
> +

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 2/10] NFS Mount Configuration File (Vers 3)
       [not found]     ` <4A7B23D2.6080900-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
@ 2009-08-07  8:07       ` Benny Halevy
  2009-08-07 17:11         ` Steve Dickson
  0 siblings, 1 reply; 26+ messages in thread
From: Benny Halevy @ 2009-08-07  8:07 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On Aug. 06, 2009, 21:41 +0300, Steve Dickson <SteveD@redhat.com> wrote:
> commit f6f4d0b872c01eaffbcb4c3919f13237aa8678e1
> Author: Steve Dickson <steved@redhat.com>
> Date:   Mon Mar 9 13:55:25 2009 -0400
> 
>     Taught conf_parse_line() to ignore spaces in the
>      '[section]' parsing and before the assignment statements
>     
>     Signed-off-by: Steve Dickson <steved@redhat.com>
> 
> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
> index c5f9fa7..5f491eb 100644
> --- a/support/nfs/conffile.c
> +++ b/support/nfs/conffile.c
> @@ -50,11 +50,6 @@
>  #include "xlog.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;
> @@ -219,26 +214,48 @@ conf_parse_line(int trans, char *line, size_t sz)
>  	if (*line == '#' || *line == ';')
>  		return;
>  
> +	/* Ignore blank lines */
> +	if (*line == '\0')
> +		return;
> +
> +	/* Strip off any leading blanks */
> +	while (isblank(*line)) 
> +		line++;
> +

Why not do this before looking for '#' or ';'?

Benny

>  	/* '[section]' parsing...  */
>  	if (*line == '[') {
> -		for (i = 1; i < sz; i++)
> -			if (line[i] == ']')
> +		line++;
> +		/* Strip off any blanks after '[' */
> +		while (isblank(*line)) 
> +			line++;
> +
> +		for (i = 0; i < sz; i++) {
> +			if (line[i] == ']') {
>  				break;
> +			}
> +		}
>  		if (section)
> -			free (section);
> +			free(section);
>  		if (i == sz) {
>  			xlog_warn("conf_parse_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;
>  		}
> -		strlcpy(section, line + 1, i);
> +		strncpy(section, line, i);
>  		return;
>  	}
>  
> 
> _______________________________________________
> NFSv4 mailing list
> NFSv4@linux-nfs.org
> http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 1/10] NFS Mount Configuration File (Vers 3)
  2009-08-07  8:06   ` Benny Halevy
@ 2009-08-07 17:09     ` Steve Dickson
  0 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 17:09 UTC (permalink / raw)
  To: Benny Halevy; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list



On 08/07/2009 04:06 AM, Benny Halevy wrote:
> On Aug. 06, 2009, 21:40 +0300, Steve Dickson <SteveD@redhat.com> wrote:
> <snip>
> 
> 
>> +/*
>> + * 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;
>> +
>> +	/* Lines starting with '#' or ';' are comments.  */
>> +	ln++;
>> +	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) {
>> +			xlog_warn("conf_parse_line: %d:"
>> + 				"non-matched ']', ignoring until next section", ln);
>> +			section = 0;
>> +			return;
>> +		}
>> +		section = malloc(i);
>> +		if (!section) {
>> +			xlog_warn("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) {
>> +				xlog_warn("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';
> 
> Should we break on the first non space?
> This will allow spaces in the value...
> Should we skip trailing comments as well (';' in particular)? I.e.:
Well to be honest I never looked a this code all that closely...
I just moved it from one place to another.. ;-) 


> 
> 			/* 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;
> 			}
Well since the idmapd.conf man page never talks about comments,
it not clear that in-line or trailing comments are supported. 
Remember my goal with this code was just to reuse it. I really had no 
intention on improving it  any of this code. But with that said...

If in-line or trailing comments are needed for this configuration
or other configuration, such the pnfs exports, then yes I would
say its a good idea... but would rather deal with afterwords 
once deemed needed... 

steved.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 2/10] NFS Mount Configuration File (Vers 3)
  2009-08-07  8:07       ` Benny Halevy
@ 2009-08-07 17:11         ` Steve Dickson
       [not found]           ` <4A7C6032.4060301-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 17:11 UTC (permalink / raw)
  To: Benny Halevy; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list



On 08/07/2009 04:07 AM, Benny Halevy wrote:
> On Aug. 06, 2009, 21:41 +0300, Steve Dickson <SteveD@redhat.com> wrote:
>> commit f6f4d0b872c01eaffbcb4c3919f13237aa8678e1
>> Author: Steve Dickson <steved@redhat.com>
>> Date:   Mon Mar 9 13:55:25 2009 -0400
>>
>>     Taught conf_parse_line() to ignore spaces in the
>>      '[section]' parsing and before the assignment statements
>>     
>>     Signed-off-by: Steve Dickson <steved@redhat.com>
>>
>> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
>> index c5f9fa7..5f491eb 100644
>> --- a/support/nfs/conffile.c
>> +++ b/support/nfs/conffile.c
>> @@ -50,11 +50,6 @@
>>  #include "xlog.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;
>> @@ -219,26 +214,48 @@ conf_parse_line(int trans, char *line, size_t sz)
>>  	if (*line == '#' || *line == ';')
>>  		return;
>>  
>> +	/* Ignore blank lines */
>> +	if (*line == '\0')
>> +		return;
>> +
>> +	/* Strip off any leading blanks */
>> +	while (isblank(*line)) 
>> +		line++;
>> +
> 
> Why not do this before looking for '#' or ';'?
Point, if we supported in-line comments or am I missing 
something? 

steved.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 3/10] NFS Mount Configuration File (Vers 3)
  2009-08-07  7:38   ` Benny Halevy
@ 2009-08-07 17:13     ` Steve Dickson
  2009-08-07 18:35     ` Steve Dickson
  1 sibling, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 17:13 UTC (permalink / raw)
  To: Benny Halevy; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list



On 08/07/2009 03:38 AM, Benny Halevy wrote:
> On Aug. 06, 2009, 21:42 +0300, Steve Dickson <SteveD@redhat.com> wrote:
>> commit 3d08862cfebb9fb8a360d362bb9e5e761e6b1fb5
>> Author: Steve Dickson <steved@redhat.com>
>> Date:   Wed Aug 5 15:53:36 2009 -0400
>>
>>     Make Section names case-insensitive which should
>>     help in locating them resulting in make the config
>>     files a bit less error prone
>>     
>>     Signed-off-by: Steve Dickson <steved@redhat.com>
>>
>> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
>> index 5f491eb..a8b8037 100644
>> --- a/support/nfs/conffile.c
>> +++ b/support/nfs/conffile.c
>> @@ -116,6 +116,18 @@ conf_hash(char *s)
>>  }
>>  
>>  /*
>> + * Convert letter from upper case to lower case
>> + */
>> +static inline void upper2lower(char *str)
>> +{
>> +	char *ptr = str;
>> +
>> +	while (*ptr) 
>> +		*ptr++ = tolower(*ptr);
>> +}
>> +
> 
> nit: to optimize this function a tiny bit you can also do:
> 
> static inline void upper2lower(char *str)
> {
> 	char c;
> 
> 	while ((c = tolower(*str)))
> 		*str++ = c;
> }
Point. I'll convert this during the commit or next re-spin...

steved.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 7/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 20:35     ` Chuck Lever
@ 2009-08-07 17:17       ` Steve Dickson
  2009-08-07 18:37       ` Steve Dickson
  1 sibling, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 17:17 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list



On 08/06/2009 04:35 PM, Chuck Lever wrote:
> How come the short descriptions (Subject:) for all of these patches are
> identical?
> 
Because that is the easiest way, plus when when searching for
the thread in mail archives, all of the patches show up... 

steved.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 6/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 20:44   ` Chuck Lever
@ 2009-08-07 17:34     ` Steve Dickson
  0 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 17:34 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On 08/06/2009 04:44 PM, Chuck Lever wrote:
> 
> Seems to me the text-based mount option parser routines (parse_opt.[ch])
> already does a lot of this.  It can break up a string into a linked list
> of options, handle quoted commas properly, catenate options to the list,
> and flatten the list back into a C string.
Well I patterned the code after the file parsing code in idmap daemon
which means there a common theme between both the idmap configuration
file and the mount configuration. I think that is important. 
 
> 
> Wouldn't it be easier to adapt that code rather than adding new code
> that does nearly the same thing?  It would save you a lot of C string
> manipulation, and reuse working code.
At this point, no. and I am reuse a lot of code...

steved.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 3/10] NFS Mount Configuration File (Vers 3)
  2009-08-07  7:38   ` Benny Halevy
  2009-08-07 17:13     ` Steve Dickson
@ 2009-08-07 18:35     ` Steve Dickson
  2009-08-08 20:54       ` Benny Halevy
  1 sibling, 1 reply; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 18:35 UTC (permalink / raw)
  To: Benny Halevy; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list



On 08/07/2009 03:38 AM, Benny Halevy wrote:
> On Aug. 06, 2009, 21:42 +0300, Steve Dickson <SteveD@redhat.com> wrote:
>> commit 3d08862cfebb9fb8a360d362bb9e5e761e6b1fb5
>> Author: Steve Dickson <steved@redhat.com>
>> Date:   Wed Aug 5 15:53:36 2009 -0400
>>
>>     Make Section names case-insensitive which should
>>     help in locating them resulting in make the config
>>     files a bit less error prone
>>     
>>     Signed-off-by: Steve Dickson <steved@redhat.com>
>>
>> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
>> index 5f491eb..a8b8037 100644
>> --- a/support/nfs/conffile.c
>> +++ b/support/nfs/conffile.c
>> @@ -116,6 +116,18 @@ conf_hash(char *s)
>>  }
>>  
>>  /*
>> + * Convert letter from upper case to lower case
>> + */
>> +static inline void upper2lower(char *str)
>> +{
>> +	char *ptr = str;
>> +
>> +	while (*ptr) 
>> +		*ptr++ = tolower(*ptr);
>> +}
>> +
> 
> nit: to optimize this function a tiny bit you can also do:
> 
> static inline void upper2lower(char *str)
> {
> 	char c;
> 
> 	while ((c = tolower(*str)))
> 		*str++ = c;
> }
> 
Here is the update to Patch 10/10 which fixes this nit.

commit d4d2a8a4af44c057d1bd89ea94bce7ce17bfd0a5
Author: Steve Dickson <steved@redhat.com>
Date:   Fri Aug 7 14:34:42 2009 -0400

    Now that only the Section names are case-insensitive
    the mount code has to make sure the the mount options
    given to the kernel are in the correct case.
    
    Fixed a couple of warnings on #ifndefs
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/support/include/conffile.h b/support/include/conffile.h
index b263581..132a149 100644
--- a/support/include/conffile.h
+++ b/support/include/conffile.h
@@ -64,4 +64,14 @@ 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/conffile.c b/support/nfs/conffile.c
index 97dc88a..b19b739 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -120,18 +120,6 @@ conf_hash(char *s)
 }
 
 /*
- * Convert letter from upper case to lower case
- */
-static inline void upper2lower(char *str)
-{
-	char *ptr = str;
-
-	while (*ptr) 
-		*ptr++ = tolower(*ptr);
-}
-
-
-/*
  * Insert a tag-value combination from LINE (the equal sign is at POS)
  */
 static int
diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
index cad8c52..e347b0e 100644
--- a/utils/mount/configfile.c
+++ b/utils/mount/configfile.c
@@ -37,11 +37,11 @@
 #define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options"
 #endif
 
-#ifndef NFSMOUNT_MOUNTPOINT  "MountPoint"
+#ifndef NFSMOUNT_MOUNTPOINT
 #define NFSMOUNT_MOUNTPOINT "MountPoint"
 #endif
 
-#ifndef NFSMOUNT_SERVER "Server"
+#ifndef NFSMOUNT_SERVER
 #define NFSMOUNT_SERVER "Server"
 #endif
 
@@ -83,6 +83,9 @@ char *mountopts_alias(char *opt, int *argtype)
 		*argtype = mnt_alias_tab[i].argtype;
 		return mnt_alias_tab[i].opt;
 	}
+	/* Make option names case-insensitive */
+	upper2lower(opt);
+
 	return opt;
 }
 /*
@@ -202,7 +205,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
 		 * Do not overwrite options if already exists 
 		 */
 		snprintf(buf, BUFSIZ, "%s=", node->field);
-		if (opts && strstr(opts, buf) != NULL)
+		if (opts && strcasestr(opts, buf) != NULL)
 			continue;
 		if (lookup_entry(node->field) != NULL)
 			continue;

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Patch 7/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 20:35     ` Chuck Lever
  2009-08-07 17:17       ` Steve Dickson
@ 2009-08-07 18:37       ` Steve Dickson
  1 sibling, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-07 18:37 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On 08/06/2009 04:35 PM, Chuck Lever wrote:
> 
> On Aug 6, 2009, at 2:46 PM, Steve Dickson wrote:
>> commit eab66bd02db90965d1cbf4e100a274a4e3e6e29e
>> Author: Steve Dickson <steved@redhat.com>
>> Date:   Sun Aug 2 12:37:19 2009 -0400
>>
>>    Added hooks to the mount command that allow
>>    mount options to be set in a configuration file
>>
>>    Signed-off-by: Steve Dickson <steved@redhat.com>
>>
>> diff --git a/utils/mount/mount.c b/utils/mount/mount.c
>> index a668cd9..30d087e 100644
>> --- a/utils/mount/mount.c
>> +++ b/utils/mount/mount.c
>> @@ -47,6 +47,11 @@
>> #include "stropts.h"
>> #include "version.h"
>>
>> +#ifdef MOUNT_CONFIG
>> +#include "conffile.h"
>> +extern char *conf_get_mntopts(char *, char *, char *);
> 
> Can this forward declaration be added to conffile.h ?
> 
>> +#endif
>> +
>> char *progname;
>> int nfs_mount_data_version;
>> int nomtab;
>> @@ -474,6 +479,13 @@ int main(int argc, char *argv[])
>>     spec = argv[1];
>>     mount_point = argv[2];
>>
>> +#ifdef MOUNT_CONFIG
>> +    /*
>> +     * Read the the default mount options
>> +     */
>> +    conf_init();
>> +#endif
> 
> It would be cleaner if the #ifdefs were moved to conf_init() (and above,
> for the #include, and below, into conf_get_mntopts()).  If MOUNT_CONFIG
> isn't set, then configfile.o would just contain stubs, but it would then
> always be built.
> 
> Otherwise, we end up with each new feature adding #ifdefs in the
> mainline code, and eventually it becomes unreadable.
> 
I agree... there is the update to this patch:

commit 5225a4e8fbedc5c4f888691855dd3fe2e3eff9ad
Author: Steve Dickson <steved@redhat.com>
Date:   Fri Aug 7 14:29:07 2009 -0400

    Added hooks to the mount command that allow
    mount options to be set in a configuration file
    
    Signed-off-by: Steve Dickson <steved@redhat.com>

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index a1b56ca..db7778f 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -15,7 +15,8 @@ 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
diff --git a/utils/mount/mount.c b/utils/mount/mount.c
index a668cd9..909fedf 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();
+
 	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..2af9f9d
--- /dev/null
+++ b/utils/mount/mount_config.h
@@ -0,0 +1,47 @@
+#ifndef _LINUX_MOUNT__CONFIG_H
+#define _LINUX_MOUNT_CONFIG__H
+/*
+ * mount_config.h -- mount configuration file routines 
+ * Copyright (C) 2008 Red Hat, Inc <nfs@redhat.com>
+ *
+ * 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(void);
+
+#ifdef MOUNT_CONFIG
+#include "conffile.h"
+extern char *conf_get_mntopts(char *, char *, char *);
+
+inline void mount_config_init()
+{
+	/*
+	 * 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() { }
+
+inline char *mount_config_opts(char *spec, 
+		char *mount_point, char *mount_opts)
+{
+	return mount_opts;
+}
+#endif /* MOUNT_CONFIG */
+#endif

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Patch 2/10] NFS Mount Configuration File (Vers 3)
       [not found]           ` <4A7C6032.4060301-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
@ 2009-08-08 20:52             ` Benny Halevy
  0 siblings, 0 replies; 26+ messages in thread
From: Benny Halevy @ 2009-08-08 20:52 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On Aug. 07, 2009, 20:11 +0300, Steve Dickson <SteveD@redhat.com> wrote:
> 
> On 08/07/2009 04:07 AM, Benny Halevy wrote:
>> On Aug. 06, 2009, 21:41 +0300, Steve Dickson <SteveD@redhat.com> wrote:
>>> commit f6f4d0b872c01eaffbcb4c3919f13237aa8678e1
>>> Author: Steve Dickson <steved@redhat.com>
>>> Date:   Mon Mar 9 13:55:25 2009 -0400
>>>
>>>     Taught conf_parse_line() to ignore spaces in the
>>>      '[section]' parsing and before the assignment statements
>>>     
>>>     Signed-off-by: Steve Dickson <steved@redhat.com>
>>>
>>> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
>>> index c5f9fa7..5f491eb 100644
>>> --- a/support/nfs/conffile.c
>>> +++ b/support/nfs/conffile.c
>>> @@ -50,11 +50,6 @@
>>>  #include "xlog.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;
>>> @@ -219,26 +214,48 @@ conf_parse_line(int trans, char *line, size_t sz)
>>>  	if (*line == '#' || *line == ';')
>>>  		return;
>>>  
>>> +	/* Ignore blank lines */
>>> +	if (*line == '\0')
>>> +		return;
>>> +
>>> +	/* Strip off any leading blanks */
>>> +	while (isblank(*line)) 
>>> +		line++;
>>> +
>> Why not do this before looking for '#' or ';'?
> Point, if we supported in-line comments or am I missing 
> something? 

Right.  This will allow the comment to start after a string
of white spaces.  It's not the most important feature but
will allow more readable config file, I think.

Benny

> 
> steved.
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 3/10] NFS Mount Configuration File (Vers 3)
  2009-08-07 18:35     ` Steve Dickson
@ 2009-08-08 20:54       ` Benny Halevy
  0 siblings, 0 replies; 26+ messages in thread
From: Benny Halevy @ 2009-08-08 20:54 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Linux NFS Mailing list, Linux NFSv4 mailing list

On Aug. 07, 2009, 21:35 +0300, Steve Dickson <SteveD@redhat.com> wrote:
> 
> On 08/07/2009 03:38 AM, Benny Halevy wrote:
>> On Aug. 06, 2009, 21:42 +0300, Steve Dickson <SteveD@redhat.com> wrote:
>>> commit 3d08862cfebb9fb8a360d362bb9e5e761e6b1fb5
>>> Author: Steve Dickson <steved@redhat.com>
>>> Date:   Wed Aug 5 15:53:36 2009 -0400
>>>
>>>     Make Section names case-insensitive which should
>>>     help in locating them resulting in make the config
>>>     files a bit less error prone
>>>     
>>>     Signed-off-by: Steve Dickson <steved@redhat.com>
>>>
>>> diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
>>> index 5f491eb..a8b8037 100644
>>> --- a/support/nfs/conffile.c
>>> +++ b/support/nfs/conffile.c
>>> @@ -116,6 +116,18 @@ conf_hash(char *s)
>>>  }
>>>  
>>>  /*
>>> + * Convert letter from upper case to lower case
>>> + */
>>> +static inline void upper2lower(char *str)
>>> +{
>>> +	char *ptr = str;
>>> +
>>> +	while (*ptr) 
>>> +		*ptr++ = tolower(*ptr);
>>> +}
>>> +
>> nit: to optimize this function a tiny bit you can also do:
>>
>> static inline void upper2lower(char *str)
>> {
>> 	char c;
>>
>> 	while ((c = tolower(*str)))
>> 		*str++ = c;
>> }
>>
> Here is the update to Patch 10/10 which fixes this nit.

Cool. Looks good!

Benny

> 
> commit d4d2a8a4af44c057d1bd89ea94bce7ce17bfd0a5
> Author: Steve Dickson <steved@redhat.com>
> Date:   Fri Aug 7 14:34:42 2009 -0400
> 
>     Now that only the Section names are case-insensitive
>     the mount code has to make sure the the mount options
>     given to the kernel are in the correct case.
>     
>     Fixed a couple of warnings on #ifndefs
>     
>     Signed-off-by: Steve Dickson <steved@redhat.com>
> 
> diff --git a/support/include/conffile.h b/support/include/conffile.h
> index b263581..132a149 100644
> --- a/support/include/conffile.h
> +++ b/support/include/conffile.h
> @@ -64,4 +64,14 @@ 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/conffile.c b/support/nfs/conffile.c
> index 97dc88a..b19b739 100644
> --- a/support/nfs/conffile.c
> +++ b/support/nfs/conffile.c
> @@ -120,18 +120,6 @@ conf_hash(char *s)
>  }
>  
>  /*
> - * Convert letter from upper case to lower case
> - */
> -static inline void upper2lower(char *str)
> -{
> -	char *ptr = str;
> -
> -	while (*ptr) 
> -		*ptr++ = tolower(*ptr);
> -}
> -
> -
> -/*
>   * Insert a tag-value combination from LINE (the equal sign is at POS)
>   */
>  static int
> diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
> index cad8c52..e347b0e 100644
> --- a/utils/mount/configfile.c
> +++ b/utils/mount/configfile.c
> @@ -37,11 +37,11 @@
>  #define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options"
>  #endif
>  
> -#ifndef NFSMOUNT_MOUNTPOINT  "MountPoint"
> +#ifndef NFSMOUNT_MOUNTPOINT
>  #define NFSMOUNT_MOUNTPOINT "MountPoint"
>  #endif
>  
> -#ifndef NFSMOUNT_SERVER "Server"
> +#ifndef NFSMOUNT_SERVER
>  #define NFSMOUNT_SERVER "Server"
>  #endif
>  
> @@ -83,6 +83,9 @@ char *mountopts_alias(char *opt, int *argtype)
>  		*argtype = mnt_alias_tab[i].argtype;
>  		return mnt_alias_tab[i].opt;
>  	}
> +	/* Make option names case-insensitive */
> +	upper2lower(opt);
> +
>  	return opt;
>  }
>  /*
> @@ -202,7 +205,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
>  		 * Do not overwrite options if already exists 
>  		 */
>  		snprintf(buf, BUFSIZ, "%s=", node->field);
> -		if (opts && strstr(opts, buf) != NULL)
> +		if (opts && strcasestr(opts, buf) != NULL)
>  			continue;
>  		if (lookup_entry(node->field) != NULL)
>  			continue;
> 
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Patch 0/10] NFS Mount Configuration File (Vers 3)
  2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
                   ` (7 preceding siblings ...)
  2009-08-06 18:49 ` [Patch 10/10] " Steve Dickson
@ 2009-08-17 13:12 ` Steve Dickson
  8 siblings, 0 replies; 26+ messages in thread
From: Steve Dickson @ 2009-08-17 13:12 UTC (permalink / raw)
  To: Linux NFS Mailing list, Linux NFSv4 mailing list

On 08/06/2009 02:38 PM, Steve Dickson wrote:
> Hello,
> 
> Here is the latest version of these patches. In the version
> the following changes were made:
> 
>    1) Section headers how have an argument to them. Similar
>       to [Server "foobar" ] or [MountPoint "/export"]
>    
>    2) Only the Section names are now case-less. Its up to
>       the caller of the parsing routines to deal with case
>       sensitivity of the data.
> 
> 
> Here are the pointers to the two previous versions which
> will explain the who, what and whys:  
> 
> http://marc.info/?l=linux-nfs&m=123663164305546&w=2
> http://marc.info/?l=linux-nfs&m=124931114811175&w=2
> 
> 
> This entire patch set is available at:
>     http://people.redhat.com/steved/mount-conf/ver03/
> 
> and on the 'mount_conf-ver03' branch on my experimental git tree:
>     git://linux-nfs.org/~steved/nfs-utils-exp.git

Committed... Which included the updated patches I posted
to this thread as well as Benny's suggestion on supporting
inline comments... As usual, he's observations were spot on... 

steved.

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2009-08-17 13:12 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-06 18:38 [Patch 0/10] NFS Mount Configuration File (Vers 3) Steve Dickson
2009-08-06 18:40 ` [Patch 1/10] " Steve Dickson
2009-08-07  8:06   ` Benny Halevy
2009-08-07 17:09     ` Steve Dickson
     [not found] ` <4A7B2324.9090406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2009-08-06 18:41   ` [Patch 2/10] " Steve Dickson
     [not found]     ` <4A7B23D2.6080900-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2009-08-07  8:07       ` Benny Halevy
2009-08-07 17:11         ` Steve Dickson
     [not found]           ` <4A7C6032.4060301-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2009-08-08 20:52             ` Benny Halevy
2009-08-06 18:44   ` [Patch 5/10] " Steve Dickson
2009-08-06 18:47   ` [Patch 8/10] " Steve Dickson
2009-08-06 18:42 ` [Patch 3/10] " Steve Dickson
2009-08-07  7:38   ` Benny Halevy
2009-08-07 17:13     ` Steve Dickson
2009-08-07 18:35     ` Steve Dickson
2009-08-08 20:54       ` Benny Halevy
2009-08-06 18:43 ` [Patch 4/10] " Steve Dickson
2009-08-06 18:45 ` [Patch 6/10] " Steve Dickson
2009-08-06 20:44   ` Chuck Lever
2009-08-07 17:34     ` Steve Dickson
2009-08-06 18:46 ` [Patch 7/10] " Steve Dickson
     [not found]   ` <4A7B2515.2040304-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2009-08-06 20:35     ` Chuck Lever
2009-08-07 17:17       ` Steve Dickson
2009-08-07 18:37       ` Steve Dickson
2009-08-06 18:48 ` [Patch 9/10] " Steve Dickson
2009-08-06 18:49 ` [Patch 10/10] " Steve Dickson
2009-08-17 13:12 ` [Patch 0/10] " Steve Dickson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.