Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 0eec05715da3ca8ae3817a0833b18fa6 > files > 58

nfs-utils-1.0.9-50.el5.src.rpm

--- nfs-utils-1.0.9/support/include/exportfs.h.orig	2008-02-09 06:58:10.000000000 -0500
+++ nfs-utils-1.0.9/support/include/exportfs.h	2008-02-09 06:58:45.000000000 -0500
@@ -47,7 +47,9 @@ typedef struct mexport {
 	int			m_exported;	/* known to knfsd. -1 means not sure */
 	int			m_xtabent  : 1,	/* xtab entry exists */
 				m_mayexport: 1,	/* derived from xtabbed */
-				m_changed  : 1; /* options (may) have changed */
+				m_changed  : 1, /* options (may) have changed */
+				m_warned   : 1;	/* warned about multiple exports
+						  * matching one client */
 } nfs_export;
 
 extern nfs_client *		clientlist[MCL_MAXTYPES];
--- nfs-utils-1.0.9/support/export/export.c.orig	2008-02-09 06:58:10.000000000 -0500
+++ nfs-utils-1.0.9/support/export/export.c	2008-02-09 06:58:45.000000000 -0500
@@ -92,6 +92,7 @@ export_init(nfs_export *exp, nfs_client 
 	exp->m_xtabent = 0;
 	exp->m_mayexport = 0;
 	exp->m_changed = 0;
+	exp->m_warned = 0;
 	exp->m_client = clp;
 	clp->m_count++;
 }
@@ -119,6 +120,7 @@ export_dup(nfs_export *exp, struct hoste
 	new->m_exported = 0;
 	new->m_xtabent = 0;
 	new->m_changed = 0;
+	new->m_warned = 0;
 	export_add(new);
 
 	return new;
--- nfs-utils-1.0.9/utils/mountd/mountd.c.orig	2008-02-09 06:58:10.000000000 -0500
+++ nfs-utils-1.0.9/utils/mountd/mountd.c	2008-02-09 06:58:45.000000000 -0500
@@ -29,7 +29,7 @@
 
 extern void	cache_open(void);
 extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p);
-extern void cache_export(nfs_export *exp);
+extern int cache_export(nfs_export *exp, char *path);
 
 extern void my_svc_run(void);
 
@@ -398,7 +398,7 @@ get_rootfh(struct svc_req *rqstp, dirpat
 		     p, strerror(errno));
 		*error = NFSERR_NOENT;
 	} else if (estb.st_dev != stb.st_dev
-		   /* && (!new_cache || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) */
+		   && (!new_cache || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT))
 		) {
 		xlog(L_WARNING, "request to export directory %s below nearest filesystem %s",
 		     p, exp->m_export.e_path);
@@ -417,7 +417,10 @@ get_rootfh(struct svc_req *rqstp, dirpat
 		 */
 		struct nfs_fh_len  *fh;
 
-		cache_export(exp);
+		if (cache_export(exp, p)) {
+			*error = NFSERR_ACCES;
+			return NULL;
+		}
 		fh = cache_get_filehandle(exp, v3?64:32, p);
 		if (fh == NULL) 
 			*error = NFSERR_ACCES;
--- nfs-utils-1.0.9/utils/mountd/cache.c.orig	2008-02-09 06:58:10.000000000 -0500
+++ nfs-utils-1.0.9/utils/mountd/cache.c	2008-02-09 07:02:53.000000000 -0500
@@ -21,6 +21,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
+#include <mntent.h>
 #include "misc.h"
 #include "nfslib.h"
 #include "exportfs.h"
@@ -37,7 +38,7 @@
  * Record is terminated with newline.
  *
  */
-void cache_export_ent(char *domain, struct exportent *exp);
+int cache_export_ent(char *domain, struct exportent *exp, char *p);
 
 
 char *lbuf  = NULL;
@@ -59,6 +60,7 @@ void auth_unix_ip(FILE *f)
 	char *client = NULL;
 	struct in_addr addr;
 	struct hostent *he = NULL;
+
 	if (readline(fileno(f), &lbuf, &lbuflen) != 1)
 		return;
 
@@ -92,12 +94,37 @@ void auth_unix_ip(FILE *f)
 	else if (client)
 		qword_print(f, *client?client:"DEFAULT");
 	qword_eol(f);
-	xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, *client?client: "DEFAULT");
+	xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
 
 	if (client) free(client);
 	free(he);
 }
 
