Blob Blame History Raw
autofs-5.1.4 - add mount.fedfs.c

From: Ian Kent <raven@themaw.net>

Add build and install of the mount.fedfs binary.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG                |    1 
 Makefile                 |    3 
 Makefile.rules           |    2 
 autofs.spec              |    1 
 fedfs/Makefile           |   36 +++
 fedfs/fedfs-gpl-boiler.h |   40 ++++
 fedfs/fedfs-nls.h        |   38 ++++
 fedfs/mount.fedfs.c      |  485 ++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 605 insertions(+), 1 deletion(-)
 create mode 100644 fedfs/Makefile
 create mode 100644 fedfs/fedfs-gpl-boiler.h
 create mode 100644 fedfs/fedfs-nls.h
 create mode 100644 fedfs/mount.fedfs.c

diff --git a/CHANGELOG b/CHANGELOG
index 8d6c737c..88992147 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@ xx/xx/2018 autofs-5.1.5
 - dont allow trailing slash in master map mount points.
 - fix libresolv configure check.
 - add fedfs-getsrvinfo.c.
+- add mount.fedfs.c.
 
 19/12/2017 autofs-5.1.4
 - fix spec file url.
diff --git a/Makefile b/Makefile
index e560a7cb..99db2c75 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,9 @@ kernel:
 samples:
 	set -e; if [ -d samples ]; then $(MAKE) -C samples all; fi
 
+fedfs:
+	set -e; if [ -d fedfs ]; then $(MAKE) -C fedfs all; fi
+
 clean:
 	for i in $(SUBDIRS) samples; do \
 		if [ -d $$i ]; then $(MAKE) -C $$i clean; fi; done 	
diff --git a/Makefile.rules b/Makefile.rules
index 4deab3b9..fc9f6019 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -3,7 +3,7 @@
 #
 
 # Root directory contents
-SUBDIRS = lib daemon modules man
+SUBDIRS = lib daemon fedfs modules man
 INCDIRS = include
 INCFILES = COPYING COPYRIGHT NEWS README* TODO Makefile Makefile.rules \
 	   Makefile.conf.in .version .autofs-* configure.in aclocal.m4 \
diff --git a/autofs.spec b/autofs.spec
index 2464e741..2cc0e38f 100644
--- a/autofs.spec
+++ b/autofs.spec
@@ -191,6 +191,7 @@ fi
 %config(noreplace) /etc/sysconfig/autofs
 %config(noreplace) /etc/autofs_ldap_auth.conf
 %{_sbindir}/automount
+%{_sbindir}/mount.fedfs
 %dir %{_libdir}/autofs
 %{_libdir}/autofs/*
 %{_mandir}/*/*
