walters / rpms / nfs-utils

Forked from rpms/nfs-utils 6 years ago
Clone
718f39a
diff --git a/support/export/export.c b/support/export/export.c
718f39a
index e1bebce..0b8a858 100644
718f39a
--- a/support/export/export.c
718f39a
+++ b/support/export/export.c
718f39a
@@ -15,6 +15,8 @@
718f39a
 #include <sys/param.h>
718f39a
 #include <netinet/in.h>
718f39a
 #include <stdlib.h>
718f39a
+#include <dirent.h>
718f39a
+#include <errno.h>
718f39a
 #include "xmalloc.h"
718f39a
 #include "nfslib.h"
718f39a
 #include "exportfs.h"
718f39a
@@ -96,6 +98,69 @@ export_read(char *fname)
718f39a
 }
718f39a
 
718f39a
 /**
718f39a
+ * export_d_read - read entries from /etc/exports.
718f39a
+ * @fname: name of directory to read from
718f39a
+ *
718f39a
+ * Returns number of read entries.
718f39a
+ * Based on mnt_table_parse_dir() in
718f39a
+ *  util-linux-ng/shlibs/mount/src/tab_parse.c
718f39a
+ */
718f39a
+int
718f39a
+export_d_read(const char *dname)
718f39a
+{
718f39a
+	int n = 0, i;
718f39a
+	struct dirent **namelist = NULL;
718f39a
+	int volumes = 0;
718f39a
+
718f39a
+
718f39a
+	n = scandir(dname, &namelist, NULL, versionsort);
718f39a
+	if (n < 0) {
718f39a
+		if (errno == ENOENT)
718f39a
+			/* Silently return */
718f39a
+			return volumes;
718f39a
+		xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno));
718f39a
+	} else if (n == 0)
718f39a
+		return volumes;
718f39a
+
718f39a
+	for (i = 0; i < n; i++) {
718f39a
+		struct dirent *d = namelist[i];
718f39a
+		size_t namesz;
718f39a
+		char fname[PATH_MAX + 1];
718f39a
+		int fname_len;
718f39a
+
718f39a
+
718f39a
+		if (d->d_type != DT_UNKNOWN
718f39a
+		    && d->d_type != DT_REG
718f39a
+		    && d->d_type != DT_LNK)
718f39a
+			continue;
718f39a
+		if (*d->d_name == '.')
718f39a
+			continue;
718f39a
+
718f39a
+#define _EXT_EXPORT_SIZ   (sizeof(_EXT_EXPORT) - 1)
718f39a
+		namesz = strlen(d->d_name);
718f39a
+		if (!namesz
718f39a
+		    || namesz < _EXT_EXPORT_SIZ + 1
718f39a
+		    || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ),
718f39a
+			      _EXT_EXPORT))
718f39a
+			continue;
718f39a
+
718f39a
+		fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name);
718f39a
+		if (fname_len > PATH_MAX) {
718f39a
+			xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname);
718f39a
+			continue;
718f39a
+		}
718f39a
+
718f39a
+		volumes += export_read(fname);
718f39a
+	}
718f39a
+
718f39a
+	for (i = 0; i < n; i++)
718f39a
+		free(namelist[i]);
718f39a
+	free(namelist);
718f39a
+
718f39a
+	return volumes;
718f39a
+}
718f39a
+
718f39a
+/**
718f39a
  * export_create - create an in-core nfs_export record from an export entry
718f39a
  * @xep: export entry to lookup
718f39a
  * @canonical: if set, e_hostname is known to be canonical DNS name
718f39a
diff --git a/support/include/exportfs.h b/support/include/exportfs.h
718f39a
index 4cac203..f033329 100644
718f39a
--- a/support/include/exportfs.h
718f39a
+++ b/support/include/exportfs.h
718f39a
@@ -135,6 +135,7 @@ int 				client_member(const char *client,
718f39a
 						const char *name);
718f39a
 
718f39a
 int				export_read(char *fname);
718f39a
+int				export_d_read(const char *dname);
718f39a
 void				export_reset(nfs_export *);
718f39a
 nfs_export *			export_lookup(char *hname, char *path, int caconical);
718f39a
 nfs_export *			export_find(const struct addrinfo *ai,
718f39a
diff --git a/systemd/Makefile.am b/systemd/Makefile.am
718f39a
index 03f96e9..49c9b8d 100644
718f39a
--- a/systemd/Makefile.am
718f39a
+++ b/systemd/Makefile.am
718f39a
@@ -39,8 +39,16 @@ endif
718f39a
 EXTRA_DIST = $(unit_files)
718f39a
 
718f39a
 unit_dir = /usr/lib/systemd/system
718f39a
+generator_dir = /usr/lib/systemd/system-generators
718f39a
+
718f39a
+EXTRA_PROGRAMS	= nfs-server-generator
718f39a
+genexecdir = $(generator_dir)
718f39a
+nfs_server_generator_LDADD = ../support/export/libexport.a \
718f39a
+			     ../support/nfs/libnfs.a \
718f39a
+			     ../support/misc/libmisc.a
718f39a
 
718f39a
 if INSTALL_SYSTEMD
718f39a
+genexec_PROGRAMS = nfs-server-generator
718f39a
 install-data-hook: $(unit_files)
718f39a
 	mkdir -p $(DESTDIR)/$(unitdir)
718f39a
 	cp $(unit_files) $(DESTDIR)/$(unitdir)
718f39a
diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c
718f39a
new file mode 100644
718f39a
index 0000000..af8bb52
718f39a
--- /dev/null
718f39a
+++ b/systemd/nfs-server-generator.c
718f39a
@@ -0,0 +1,144 @@
718f39a
+/*
718f39a
+ * nfs-server-generator:
718f39a
+ *   systemd generator to create ordering dependencies between
718f39a
+ *   nfs-server and various filesystem mounts
718f39a
+ *
718f39a
+ * 1/ nfs-server should start Before any 'nfs' mountpoints are
718f39a
+ *    mounted, in case they are loop-back mounts.  This ordering is particularly
718f39a
+ *    important for the shutdown side, so the nfs-server is stopped
718f39a
+ *    after the filesystems are unmounted.
718f39a
+ * 2/ nfs-server should start After all exported filesystems are mounted
718f39a
+ *    so there is no risk of exporting the underlying directory.
718f39a
+ *    This is particularly important for _net mounts which
718f39a
+ *    are not caught by "local-fs.target".
718f39a
+ */
718f39a
+
718f39a
+#ifdef HAVE_CONFIG_H
718f39a
+#include <config.h>
718f39a
+#endif
718f39a
+
718f39a
+#include <sys/stat.h>
718f39a
+#include <sys/types.h>
718f39a
+#include <unistd.h>
718f39a
+#include <stdlib.h>
718f39a
+#include <string.h>
718f39a
+#include <ctype.h>
718f39a
+#include <stdio.h>
718f39a
+#include <mntent.h>
718f39a
+
718f39a
+#include "misc.h"
718f39a
+#include "nfslib.h"
718f39a
+#include "exportfs.h"
718f39a
+
718f39a
+/* A simple "set of strings" to remove duplicates
718f39a
+ * found in /etc/exports
718f39a
+ */
718f39a
+struct list {
718f39a
+	struct list *next;
718f39a
+	char *name;
718f39a
+};
718f39a
+static int is_unique(struct list **lp, char *path)
718f39a
+{
718f39a
+	struct list *l = *lp;
718f39a
+
718f39a
+	while (l) {
718f39a
+		if (strcmp(l->name, path) == 0)
718f39a
+			return 0;
718f39a
+		l = l->next;
718f39a
+	}
718f39a
+	l = malloc(sizeof(*l));
718f39a
+	l->name = path;
718f39a
+	l->next = *lp;
718f39a
+	*lp = l;
718f39a
+	return 1;
718f39a
+}
718f39a
+
718f39a
+/* We need to convert a path name to a systemd unit
718f39a
+ * name.  This requires some translation ('/' -> '-')
718f39a
+ * and some escaping.
718f39a
+ */
718f39a
+static void systemd_escape(FILE *f, char *path)
718f39a
+{
718f39a
+	while (*path == '/')
718f39a
+		path++;
718f39a
+	if (!*path) {
718f39a
+		/* "/" becomes "-", otherwise leading "/" is ignored */
718f39a
+		fputs("-", f);
718f39a
+		return;
718f39a
+	}
718f39a
+	while (*path) {
718f39a
+		char c = *path++;
718f39a
+
718f39a
+		if (c == '/') {
718f39a
+			/* multiple non-trailing slashes become '-' */
718f39a
+			while (*path == '/')
718f39a
+				path++;
718f39a
+			if (*path)
718f39a
+				fputs("-", f);
718f39a
+		} else if (isalnum(c) || c == ':' || c == '.')
718f39a
+			fputc(c, f);
718f39a
+		else
718f39a
+			fprintf(f, "\\x%02x", c & 0xff);
718f39a
+	}
718f39a
+}
718f39a
+
718f39a
+int main(int argc, char *argv[])
718f39a
+{
718f39a
+	char		*path;
718f39a
+	char		dirbase[] = "/nfs-server.service.d";
718f39a
+	char		filebase[] = "/order-with-mounts.conf";
718f39a
+	nfs_export	*exp;
718f39a
+	int		i;
718f39a
+	struct list	*list = NULL;
718f39a
+	FILE		*f, *fstab;
718f39a
+	struct mntent	*mnt;
718f39a
+
718f39a
+	if (argc != 4 || argv[1][0] != '/') {
718f39a
+		fprintf(stderr, "nfs-server-generator: create systemd dependencies for nfs-server\n");
718f39a
+		fprintf(stderr, "Usage: normal-dir early-dir late-dir\n");
718f39a
+		exit(1);
718f39a
+	}
718f39a
+
718f39a
+	path = malloc(strlen(argv[1]) + sizeof(dirbase) + sizeof(filebase));
718f39a
+	if (!path)
718f39a
+		exit(2);
718f39a
+	if (export_read(_PATH_EXPORTS) +
718f39a
+	    export_d_read(_PATH_EXPORTS_D) == 0)
718f39a
+		/* Nothing is exported, so nothing to do */
718f39a
+		exit(0);
718f39a
+
718f39a
+	strcat(strcpy(path, argv[1]), dirbase);
718f39a
+	mkdir(path, 0755);
718f39a
+	strcat(path, filebase);
718f39a
+	f = fopen(path, "w");
718f39a
+	if (!f)
718f39a
+		return 1;
718f39a
+	fprintf(f, "# Automatically generated by nfs-server-generator\n\n[Unit]\n");
718f39a
+
718f39a
+	for (i = 0; i < MCL_MAXTYPES; i++) {
718f39a
+		for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
718f39a
+			if (!is_unique(&list, exp->m_export.e_path))
718f39a
+				continue;
718f39a
+			if (strchr(exp->m_export.e_path, ' '))
718f39a
+				fprintf(f, "RequiresMountsFor=\"%s\"\n",
718f39a
+					exp->m_export.e_path);
718f39a
+			else
718f39a
+				fprintf(f, "RequiresMountsFor=%s\n",
718f39a
+					exp->m_export.e_path);
718f39a
+		}
718f39a
+	}
718f39a
+
718f39a
+	fstab = setmntent("/etc/fstab", "r");
718f39a
+	while ((mnt = getmntent(fstab)) != NULL) {
718f39a
+		if (strcmp(mnt->mnt_type, "nfs") != 0 &&
718f39a
+		    strcmp(mnt->mnt_type, "nfs4") != 0)
718f39a
+			continue;
718f39a
+		fprintf(f, "Before= ");
718f39a
+		systemd_escape(f, mnt->mnt_dir);
718f39a
+		fprintf(f, ".mount\n");
718f39a
+	}
718f39a
+
718f39a
+	fclose(f);
718f39a
+
718f39a
+	exit(0);
718f39a
+}
718f39a
diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service
718f39a
index 2ccdc63..196c818 100644
718f39a
--- a/systemd/nfs-server.service
718f39a
+++ b/systemd/nfs-server.service
718f39a
@@ -16,9 +16,6 @@ Before= rpc-statd-notify.service
718f39a
 Wants=auth-rpcgss-module.service
