review of changes to mountd.c to add experimental server support

From: Rick Macklem <rmacklem_at_uoguelph.ca>
Date: Thu, 21 May 2009 11:55:33 -0400 (EDT)
In case anyone would like to review them, here are my proposed changes to
src/usr.sbin/mountd.c so that it supports the experimental server as well
as the regular one.

It will run the experimental server if that is the only one loaded into
the kernel or the "-4" option is specified on the command line.

It parses one additional line in the exports file, which defines where the
root of the nfsv4 file system is. This line is parsed but ignored for the
regular server.

Thanks in advance for any comments, rick
--- diff -u mountd.c ---
--- freebsd-svn/usr-src/usr.sbin/mountd/mountd.c	2009-05-17 15:59:31.000000000 -0400
+++ usr-src/usr.sbin/mountd/mountd.c	2009-05-19 09:47:58.000000000 -0400
_at__at_ -61,7 +61,9 _at__at_
  #include <rpcsvc/mount.h>
  #include <nfs/rpcv2.h>
  #include <nfs/nfsproto.h>
+#include <nfs/nfssvc.h>
  #include <nfsserver/nfs.h>
+#include <fs/nfs/nfsport.h>

  #include <arpa/inet.h>

_at__at_ -200,6 +202,7 _at__at_
      struct sockaddr *samask);
  int	scan_tree(struct dirlist *, struct sockaddr *);
  static void usage(void);
+void	parse_v4root(char *, char *, int, struct xucred *);
  int	xdr_dir(XDR *, char *);
  int	xdr_explist(XDR *, caddr_t);
  int	xdr_explist_brief(XDR *, caddr_t);
_at__at_ -233,6 +236,10 _at__at_
  int opt_flags;
  static int have_v6 = 1;

+int v4root_phase = 0;
+int run_v4server = 0;
+int has_publicfh = 0;
+
  struct pidfh *pfh = NULL;
  /* Bits for opt_flags above */
  #define	OP_MAPROOT	0x01
_at__at_ -288,17 +295,15 _at__at_
  		have_v6 = 0;
  	else
  		close(s);
-	if (modfind("nfsserver") < 0) {
-		/* Not present in kernel, try loading it */
-		if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
-			errx(1, "NFS server is not available or loadable");
-	}

-	while ((c = getopt(argc, argv, "2dh:lnp:r")) != -1)
+	while ((c = getopt(argc, argv, "24dh:lnp:r")) != -1)
  		switch (c) {
  		case '2':
  			force_v2 = 1;
  			break;
+		case '4':
+			run_v4server = 1;
+			break;
  		case 'n':
  			resvport_only = 0;
  			break;
_at__at_ -343,6 +348,26 _at__at_
  		default:
  			usage();
  		};
+
+	/*
+	 * If the "-4" option was specified OR only the nfsd module is
+	 * found in the server, run "nfsd".
+	 * Otherwise, try and run "nfsserver".
+	 */
+	if (run_v4server > 0) {
+		if (modfind("nfsd") < 0) {
+			/* Not present in kernel, try loading it */
+			if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
+				errx(1, "NFS server is not available");
+		}
+	} else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) {
+		run_v4server = 1;
+	} else if (modfind("nfsserver") < 0) {
+		/* Not present in kernel, try loading it */
+		if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
+			errx(1, "NFS server is not available");
+	}
+
  	argc -= optind;
  	argv += optind;
  	grphead = (struct grouplist *)NULL;
_at__at_ -707,7 +732,7 _at__at_
  usage()
  {
  	fprintf(stderr,
-		"usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] "
+		"usage: mountd [-2] [-4] [-d] [-l] [-n] [-p <port>] [-r] "
  		"[-h <bindip>] [export_file ...]\n");
  	exit(1);
  }
_at__at_ -1166,6 +1191,26 _at__at_
  		ep = (struct exportlist *)NULL;

  		/*
+		 * Handle the V4 root dir.
+		 */
+		if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') {
+			/*
+			 * V4: just indicates that it is the v4 root point,
+			 * so skip over that and set v4root_phase.
+			 */
+			if (v4root_phase > 0) {
+				syslog(LOG_ERR, "V4:duplicate line, ignored");
+				goto nextline;
+			}
+			v4root_phase = 1;
+			cp += 3;
+			nextfield(&cp, &endcp);
+			if (run_v4server > 0)
+				parse_v4root(cp, endcp, exflags, &anon);
+			goto nextline;
+		}
+
+		/*
  		 * Create new exports list entry
  		 */
  		len = endcp-cp;
_at__at_ -1382,7 +1427,9 _at__at_
  	int dirplen, num, i;
  	int iovlen;
  	int done;
+	struct nfsex_args eargs;

+	v4root_phase = 0;
  	bzero(&export, sizeof(export));
  	export.ex_flags = MNT_DELEXPORT;
  	dirp = NULL;