diff --git a/fedfs/Makefile b/fedfs/Makefile
new file mode 100644
index 00000000..cb325bed
--- /dev/null
+++ b/fedfs/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for mount.fedfs
+#
+
+-include ../Makefile.conf
+include ../Makefile.rules
+
+SRCS = mount.fedfs.c
+HDRS = fedfs-getsrvinfo.h fedfs-gpl-boiler.h fedfs-nls.h
+
+fedfs-getsrvinfo_OBJ = fedfs-getsrvinfo.o
+
+mount_fedfs_OBJ = mount.fedfs.o
+
+version := $(shell cat ../.version)
+
+CFLAGS += -rdynamic $(DAEMON_CFLAGS) -D_GNU_SOURCE -I../include
+CFLAGS += -DVERSION_STRING=\"$(version)\"
+LDFLAGS += -rdynamic
+
+all: mount.fedfs
+
+mount.fedfs: $(mount_fedfs_OBJ) $(fedfs-getsrvinfo_OBJ) $(HDRS)
+	$(CC) -o mount.fedfs \
+	       $(mount_fedfs_OBJ) $(fedfs-getsrvinfo_OBJ) \
+	       $(LDFLAGS) $(LIBRESOLV) $(LIBS)
+
+clean:
+	rm -f *.o *.s *~ mount.fedfs
+
+install: all
+	install -d -m 755 $(INSTALLROOT)$(sbindir)
+	if ! test -x $(INSTALLROOT)$(sbindir)/mount.fedfs; \
+	then \
+		install -c mount.fedfs -m 755 $(INSTALLROOT)$(sbindir); \
+	fi
diff --git a/fedfs/fedfs-gpl-boiler.h b/fedfs/fedfs-gpl-boiler.h
new file mode 100644
index 00000000..1353e736
--- /dev/null
+++ b/fedfs/fedfs-gpl-boiler.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Oracle.  All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils 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 version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#ifndef _GPL_BOILER_H_
+#define _GPL_BOILER_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/**
+ * GPLv2 boilerplate for usage messages
+ */
+static const char *fedfs_gpl_boilerplate =
+		"\nCopyright 2010, 2011, 2012, 2013 Oracle.  "
+		"All rights reserved.\n\n"
+		"License GPLv2: "
+		"<http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>\n"
+		"This is free software.  "
+			"You are free to change and redistribute it.\n"
+		"There is NO WARRANTY, to the extent permitted by law.\n";
+
+#endif	/* !_GPL_BOILER_H_ */
diff --git a/fedfs/fedfs-nls.h b/fedfs/fedfs-nls.h
new file mode 100644
index 00000000..92f968d3
--- /dev/null
+++ b/fedfs/fedfs-nls.h
@@ -0,0 +1,38 @@
+/*
+ * From util-linux/include/nls.h (GPLv2)
+ */
+
+#ifndef UTIL_LINUX_NLS_H
+#define UTIL_LINUX_NLS_H
+
+int main(int argc, char *argv[]);
+
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#else
+# undef setlocale
+# define setlocale(Category, Locale) ({}) /* empty */
+#endif
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+# ifdef gettext_noop
+#  define N_(String) gettext_noop (String)
+# else
+#  define N_(String) (String)
+# endif
+#else
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) (Text)
+# define N_(Text) (Text)
+#endif
+
+#endif /* UTIL_LINUX_NLS_H */
diff --git a/fedfs/mount.fedfs.c b/fedfs/mount.fedfs.c
new file mode 100644
index 00000000..bd434395
--- /dev/null
+++ b/fedfs/mount.fedfs.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2011 Oracle.  All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils 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 version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <errno.h>
+#include <getopt.h>
+#include <locale.h>
+#include <netdb.h>
+#include <langinfo.h>
+
+#include "fedfs-nls.h"
+#include "fedfs-getsrvinfo.h"
+#include "fedfs-gpl-boiler.h"
+
+/**
+ * Top-level directory on client under which we mount NFSv4 domain roots
+ */
+#define FEDFS_NFS4_TLDIR		"nfs4"
+
+/**
+ * Name of SRV record containing NFSv4 FedFS root
+ */
+#define FEDFS_NFS_DOMAINROOT	"_nfs-domainroot._tcp"
+
+/**
+ * Export path of NFSv4 FedFS root
+ */
+#define FEDFS_NFS_EXPORTPATH	"/.domainroot"
+
+/**
+ * Pathname to mount.nfs
+ */
+#define MOUNT_NFS_EXECUTABLE		"/sbin/mount.nfs"
+
+/**
+ * Mount status values, lifted from util-linux
+ */
+enum {
+	EX_SUCCESS	= 0,
+	EX_USAGE	= 1,
+	EX_FAIL		= 32,
+};
+
+static char *progname;
+static int nomtab;
+static int verbose;
+static _Bool readonly;
+static _Bool sloppy;
+static _Bool fake;
+
+/**
+ * Short form command line options
+ */
+static const char fedfs_opts[] = "fhno:rsvVw";
+
+/**
+ * Long form command line options
+ */
+static const struct option fedfs_longopts[] =
+{
+	{ "fake", 0, NULL, 'f' },
+	{ "help", 0, NULL, 'h' },
+	{ "no-mtab", 0, NULL, 'n' },
+	{ "options", 1, NULL, 'o' },
+	{ "read-only", 0, NULL, 'r' },
+	{ "read-write", 0, NULL, 'w' },
+	{ "ro", 0, NULL, 'r' },
+	{ "rw", 0, NULL, 'w' },
+	{ "sloppy", 0, NULL, 's' },
+	{ "verbose", 0, NULL, 'v' },
+	{ "version", 0, NULL, 'V' },
+	{ NULL, 0, NULL, 0 }
+};
+
+/**
+ * Display mount.fedfs usage message
+ */
+static void
+mount_usage(void)
+{
+	printf(_("\nUsage: %s remotedir localdir [-fhnrsvVw]\n\n"), progname);
+	printf(_("options:\n"));
+	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
+	printf(_("\t-h\t\tPrint this help\n"));
+	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
+	printf(_("\t-r\t\tMount file system readonly\n"));
+	printf(_("\t-s\t\tTolerate sloppy mount options\n"));
+	printf(_("\t-v\t\tVerbose\n"));
+	printf(_("\t-V\t\tPrint version\n"));
+	printf(_("\t-w\t\tMount file system read-write\n"));
+
+	printf("%s", fedfs_gpl_boilerplate);
+}
+
+/**
+ * Concatenate three strings
+ *
+ * @param s NUL-terminated C string
+ * @param t NUL-terminated C string
+ * @param u NUL-terminated C string
+ * @return pointer to NUL-terminated C string or NULL
+ *
+ * Caller must free the returned string with free(3).  Always frees
+ * its first arg - typical use: s = xstrconcat3(s,t,u);
+ *
+ * Lifted from util-linux.
+ */
+static char *
+xstrconcat3(char *s, const char *t, const char *u)
+{
+	_Bool free_s = true;
+	char *result;
+
+	if (s == NULL) {
+		s = "";
+		free_s = false;
+	}
+	if (t == NULL)
+		t = "";
+	if (u == NULL)
+		u = "";
+	result = malloc(strlen(s) + strlen(t) + strlen(u) + 1);
+	if (result == NULL)
+		goto out;
+
+	strcpy(result, s);
+	strcat(result, t);
+	strcat(result, u);
+
+out:
+	if (free_s)
+		free(s);
+	return result;
+}
+
+/**
+ * Exec mount.nfs
+ *
+ * @param server NUL-terminated C string containing name of NFS server
+ * @param port server port to use when mounting
+ * @param domainname NUL-terminated C string containing FedFS domain name
+ * @param export_path NUL-terminated C string containing server export path
+ * @param mounted_on_dir NUL-terminated C string containing local mounted-on directory
+ * @param text_options NUL-terminated C string containing user's mount options
+ *
+ */
+static void
+exec_mount_nfs4(const char *server, unsigned short port,
+		const char *domainname, const char *export_path,
+		const char *mounted_on_dir, const char *text_options)
+{
+	static char special[2048];
+	static char options[2048];
+	char *args[16];
+	int count = 0;
+
+	snprintf(special, sizeof(special), "%s:%s/%s%s", server,
+			FEDFS_NFS_EXPORTPATH, domainname, export_path);
+
+	if (text_options != NULL && strcmp(text_options, "") != 0)
+		snprintf(options, sizeof(options), "%s,vers=4,fg,port=%u",
+				text_options, port);
+	else
+		snprintf(options, sizeof(options), "vers=4,fg,port=%u", port);
+
+	if (verbose) {
+		printf(_("%s: Special device:       %s\n"),
+			progname, special);
+		printf(_("%s: Mounted-on directory: %s\n"),
+			progname, mounted_on_dir);
+		printf(_("%s: Mount options:        %s\n"),
+			progname, options);
+	}
+
+	args[count++] = MOUNT_NFS_EXECUTABLE;
+	args[count++] = special;
+	args[count++] = (char *)mounted_on_dir;
+	if (verbose)
+		args[count++] = "-v";
+	if (fake)
+		args[count++] = "-f";
+	if (nomtab)
+		args[count++] = "-n";
+	if (readonly)
+		args[count++] = "-r";
+	if (sloppy)
+		args[count++] = "-s";
+	args[count++] = "-o";
+	args[count++] = options;
+
+	args[count] = NULL;
+	execv(args[0], args);
+}
+
+/**
+ * Mount a FedFS domain root via NFSv4
+ *
+ * @param domainname NUL-terminated C string containing FedFS domain name
+ * @param export_path NUL-terminated C string containing server export path
+ * @param mounted_on_dir NUL-terminated C string containing local mounted-on directory
+ * @param text_options NUL-terminated C string containing user's mount options
+ * @return exit status code from the mount.nfs command
+ *
+ * Construct the server:/export string and the mounted-on directory string
+ * based on the DNS SRV query results, then fork and exec mount.nfs to do
+ * the actual mount request.
+ */
+static int
+nfs4_mount(const char *domainname, const char *export_path,
+		const char *mounted_on_dir, const char *text_options)
+{
+	struct srvinfo *tmp, *si = NULL;
+	int error, status;
+
+	status = EX_FAIL;
+
+	error = getsrvinfo(FEDFS_NFS_DOMAINROOT, domainname, &si);
+	switch (error) {
+	case ESI_SUCCESS:
+		break;
+	case ESI_NONAME:
+		fprintf(stderr, _("%s: Domain name %s not found\n"),
+			progname, domainname);
+		goto out;
+	case ESI_SERVICE:
+		fprintf(stderr, _("%s: No FedFS domain root available for %s\n"),
+			progname, domainname);
+		goto out;
+	default:
+		fprintf(stderr, _("%s: Failed to resolve %s: %s\n"),
+			progname, domainname, gsi_strerror(error));
+		goto out;
+	}
+
+	/*
+	 * The srvinfo list is already in RFC 2782 sorted order.  Try each
+	 * SRV record once, in the foreground.  Go with the first one that
+	 * works.
+	 */
+	for (tmp = si; tmp != NULL; tmp = tmp->si_next) {
+		pid_t pid;
+
+		pid = fork();
+		switch (pid) {
+		case 0:
+			exec_mount_nfs4(tmp->si_target, tmp->si_port,
+					domainname, export_path, mounted_on_dir,
+					text_options);
+			/*NOTREACHED*/
+			fprintf(stderr, _("%s: Failed to exec: %s\n"),
+				progname, strerror(errno));
+			exit(EX_FAIL);
+		case -1:
+			fprintf(stderr, _("%s: Failed to fork: %s\n"),
+				progname, strerror(errno));
+			goto out;
+		default:
+			waitpid(pid, &status, 0);
+			if (status == EX_SUCCESS)
+				goto out;
+		}
+	}
+
+out:
+	freesrvinfo(si);
+	return status;
+}
+
+/**
+ * Try one mount request
+ *
+ * @param source NUL-terminated C string containing name of "special device"
+ * @param target NUL-terminated C string containing local mounted-on directory
+ * @param text_options NUL-terminated C string containing user's mount options
+ * @return an exit status code
+ *
+ * Parse the pathname in "source."  It contains the file system protocol
+ * and FedFS domain name.  Then pass these arguments to the appropriate
+ * mount helper subcommand.
+ */
+static int
+try_mount(const char *source, const char *target, const char *text_options)
+{
+	char *global_name, *topdir, *domainname, *remaining;
+	int result;
+
+	remaining = NULL;
+	result = EX_FAIL;
+
+	global_name = strdup(source);
+	if (global_name == NULL) {
+		fprintf(stderr, _("%s: Unable to parse globally useful name\n"),
+				progname);
+		goto out;
+	}
+
+	topdir = strtok(global_name, "/");
+	if (topdir == NULL) {
+		fprintf(stderr, _("%s: Invalid globally useful name: %s\n"),
+			progname, source);
+		goto out;
+	}
+	if (verbose)
+		printf(_("%s: Top-level directory:  %s\n"),
+			progname, topdir);
+
+	domainname = strtok(NULL, "/");
+	if (domainname == NULL) {
+		fprintf(stderr, _("%s: Missing domain name in globally "
+				"useful name: %s\n"), progname, source);
+		goto out;
+	}
+	if (verbose)
+		printf(_("%s: Domain name:          %s\n"),
+			progname, domainname);
+
+	remaining = strtok(NULL, "/");
+	if (remaining == NULL) {
+		remaining = strdup("/");
+		if (remaining == NULL) {
+			fprintf(stderr, _("%s: No memory\n"), progname);
+			goto out;
+		}
+	} else {
+		char *tmp;
+
+		tmp = malloc(strlen(remaining) + 1);
+		if (tmp == NULL) {
+			fprintf(stderr, _("%s: No memory\n"), progname);
+			remaining = NULL;
+			goto out;
+		}
+		strcpy(tmp, "/");
+		strcat(tmp, remaining);
+		remaining = tmp;
+	}
+	if (verbose)
+		printf(_("%s: Export path:          %s\n"),
+			progname, remaining);
+
+	if (strcmp(topdir, FEDFS_NFS4_TLDIR) == 0)
+		result = nfs4_mount(domainname, remaining, target, text_options);
+#if 0
+	/* example: SMB support plugs in here */
+	else if (strcmp(topdir, FEDFS_SMB_TLDIR) == 0)
+		result = smb_mount(domainname, remaining, target, text_options);
+#endif
+	else
+		fprintf(stderr, _("%s: Unrecognized file system protocol\n"), progname);
+
+out:
+	free(global_name);
+	free(remaining);
+
+	return result;
+}
+
+/**
+ * Program entry point
+ *
+ * @param argc count of command line arguments
+ * @param argv array of NUL-terminated C strings containing command line arguments
+ * @return program exit status
+ */
+int main(int argc, char *argv[])
+{
+	char *source, *target, *text_options;
+	int c, mnt_err;
+
+	(void)setlocale(LC_ALL, "");
+
+	progname = basename(argv[0]);
+
+	if (argv[1] && argv[1][0] == '-') {
+		if(argv[1][1] == 'V')
+			printf("%s (VERSION_STRING)\n", progname);
+		else
+			mount_usage();
+		exit(EX_SUCCESS);
+	}
+
+	if (argc < 3) {
+		mount_usage();
+		exit(EX_USAGE);
+	}
+
+	source = argv[1];
+	target = argv[2];
+
+	mnt_err = EX_USAGE;
+	text_options = NULL;
+	readonly = false;
+	sloppy = false;
+	fake = false;
+	argv[2] = argv[0]; /* so that getopt error messages are correct */
+	while ((c = getopt_long(argc - 2, argv + 2, fedfs_opts,
+				fedfs_longopts, NULL)) != -1) {
+		switch (c) {
+		case 'f':
+			fake = true;
+			break;
+		case 'n':
+			++nomtab;
+			break;
+		case 'o':
+			/* Ugh. */
+			if (text_options != NULL)
+				text_options = xstrconcat3(text_options, ",", optarg);
+			else
+				text_options = strdup(optarg);
+			if (text_options == NULL) {
+				fprintf(stderr, _("%s: No memory\n"), progname);
+				goto out;
+			}
+			break;
+		case 'r':
+			readonly = true;
+			break;
+		case 's':
+			sloppy = true;
+			break;
+		case 'v':
+			++verbose;
+			break;
+		case 'V':
+			printf("%s: (VERSION_STRING)\n", progname);
+			mnt_err = EX_SUCCESS;
+			goto out;
+		case 'w':
+			readonly = false;
+			break;
+		case 'h':
+		default:
+			mount_usage();
+			goto out;
+		}
+	}
+
+	/* Extra non-option words at the end are bogus...  */
+	if (optind != argc - 2) {
+		mount_usage();
+		goto out;
+	}
+
+	if (getuid() != 0 && geteuid() != 0) {
+		fprintf(stderr, _("%s: Not installed setuid - "
+			    "\"user\" FedFS mounts are not supported\n"), progname);
+		mnt_err = EX_FAIL;
+		goto out;
+	}
+
+	mnt_err = try_mount(source, target, text_options);
+
+out:
+	free(text_options);
+	exit(mnt_err);
+}