718f39a
 After=rpc-gssd.service gssproxy.service rpc-svcgssd.service
718f39a
 
718f39a
-# start/stop server before/after client
718f39a
-Before=remote-fs-pre.target
718f39a
-
718f39a
 Wants=nfs-config.service
718f39a
 After=nfs-config.service
718f39a
 
718f39a
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
718f39a
index a00b5ea..4ac2c15 100644
718f39a
--- a/utils/exportfs/exportfs.c
718f39a
+++ b/utils/exportfs/exportfs.c
718f39a
@@ -26,7 +26,6 @@
718f39a
 #include <fcntl.h>
718f39a
 #include <netdb.h>
718f39a
 #include <errno.h>
718f39a
-#include <dirent.h>
718f39a
 #include <limits.h>
718f39a
 #include <time.h>
718f39a
 
718f39a
@@ -47,7 +46,6 @@ static void	error(nfs_export *exp, int err);
718f39a
 static void	usage(const char *progname, int n);
718f39a
 static void	validate_export(nfs_export *exp);
718f39a
 static int	matchhostname(const char *hostname1, const char *hostname2);
718f39a
-static int	export_d_read(const char *dname);
718f39a
 static void grab_lockfile(void);
718f39a
 static void release_lockfile(void);
718f39a
 
718f39a
@@ -700,63 +698,6 @@ out:
718f39a
 	return result;