_at__at_ -1411,6 +1458,21 _at__at_
  	grphead = (struct grouplist *)NULL;

  	/*
+	 * and the old V4 root dir.
+	 */
+	bzero(&eargs, sizeof (eargs));
+	eargs.export.ex_flags = MNT_DELEXPORT;
+	if (run_v4server > 0 &&
+	    nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 &&
+	    errno != ENOENT)
+		syslog(LOG_ERR, "Can't delete exports for V4:");
+
+	/*
+	 * and clear flag that notes if a public fh has been exported.
+	 */
+	has_publicfh = 0;
+
+	/*
  	 * And delete exports that are in the kernel for all local
  	 * filesystems.
  	 * XXX: Should know how to handle all local exportable filesystems.
_at__at_ -1491,6 +1553,12 _at__at_
  		syslog(LOG_ERR, "can't open any exports file");
  		exit(2);
  	}
+
+	/*
+	 * If there was no public fh, clear any previous one set.
+	 */
+	if (run_v4server > 0 && has_publicfh == 0)
+		(void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
  }

  /*
_at__at_ -1936,6 +2004,12 _at__at_
  			syslog(LOG_ERR, "bad opt %s", cpopt);
  			return (1);
  		}
+		if (v4root_phase == 1 &&
+		    ((*exflagsp & ~MNT_EXPORTED) ||
+		     (opt_flags & ~OP_SEC))) {
+			syslog(LOG_ERR, "Bad opt %s on V4:", cpopt);
+			return (1);
+		}
  		if (usedarg >= 0) {
  			*endcp = savedc2;
  			**endcpp = savedc;
_at__at_ -2233,6 +2307,29 _at__at_
  				goto error_exit;
  			}
  		}
+
+		/*
+		 * For the experimental server:
+		 * If this is the public directory, get the file handle
+		 * and load it into the kernel via the nfssvc() syscall.
+		 */
+		if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) {
+			fhandle_t fh;
+			char *public_name;
+
+			if (eap.ex_indexfile != NULL)
+				public_name = eap.ex_indexfile;
+			else
+				public_name = dirp;
+			if (getfh(public_name, &fh) < 0)
+				syslog(LOG_ERR,
+				    "Can't get public fh for %s", public_name);
+			else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0)
+				syslog(LOG_ERR,
+				    "Can't set public fh for %s", public_name);
+			else
+				has_publicfh = 1;
+		}
  skip:
  		if (ai != NULL)
  			ai = ai->ai_next;
_at__at_ -2688,7 +2785,7 _at__at_
  	struct dirlist *dp;
  {

-	if (dp == (struct dirlist *)NULL)
+	if (v4root_phase != 1 && dp == NULL)
  	    return (1);
  	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
  	    syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
_at__at_ -2710,6 +2807,12 _at__at_
  	    syslog(LOG_ERR, "-alldirs has multiple directories");
  	    return (1);
  	}
+	if (v4root_phase == 1) {
+	    if ((opt_flags & ~OP_SEC) != 0) {
+		syslog(LOG_ERR, "only -sec option allowed on V4:");
+		return (1);
+	    }
+	}
  	return (0);
  }

_at__at_ -2871,3 +2974,86 _at__at_
  	rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
  	exit (0);
  }
+
+/*
+ * Parse the V4: line.
+ */
+void
+parse_v4root(char *cp, char *endcp, int exflags, struct xucred *anonp)
+{
+	char *dirp, savedc;
+	struct grouplist gr;
+	struct exportlist ea;
+	struct nfsex_args nfsea;
+	int len, has_host, i;
+
+	exflags = MNT_EXPORTED;
+	bzero(&nfsea, sizeof (nfsea));
+	bzero(&ea, sizeof (ea));
+	bzero(&gr, sizeof (gr));
+	dirp = NULL;
+	len = endcp - cp;
+	while (len > 0) {
+		if (len > RPCMNT_NAMELEN) {
+			syslog(LOG_ERR, "V4: line too long, ignored");
+			v4root_phase = 2;
+			return;
+		}
+		if (*cp == '-') {
+			if (debug)
+				warnx("doing opt %s", cp);
+			if (do_opt(&cp, &endcp, &ea, &gr, &has_host,
+			    &exflags, anonp)) {
+				v4root_phase = 2;
+				return;
+			}
+		} else if (*cp == '/') {
+			savedc = *endcp;
+			*endcp = '\0';
+			if (check_dirpath(cp)) {
+				if (dirp != NULL) {
+					syslog(LOG_ERR, "Multiple V4 dirs");
+					v4root_phase = 2;
+					return;
+				}
+				dirp = cp;
+			} else {
+				syslog(LOG_ERR, "V4: dir %s invalid", cp);
+				v4root_phase = 2;
+				return;
+			}
+			*endcp = savedc;
+		}
+		cp = endcp;
+		nextfield(&cp, &endcp);
+		len = endcp - cp;
+	}
+
+	/* Check the options */
+	if (check_options(NULL)) {
+		v4root_phase = 2;
+		return;
+	}
+
+	/*
+	 * Now, do the nfssvc() syscall.
+	 */
+	nfsea.export.ex_flags = exflags;
+	nfsea.export.ex_anon = *anonp;
+	if (ea.ex_numsecflavors == 0) {
+		nfsea.export.ex_numsecflavors = 4;
+		nfsea.export.ex_secflavors[0] = AUTH_SYS;
+		nfsea.export.ex_secflavors[1] = RPCSEC_GSS_KRB5;
+		nfsea.export.ex_secflavors[2] = RPCSEC_GSS_KRB5I;
+		nfsea.export.ex_secflavors[3] = RPCSEC_GSS_KRB5P;
+	} else {
+		nfsea.export.ex_numsecflavors = ea.ex_numsecflavors;
+		for (i = 0; i < ea.ex_numsecflavors; i++)
+			nfsea.export.ex_secflavors[i] = ea.ex_secflavors[i];
+	}
+	nfsea.fspec = dirp;
+	if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0)
+		syslog(LOG_ERR, "Exporting V4: failed");
+	v4root_phase = 2;
+}
+
Received on Thu May 21 2009 - 14:04:22 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:48 UTC