+/* Iterate through /etc/mtab, finding mountpoints
+ * at or below a given path
+ */
+static char *next_mnt(void **v, char *p)
+{
+	FILE *f;
+	struct mntent *me;
+	int l = strlen(p);
+	if (*v == NULL) {
+		f = setmntent("/etc/mtab", "r");
+		*v = f;
+	} else
+		f = *v;
+	while ((me = getmntent(f)) != NULL &&
+	       (strncmp(me->mnt_dir, p, l) != 0 ||
+		me->mnt_dir[l] != '/'))
+		;
+	if (me == NULL) {
+		endmntent(f);
+		*v = NULL;
+		return NULL;
+	}
+	return me->mnt_dir;
+}
+
 void nfsd_fh(FILE *f)
 {
 	/* request are:
@@ -115,6 +142,7 @@ void nfsd_fh(FILE *f)
 	char fsid[32];
 	struct exportent *found = NULL;
 	struct hostent *he = NULL;
+	char *found_path = NULL;
 	struct in_addr addr;
 	nfs_export *exp;
 	int i;
@@ -183,8 +211,34 @@ void nfsd_fh(FILE *f)
 
 	/* Now determine export point for this fsid/domain */
 	for (i=0 ; i < MCL_MAXTYPES; i++) {
-		for (exp = exportlist[i]; exp; exp = exp->m_next) {
+		nfs_export *next_exp;
+		for (exp = exportlist[i]; exp; exp = next_exp) {
 			struct stat stb;
+			char *path;
+
+			if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
+				static nfs_export *prev = NULL;
+				static void *mnt = NULL;
+
+				if (prev == exp) {
+					/* try a submount */
+					path = next_mnt(&mnt, exp->m_export.e_path);
+					if (!path) {
+						next_exp = exp->m_next;
+						prev = NULL;
+						continue;
+					}
+					next_exp = exp;
+				} else {
+					prev = exp;
+					mnt = NULL;
+					path = exp->m_export.e_path;
+					next_exp = exp;
+				}
+			} else {
+				path = exp->m_export.e_path;
+				next_exp = exp->m_next;
+			}
 
 			if (!use_ipaddr && !client_member(dom, exp->m_client->m_hostname))
 				continue;
@@ -193,11 +247,9 @@ void nfsd_fh(FILE *f)
 					   exp->m_export.e_mountpoint:
 					   exp->m_export.e_path))
 				dev_missing ++;
-			if (stat(exp->m_export.e_path, &stb) != 0)
+			if (stat(path, &stb) != 0)
 				continue;
-			if (fsidtype == 1 &&
-			    ((exp->m_export.e_flags & NFSEXP_FSID) == 0 ||
-			     exp->m_export.e_fsid != fsidnum))
+			if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode))
 				continue;
 			if (fsidtype != 1) {
 				if (stb.st_ino != inode)
@@ -205,6 +257,10 @@ void nfsd_fh(FILE *f)
 				if (major != major(stb.st_dev) ||
 				    minor != minor(stb.st_dev))
 					continue;
+			} else {
+				if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 ||
+				     exp->m_export.e_fsid != fsidnum))
+					continue;
 			}
 			if (use_ipaddr) {
 				if (he == NULL) {
@@ -216,12 +272,15 @@ void nfsd_fh(FILE *f)
 					continue;
 			}
 			/* It's a match !! */
-			if (!found)
+			if (!found) {
 				found = &exp->m_export;
-			else if (strcmp(found->e_path, exp->m_export.e_path)!= 0)
+				found_path = strdup(path);
+				if (found_path == NULL)
+					goto out;
+			} else if (strcmp(found->e_path, exp->m_export.e_path)!= 0)
 			{
 				xlog(L_WARNING, "%s and %s have same filehandle for %s, using first",
-				     found->e_path, exp->m_export.e_path, dom);
+				     found_path, path, dom);
 			}
 		}
 	}
@@ -245,8 +304,10 @@ void nfsd_fh(FILE *f)
 		goto out;
 	}
 
-	if (found)
-		cache_export_ent(dom, found);
+	if (found) {
+		if (cache_export_ent(dom, found, found_path) < 0)
+			found = 0;
+	}
 
 	qword_print(f, dom);
 	qword_printint(f, fsidtype);
@@ -256,7 +317,10 @@ void nfsd_fh(FILE *f)
 		qword_print(f, found->e_path);
 	qword_eol(f);
  out:
-	free(he);
+	if (found_path)
+		free(found_path);
+	if (he)
+		free(he);
 	free(dom);
 	xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL);
 	return;		
@@ -338,6 +402,7 @@ void nfsd_export(FILE *f)
 	char *dom, *path;
 	nfs_export *exp, *found = NULL;
 	struct in_addr addr;
+	int found_type = 0;
 	struct hostent *he = NULL;
 
 