718f39a
 }
718f39a
 
718f39a
-/* Based on mnt_table_parse_dir() in
718f39a
-   util-linux-ng/shlibs/mount/src/tab_parse.c */
718f39a
-static int
718f39a
-export_d_read(const char *dname)
718f39a
-{
718f39a
-	int n = 0, i;
718f39a
-	struct dirent **namelist = NULL;
718f39a
-	int volumes = 0;
718f39a
-
718f39a
-
718f39a
-	n = scandir(dname, &namelist, NULL, versionsort);
718f39a
-	if (n < 0) {
718f39a
-		if (errno == ENOENT)
718f39a
-			/* Silently return */
718f39a
-			return volumes;
718f39a
-		xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno));
718f39a
-	} else if (n == 0)
718f39a
-		return volumes;
718f39a
-
718f39a
-	for (i = 0; i < n; i++) {
718f39a
-		struct dirent *d = namelist[i];
718f39a
-		size_t namesz;
718f39a
-		char fname[PATH_MAX + 1];
718f39a
-		int fname_len;
718f39a
-
718f39a
-
718f39a
-		if (d->d_type != DT_UNKNOWN
718f39a
-		    && d->d_type != DT_REG
718f39a
-		    && d->d_type != DT_LNK)
718f39a
-			continue;
718f39a
-		if (*d->d_name == '.')
718f39a
-			continue;
718f39a
-
718f39a
-#define _EXT_EXPORT_SIZ   (sizeof(_EXT_EXPORT) - 1)
718f39a
-		namesz = strlen(d->d_name);
718f39a
-		if (!namesz
718f39a
-		    || namesz < _EXT_EXPORT_SIZ + 1
718f39a
-		    || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ),
718f39a
-			      _EXT_EXPORT))
718f39a
-			continue;
718f39a
-
718f39a
-		fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name);
718f39a
-		if (fname_len > PATH_MAX) {
718f39a
-			xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname);
718f39a
-			continue;
718f39a
-		}
718f39a
-
718f39a
-		volumes += export_read(fname);
718f39a
-	}
718f39a
-
718f39a
-	for (i = 0; i < n; i++)
718f39a
-		free(namelist[i]);
718f39a
-	free(namelist);
718f39a
-
718f39a
-	return volumes;
718f39a
-}
718f39a
-
718f39a
 static char
718f39a
 dumpopt(char c, char *fmt, ...)
718f39a
 {
718f39a
diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man
718f39a
index b9200c7..d4ab894 100644
718f39a
--- a/utils/idmapd/idmapd.man
718f39a
+++ b/utils/idmapd/idmapd.man
718f39a
@@ -23,6 +23,29 @@ is the NFSv4 ID <-> name mapping daemon.  It provides functionality to
718f39a
 the NFSv4 kernel client and server, to which it communicates via
718f39a
 upcalls, by translating user and group IDs to names, and vice versa.
718f39a
 .Pp
718f39a
+The system derives the
718f39a
+.I user
718f39a
+part of the string by performing a password or group lookup.
718f39a
+The lookup mechanism is configured in
718f39a
+.Pa /etc/idmapd.conf
718f39a
+.Pp
718f39a
+By default, the
718f39a
+.I domain
718f39a
+part of the string is the system's DNS domain name.
718f39a
+It can also be specified in
718f39a
+.Pa /etc/idmapd.conf
718f39a
+if the system is multi-homed,
718f39a
+or if the system's DNS domain name does
718f39a
+not match the name of the system's Kerberos realm.
718f39a
+.Pp
718f39a
+When the domain is not specified in /etc/idmapd.conf
718f39a
+the local DNS server will be queried for the 
718f39a
+.Sy _nfsv4idmapdomain 
718f39a
+text record. If the record exists
718f39a
+that will be used as the domain. When the record
718f39a
+does not exist, the domain part of the DNS domain
718f39a
+will used. 
718f39a
+.Pp
718f39a
 Note that on more recent kernels only the NFSv4 server uses
718f39a
 .Nm .
718f39a
 The NFSv4 client instead uses
718f39a
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
718f39a
index 9de6794..d5dfb5e 100644
718f39a
--- a/utils/mount/stropts.c
718f39a
+++ b/utils/mount/stropts.c
718f39a
@@ -948,6 +948,7 @@ static int nfs_is_permanent_error(int error)
718f39a
 	case ETIMEDOUT:
718f39a
 	case ECONNREFUSED:
718f39a
 	case EHOSTUNREACH:
718f39a
+	case EOPNOTSUPP:	/* aka RPC_PROGNOTREGISTERED */
718f39a
 	case EAGAIN:
718f39a
 		return 0;	/* temporary */
718f39a
 	default:
718f39a
@@ -1019,8 +1020,7 @@ static int nfsmount_parent(struct nfsmount_info *mi)
718f39a
 	if (nfs_try_mount(mi))
718f39a
 		return EX_SUCCESS;
718f39a
 
718f39a
-	/* retry background mounts when the server is not up */
718f39a
-	if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) {
718f39a
+	if (nfs_is_permanent_error(errno)) {
718f39a
 		mount_error(mi->spec, mi->node, errno);
718f39a
 		return EX_FAIL;
718f39a
 	}
718f39a
@@ -1055,8 +1055,7 @@ static int nfsmount_child(struct nfsmount_info *mi)
718f39a
 		if (nfs_try_mount(mi))
718f39a
 			return EX_SUCCESS;
718f39a
 
718f39a
-		/* retry background mounts when the server is not up */
718f39a
-		if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP)
718f39a
+		if (nfs_is_permanent_error(errno))
718f39a
 			break;
718f39a
 
718f39a
 		if (time(NULL) > timeout)
718f39a
diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man
718f39a
index 2f17cf2..2af16f3 100644
718f39a
--- a/utils/nfsidmap/nfsidmap.man
718f39a
+++ b/utils/nfsidmap/nfsidmap.man
718f39a
@@ -39,6 +39,15 @@ if the system is multi-homed,
718f39a
 or if the system's DNS domain name does
718f39a
 not match the name of the system's Kerberos realm.
718f39a
 .PP
718f39a
+When the domain is not specified in 
718f39a
+.I /etc/idmapd.conf
718f39a
+the local DNS server will be queried for the 
718f39a
+.I _nfsv4idmapdomain 
718f39a
+text record. If the record exists
718f39a
+that will be used as the domain. When the record
718f39a
+does not exist, the domain part of the DNS domain
718f39a
+will used. 
718f39a
+.PP
718f39a
 The
718f39a
 .I /usr/sbin/nfsidmap
718f39a
 program performs translations on behalf of the kernel.