@@ -365,7 +430,17 @@ void nfsd_export(FILE *f)
 		for (exp = exportlist[i]; exp; exp = exp->m_next) {
 			if (!use_ipaddr && !client_member(dom, exp->m_client->m_hostname))
 				continue;
-			if (strcmp(path, exp->m_export.e_path))
+			if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
+				/* if path is a mountpoint below e_path, then OK */
+				int l = strlen(exp->m_export.e_path);
+				if (strcmp(path, exp->m_export.e_path) == 0 ||
+					(strncmp(path, exp->m_export.e_path, l) == 0 &&
+					path[l] == '/' &&
+					is_mountpoint(path)))
+					/* ok */;
+				else 
+					continue;
+			} else if (strcmp(path, exp->m_export.e_path))
 				continue;
 			if (use_ipaddr) {
 				if (he == NULL) {
@@ -376,12 +451,30 @@ void nfsd_export(FILE *f)
 				if (!client_check(exp->m_client, he))
 					continue;
 			}
-			if (!found)
+			if (!found) {
 				found = exp;
-			else {
-				xlog(L_WARNING, "%s exported to both %s and %s in %s",
-				     path, exp->m_client->m_hostname, found->m_client->m_hostname,
-				     dom);
+				found_type = i;
+				continue;
+			}
+			/* If one is a CROSSMOUNT, then prefer the longest path */
+			if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) ||
+				 (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) &&
+				strlen(found->m_export.e_path) !=
+				strlen(exp->m_export.e_path)) {
+
+				if (strlen(exp->m_export.e_path) >
+					strlen(found->m_export.e_path)) {
+					found = exp;
+					found_type = i;
+				}
+				continue;
+
+			} else if (found_type == i && found->m_warned == 0) {
+				xlog(L_WARNING, "%s exported to both %s and %s, "
+					"arbitrarily choosing options from first",
+					path, found->m_client->m_hostname, exp->m_client->m_hostname,
+					dom);
+				found->m_warned = 1;
 			}
 		}
 	}
@@ -418,7 +511,7 @@ struct {
 void cache_open(void) 
 {
 	int i;
-	for (i=0; cachelist[i].cache_name; i++ ){
+	for (i=0; cachelist[i].cache_name; i++ ) {
 		char path[100];
 		sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name);
 		cachelist[i].f = fopen(path, "r+");
@@ -456,35 +549,84 @@ int cache_process_req(fd_set *readfds) 
  * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel
  */
 
-void cache_export_ent(char *domain, struct exportent *exp)
+int cache_export_ent(char *domain, struct exportent *exp, char *path)
 {
-
+	int err = 0;
 	FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w");
 	if (!f)
-		return;
+		return -1;
+
+	err = dump_to_cache(f, domain, exp->e_path, exp);
+	if (err) {
+		xlog(L_WARNING,
+			"Cannot export %s, possibly unsupported filesystem or"
+			" fsid= required", exp->e_path);
+	}
 
-	dump_to_cache(f, domain, exp->e_path, exp);
+	while (err == 0 && (exp->e_flags & NFSEXP_CROSSMOUNT) && path) {
+		/* really an 'if', but we can break out of
+		 * a 'while' more easily */
+		/* Look along 'path' for other filesystems
+		 * and export them with the same options
+		 */
+		struct stat stb;
+		int l = strlen(exp->e_path);
+		int dev;
+
+		if (strlen(path) <= l || path[l] != '/' ||
+		    strncmp(exp->e_path, path, l) != 0)
+			break;
+		if (stat(exp->e_path, &stb) != 0)
+			break;
+		dev = stb.st_dev;
+		while(path[l] == '/') {
+			char c;
+			/* errors for submount should fail whole filesystem */
+			int err2;
+
+			l++;
+			while (path[l] != '/' && path[l])
+				l++;
+			c = path[l];
+			path[l] = 0;
+			err2 = lstat(path, &stb);
+			path[l] = c;
+			if (err2 < 0)
+				break;
+			if (stb.st_dev == dev)
+				continue;
+			dev = stb.st_dev;
+			path[l] = 0;
+			dump_to_cache(f, domain, path, exp);
+			path[l] = c;
+		}
+		break;
+	}
 
 	fclose(f);
+	return err;
 }
 
-void cache_export(nfs_export *exp)
+int cache_export(nfs_export *exp, char *path)
 {
+	int err;
 	FILE *f;
 
 	f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w");
 	if (!f)
-		return;
+		return -1;
 
 	qword_print(f, "nfsd");
 	qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0]));
 	qword_printint(f, time(0)+30*60);
 	qword_print(f, exp->m_client->m_hostname);
-	qword_eol(f);
+	err = qword_eol(f);
 	
 	fclose(f);
 
-	cache_export_ent(exp->m_client->m_hostname, &exp->m_export);
+	err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export, path) 
+		|| err;
+	return err;
 }
 
 /* Get a filehandle.
@@ -511,7 +653,7 @@ cache_get_filehandle(nfs_export *exp, in
 	qword_print(f, p);
 	qword_printint(f, len);	
 	qword_eol(f);
-	
+
 	failed = (fgets(buf, sizeof(buf), f) == NULL);
 	fclose(f);
 	if (failed)
--- nfs-utils-1.0.9/utils/exportfs/exportfs.c.orig	2008-02-09 06:58:10.000000000 -0500
+++ nfs-utils-1.0.9/utils/exportfs/exportfs.c	2008-02-09 06:58:45.000000000 -0500
@@ -218,6 +218,7 @@ export_all(int verbose)
 			exp->m_xtabent = 1;
 			exp->m_mayexport = 1;
 			exp->m_changed = 1;
+			exp->m_warned = 0;
 		}
 	}
 }
@@ -274,6 +275,7 @@ exportfs(char *arg, char *options, int v
 	exp->m_xtabent = 1;
 	exp->m_mayexport = 1;
 	exp->m_changed = 1;
+	exp->m_warned = 0;
 	if (hp) free (hp);
 }