1345 lines
39 KiB
Diff
1345 lines
39 KiB
Diff
|
diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h
|
||
|
index 38db5b5..df4ad76 100644
|
||
|
--- a/support/include/nfs/nfs.h
|
||
|
+++ b/support/include/nfs/nfs.h
|
||
|
@@ -17,7 +17,6 @@
|
||
|
|
||
|
#define NFS4_MINMINOR 1
|
||
|
#define NFS4_MAXMINOR 2
|
||
|
-#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */
|
||
|
|
||
|
struct nfs_fh_len {
|
||
|
int fh_size;
|
||
|
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
|
||
|
index f210a06..ce4b14b 100644
|
||
|
--- a/support/include/nfslib.h
|
||
|
+++ b/support/include/nfslib.h
|
||
|
@@ -128,6 +128,10 @@ void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos);
|
||
|
void fendrmtabent(FILE *fp);
|
||
|
void frewindrmtabent(FILE *fp);
|
||
|
|
||
|
+/* mydaemon */
|
||
|
+void mydaemon(int nochdir, int noclose, int *pipefds);
|
||
|
+void release_parent(int *pipefds);
|
||
|
+
|
||
|
/*
|
||
|
* wildmat borrowed from INN
|
||
|
*/
|
||
|
diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am
|
||
|
index 05c2fc4..fb9b8c1 100644
|
||
|
--- a/support/nfs/Makefile.am
|
||
|
+++ b/support/nfs/Makefile.am
|
||
|
@@ -2,7 +2,7 @@
|
||
|
|
||
|
noinst_LIBRARIES = libnfs.a
|
||
|
libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \
|
||
|
- xlog.c xcommon.c wildmat.c nfsclient.c \
|
||
|
+ xlog.c xcommon.c wildmat.c mydaemon.c nfsclient.c \
|
||
|
nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \
|
||
|
svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \
|
||
|
svc_create.c atomicio.c strlcpy.c strlcat.c
|
||
|
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
|
||
|
index d18667f..819d6c4 100644
|
||
|
--- a/support/nfs/exports.c
|
||
|
+++ b/support/nfs/exports.c
|
||
|
@@ -366,7 +366,7 @@ mkexportent(char *hname, char *path, char *options)
|
||
|
ee.e_hostname = xstrdup(hname);
|
||
|
|
||
|
if (strlen(path) >= sizeof(ee.e_path)) {
|
||
|
- xlog(L_WARNING, "path name %s too long", path);
|
||
|
+ xlog(L_ERROR, "path name %s too long", path);
|
||
|
return NULL;
|
||
|
}
|
||
|
strncpy(ee.e_path, path, sizeof (ee.e_path));
|
||
|
diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c
|
||
|
new file mode 100644
|
||
|
index 0000000..e885d60
|
||
|
--- /dev/null
|
||
|
+++ b/support/nfs/mydaemon.c
|
||
|
@@ -0,0 +1,148 @@
|
||
|
+/*
|
||
|
+ mydaemon.c
|
||
|
+
|
||
|
+ Copyright (c) 2000 The Regents of the University of Michigan.
|
||
|
+ All rights reserved.
|
||
|
+
|
||
|
+ Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
|
||
|
+ Copyright (c) 2002 Andy Adamson <andros@UMICH.EDU>.
|
||
|
+ Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
|
||
|
+ Copyright (c) 2002 J. Bruce Fields <bfields@UMICH.EDU>.
|
||
|
+ Copyright (c) 2013 Jeff Layton <jlayton@redhat.com>
|
||
|
+
|
||
|
+ All rights reserved, all wrongs reversed.
|
||
|
+
|
||
|
+ 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.
|
||
|
+ 3. Neither the name of the University nor the names of its
|
||
|
+ contributors may be used to endorse or promote products derived
|
||
|
+ from this software without specific prior written permission.
|
||
|
+
|
||
|
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||
|
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||
|
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 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 USE, 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.
|
||
|
+
|
||
|
+*/
|
||
|
+
|
||
|
+#include <sys/param.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <xlog.h>
|
||
|
+
|
||
|
+/**
|
||
|
+ * mydaemon - daemonize, but have parent wait to exit
|
||
|
+ * @nochdir: skip chdir()'ing the child to / after forking if true
|
||
|
+ * @noclose: skip closing stdin/stdout/stderr if true
|
||
|
+ * @pipefds: pointer to 2 element array of pipefds
|
||
|
+ *
|
||
|
+ * This function is like daemon(), but with our own special sauce to delay
|
||
|
+ * the exit of the parent until the child is set up properly. A pipe is created
|
||
|
+ * between parent and child. The parent process will wait to exit until the
|
||
|
+ * child dies or writes a '1' on the pipe signaling that it started
|
||
|
+ * successfully.
|
||
|
+ */
|
||
|
+void
|
||
|
+mydaemon(int nochdir, int noclose, int *pipefds)
|
||
|
+{
|
||
|
+ int pid, status, tempfd;
|
||
|
+
|
||
|
+ if (pipe(pipefds) < 0) {
|
||
|
+ xlog_err("mydaemon: pipe() failed: errno %d (%s)\n",
|
||
|
+ errno, strerror(errno));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+ if ((pid = fork ()) < 0) {
|
||
|
+ xlog_err("mydaemon: fork() failed: errno %d (%s)\n",
|
||
|
+ errno, strerror(errno));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (pid != 0) {
|
||
|
+ /*
|
||
|
+ * Parent. Wait for status from child.
|
||
|
+ */
|
||
|
+ close(pipefds[1]);
|
||
|
+ if (read(pipefds[0], &status, 1) != 1)
|
||
|
+ exit(1);
|
||
|
+ exit (0);
|
||
|
+ }
|
||
|
+ /* Child. */
|
||
|
+ close(pipefds[0]);
|
||
|
+ setsid ();
|
||
|
+ if (nochdir == 0) {
|
||
|
+ if (chdir ("/") == -1) {
|
||
|
+ xlog_err("mydaemon: chdir() failed: errno %d (%s)\n",
|
||
|
+ errno, strerror(errno));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ while (pipefds[1] <= 2) {
|
||
|
+ pipefds[1] = dup(pipefds[1]);
|
||
|
+ if (pipefds[1] < 0) {
|
||
|
+ xlog_err("mydaemon: dup() failed: errno %d (%s)\n",
|
||
|
+ errno, strerror(errno));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (noclose == 0) {
|
||
|
+ tempfd = open("/dev/null", O_RDWR);
|
||
|
+ if (tempfd >= 0) {
|
||
|
+ dup2(tempfd, 0);
|
||
|
+ dup2(tempfd, 1);
|
||
|
+ dup2(tempfd, 2);
|
||
|
+ close(tempfd);
|
||
|
+ } else {
|
||
|
+ xlog_err("mydaemon: can't open /dev/null: errno %d "
|
||
|
+ "(%s)\n", errno, strerror(errno));
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * release_parent - tell the parent that it can exit now
|
||
|
+ * @pipefds: pipefd array that was previously passed to mydaemon()
|
||
|
+ *
|
||
|
+ * This function tells the parent process of mydaemon() that it's now clear
|
||
|
+ * to exit(0).
|
||
|
+ */
|
||
|
+void
|
||
|
+release_parent(int *pipefds)
|
||
|
+{
|
||
|
+ int status;
|
||
|
+
|
||
|
+ if (pipefds[1] > 0) {
|
||
|
+ if (write(pipefds[1], &status, 1) != 1) {
|
||
|
+ xlog_err("WARN: writing to parent pipe failed: errno "
|
||
|
+ "%d (%s)\n", errno, strerror(errno));
|
||
|
+ }
|
||
|
+ close(pipefds[1]);
|
||
|
+ pipefds[1] = -1;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
|
||
|
index da5fe21..8c86790 100644
|
||
|
--- a/utils/exportfs/exportfs.c
|
||
|
+++ b/utils/exportfs/exportfs.c
|
||
|
@@ -27,6 +27,10 @@
|
||
|
#include <netdb.h>
|
||
|
#include <errno.h>
|
||
|
#include <dirent.h>
|
||
|
+#include <limits.h>
|
||
|
+#include <time.h>
|
||
|
+
|
||
|
+#define INT_TO_LONG_THRESHOLD_SECS (INT_MAX - (60 * 60 * 24))
|
||
|
|
||
|
#include "sockaddr.h"
|
||
|
#include "misc.h"
|
||
|
@@ -61,19 +65,19 @@ static int _lockfd = -1;
|
||
|
* writes A+B writes A+C
|
||
|
*
|
||
|
* The locking in support/export/xtab.c will prevent mountd from
|
||
|
- * seeing a partially written version of etab, and will prevent
|
||
|
+ * seeing a partially written version of etab, and will prevent
|
||
|
* the two writers above from writing simultaneously and
|
||
|
* corrupting etab, but to prevent problems like the above we
|
||
|
* need these additional lockfile() routines.
|
||
|
*/
|
||
|
-static void
|
||
|
+static void
|
||
|
grab_lockfile()
|
||
|
{
|
||
|
_lockfd = open(lockfile, O_CREAT|O_RDWR, 0666);
|
||
|
- if (_lockfd != -1)
|
||
|
+ if (_lockfd != -1)
|
||
|
lockf(_lockfd, F_LOCK, 0);
|
||
|
}
|
||
|
-static void
|
||
|
+static void
|
||
|
release_lockfile()
|
||
|
{
|
||
|
if (_lockfd != -1)
|
||
|
@@ -267,7 +271,7 @@ exports_update(int verbose)
|
||
|
exports_update_one(exp, verbose);
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
+
|
||
|
/*
|
||
|
* export_all finds all entries and
|
||
|
* marks them xtabent and mayexport so that they get exported
|
||
|
@@ -282,7 +286,7 @@ export_all(int verbose)
|
||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||
|
if (verbose)
|
||
|
printf("exporting %s:%s\n",
|
||
|
- exp->m_client->m_hostname,
|
||
|
+ exp->m_client->m_hostname,
|
||
|
exp->m_export.e_path);
|
||
|
exp->m_xtabent = 1;
|
||
|
exp->m_mayexport = 1;
|
||
|
@@ -329,7 +333,7 @@ exportfs(char *arg, char *options, int verbose)
|
||
|
goto out;
|
||
|
|
||
|
if (verbose)
|
||
|
- printf("exporting %s:%s\n", exp->m_client->m_hostname,
|
||
|
+ printf("exporting %s:%s\n", exp->m_client->m_hostname,
|
||
|
exp->m_export.e_path);
|
||
|
exp->m_xtabent = 1;
|
||
|
exp->m_mayexport = 1;
|
||
|
@@ -387,7 +391,7 @@ unexportfs(char *arg, int verbose)
|
||
|
else
|
||
|
#endif
|
||
|
printf("unexporting %s:%s\n",
|
||
|
- exp->m_client->m_hostname,
|
||
|
+ exp->m_client->m_hostname,
|
||
|
exp->m_export.e_path);
|
||
|
}
|
||
|
#if 0
|
||
|
@@ -398,7 +402,7 @@ unexportfs(char *arg, int verbose)
|
||
|
exp->m_mayexport = 0;
|
||
|
success = 1;
|
||
|
}
|
||
|
- if (!success)
|
||
|
+ if (!success)
|
||
|
xlog(L_ERROR, "Could not find '%s:%s' to unexport.", arg, path);
|
||
|
|
||
|
freeaddrinfo(ai);
|
||
|
@@ -406,17 +410,33 @@ unexportfs(char *arg, int verbose)
|
||
|
|
||
|
static int can_test(void)
|
||
|
{
|
||
|
+ char buf[1024];
|
||
|
int fd;
|
||
|
int n;
|
||
|
- char *setup = "nfsd 0.0.0.0 2147483647 -test-client-\n";
|
||
|
+
|
||
|
fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY);
|
||
|
- if ( fd < 0) return 0;
|
||
|
- n = write(fd, setup, strlen(setup));
|
||
|
+ if (fd < 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * We introduce tolerance of 1 day to ensure that we use a
|
||
|
+ * LONG_MAX for the expiry timestamp before it is actually
|
||
|
+ * needed. To use LONG_MAX, the kernel code must have
|
||
|
+ * commit 2f74f972 (sunrpc: prepare NFS for 2038).
|
||
|
+ */
|
||
|
+ if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS)
|
||
|
+ sprintf(buf, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX);
|
||
|
+ else
|
||
|
+ sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX);
|
||
|
+
|
||
|
+ n = write(fd, buf, strlen(buf));
|
||
|
close(fd);
|
||
|
if (n < 0)
|
||
|
return 0;
|
||
|
+
|
||
|
fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY);
|
||
|
- if ( fd < 0) return 0;
|
||
|
+ if (fd < 0)
|
||
|
+ return 0;
|
||
|
close(fd);
|
||
|
return 1;
|
||
|
}
|
||
|
@@ -424,11 +444,17 @@ static int can_test(void)
|
||
|
static int test_export(char *path, int with_fsid)
|
||
|
{
|
||
|
char buf[1024];
|
||
|
+ char *bp = buf;
|
||
|
+ int len = sizeof(buf);
|
||
|
int fd, n;
|
||
|
|
||
|
- sprintf(buf, "-test-client- %s 3 %d 65534 65534 0\n",
|
||
|
- path,
|
||
|
- with_fsid ? NFSEXP_FSID : 0);
|
||
|
+ n = snprintf(buf, len, "-test-client- ");
|
||
|
+ bp += n;
|
||
|
+ len -= n;
|
||
|
+ qword_add(&bp, &len, path);
|
||
|
+ if (len < 1)
|
||
|
+ return 0;
|
||
|
+ snprintf(bp, len, " 3 %d 65534 65534 0\n", with_fsid ? NFSEXP_FSID : 0);
|
||
|
fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY);
|
||
|
if (fd < 0)
|
||
|
return 0;
|
||
|
@@ -596,7 +622,7 @@ export_d_read(const char *dname)
|
||
|
int fname_len;
|
||
|
|
||
|
|
||
|
- if (d->d_type != DT_UNKNOWN
|
||
|
+ if (d->d_type != DT_UNKNOWN
|
||
|
&& d->d_type != DT_REG
|
||
|
&& d->d_type != DT_LNK)
|
||
|
continue;
|
||
|
@@ -605,7 +631,7 @@ export_d_read(const char *dname)
|
||
|
|
||
|
#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1)
|
||
|
namesz = strlen(d->d_name);
|
||
|
- if (!namesz
|
||
|
+ if (!namesz
|
||
|
|| namesz < _EXT_EXPORT_SIZ + 1
|
||
|
|| strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ),
|
||
|
_EXT_EXPORT))
|
||
|
@@ -619,7 +645,7 @@ export_d_read(const char *dname)
|
||
|
|
||
|
export_read(fname);
|
||
|
}
|
||
|
-
|
||
|
+
|
||
|
for (i = 0; i < n; i++)
|
||
|
free(namelist[i]);
|
||
|
free(namelist);
|
||
|
@@ -642,6 +668,9 @@ dumpopt(char c, char *fmt, ...)
|
||
|
static void
|
||
|
dump(int verbose, int export_format)
|
||
|
{
|
||
|
+ char buf[1024];
|
||
|
+ char *bp;
|
||
|
+ int len;
|
||
|
nfs_export *exp;
|
||
|
struct exportent *ep;
|
||
|
int htype;
|
||
|
@@ -659,7 +688,15 @@ dump(int verbose, int export_format)
|
||
|
if (strlen(ep->e_path) > 14 && !export_format)
|
||
|
printf("%-14s\n\t\t%s", ep->e_path, hname);
|
||
|
else
|
||
|
- printf(((export_format)? "%s %s" : "%-14s\t%s"), ep->e_path, hname);
|
||
|
+ if (export_format) {
|
||
|
+ bp = buf;
|
||
|
+ len = sizeof(buf) - 1;
|
||
|
+ qword_add(&bp, &len, ep->e_path);
|
||
|
+ *bp = '\0';
|
||
|
+ printf("%s %s", buf, hname);
|
||
|
+ } else {
|
||
|
+ printf("%-14s\t%s", ep->e_path, hname);
|
||
|
+ }
|
||
|
|
||
|
if (!verbose && !export_format) {
|
||
|
printf("\n");
|
||
|
@@ -697,8 +734,8 @@ dump(int verbose, int export_format)
|
||
|
if (ep->e_uuid)
|
||
|
c = dumpopt(c, "fsid=%s", ep->e_uuid);
|
||
|
if (ep->e_mountpoint)
|
||
|
- c = dumpopt(c, "mountpoint%s%s",
|
||
|
- ep->e_mountpoint[0]?"=":"",
|
||
|
+ c = dumpopt(c, "mountpoint%s%s",
|
||
|
+ ep->e_mountpoint[0]?"=":"",
|
||
|
ep->e_mountpoint);
|
||
|
if (ep->e_anonuid != 65534)
|
||
|
c = dumpopt(c, "anonuid=%d", ep->e_anonuid);
|
||
|
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
|
||
|
index 8ee478b..fdad153 100644
|
||
|
--- a/utils/gssd/gssd.c
|
||
|
+++ b/utils/gssd/gssd.c
|
||
|
@@ -54,6 +54,7 @@
|
||
|
#include "err_util.h"
|
||
|
#include "gss_util.h"
|
||
|
#include "krb5_util.h"
|
||
|
+#include "nfslib.h"
|
||
|
|
||
|
char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
|
||
|
char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
|
||
|
@@ -63,6 +64,7 @@ int use_memcache = 0;
|
||
|
int root_uses_machine_creds = 1;
|
||
|
unsigned int context_timeout = 0;
|
||
|
char *preferred_realm = NULL;
|
||
|
+int pipefds[2] = { -1, -1 };
|
||
|
|
||
|
void
|
||
|
sig_die(int signal)
|
||
|
@@ -187,8 +189,8 @@ main(int argc, char *argv[])
|
||
|
if (gssd_check_mechs() != 0)
|
||
|
errx(1, "Problem with gssapi library");
|
||
|
|
||
|
- if (!fg && daemon(0, 0) < 0)
|
||
|
- errx(1, "fork");
|
||
|
+ if (!fg)
|
||
|
+ mydaemon(0, 0, pipefds);
|
||
|
|
||
|
signal(SIGINT, sig_die);
|
||
|
signal(SIGTERM, sig_die);
|
||
|
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
|
||
|
index 86472a1..56a18d6 100644
|
||
|
--- a/utils/gssd/gssd.h
|
||
|
+++ b/utils/gssd/gssd.h
|
||
|
@@ -67,12 +67,14 @@ extern int use_memcache;
|
||
|
extern int root_uses_machine_creds;
|
||
|
extern unsigned int context_timeout;
|
||
|
extern char *preferred_realm;
|
||
|
+extern int pipefds[2];
|
||
|
|
||
|
TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list;
|
||
|
|
||
|
struct clnt_info {
|
||
|
TAILQ_ENTRY(clnt_info) list;
|
||
|
char *dirname;
|
||
|
+ char *pdir;
|
||
|
int dir_fd;
|
||
|
char *servicename;
|
||
|
char *servername;
|
||
|
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
|
||
|
index ccf7fe5..9970028 100644
|
||
|
--- a/utils/gssd/gssd_main_loop.c
|
||
|
+++ b/utils/gssd/gssd_main_loop.c
|
||
|
@@ -53,6 +53,7 @@
|
||
|
|
||
|
#include "gssd.h"
|
||
|
#include "err_util.h"
|
||
|
+#include "nfslib.h"
|
||
|
|
||
|
extern struct pollfd *pollarray;
|
||
|
extern unsigned long pollsize;
|
||
|
@@ -245,6 +246,9 @@ gssd_run()
|
||
|
/* Error msg is already printed */
|
||
|
exit(1);
|
||
|
}
|
||
|
+
|
||
|
+ /* release the parent after the initial dir scan */
|
||
|
+ release_parent(pipefds);
|
||
|
}
|
||
|
gssd_poll(pollarray, pollsize);
|
||
|
}
|
||
|
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
|
||
|
index b48d163..33cfeb2 100644
|
||
|
--- a/utils/gssd/gssd_proc.c
|
||
|
+++ b/utils/gssd/gssd_proc.c
|
||
|
@@ -256,6 +256,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
|
||
|
if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
|
||
|
goto fail;
|
||
|
close(fd);
|
||
|
+ fd = -1;
|
||
|
buf[nbytes] = '\0';
|
||
|
|
||
|
numfields = sscanf(buf,"RPC server: %127s\n"
|
||
|
@@ -322,6 +323,7 @@ destroy_client(struct clnt_info *clp)
|
||
|
if (clp->krb5_fd != -1) close(clp->krb5_fd);
|
||
|
if (clp->gssd_fd != -1) close(clp->gssd_fd);
|
||
|
free(clp->dirname);
|
||
|
+ free(clp->pdir);
|
||
|
free(clp->servicename);
|
||
|
free(clp->servername);
|
||
|
free(clp->protocol);
|
||
|
@@ -403,11 +405,10 @@ process_clnt_dir_files(struct clnt_info * clp)
|
||
|
return -1;
|
||
|
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
|
||
|
clp->dirname);
|
||
|
- if ((clp->servicename == NULL) &&
|
||
|
- read_service_info(info_file_name, &clp->servicename,
|
||
|
- &clp->servername, &clp->prog, &clp->vers,
|
||
|
- &clp->protocol, (struct sockaddr *) &clp->addr))
|
||
|
- return -1;
|
||
|
+ if (clp->prog == 0)
|
||
|
+ read_service_info(info_file_name, &clp->servicename,
|
||
|
+ &clp->servername, &clp->prog, &clp->vers,
|
||
|
+ &clp->protocol, (struct sockaddr *) &clp->addr);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -463,6 +464,9 @@ process_clnt_dir(char *dir, char *pdir)
|
||
|
if (!(clp = insert_new_clnt()))
|
||
|
goto fail_destroy_client;
|
||
|
|
||
|
+ if (!(clp->pdir = strdup(pdir)))
|
||
|
+ goto fail_destroy_client;
|
||
|
+
|
||
|
/* An extra for the '/', and an extra for the null */
|
||
|
if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
|
||
|
goto fail_destroy_client;
|
||
|
@@ -527,7 +531,7 @@ update_old_clients(struct dirent **namelist, int size, char *pdir)
|
||
|
/* only compare entries in the global list that are from the
|
||
|
* same pipefs parent directory as "pdir"
|
||
|
*/
|
||
|
- if (strcmp(clp->dirname, pdir) != 0) continue;
|
||
|
+ if (strcmp(clp->pdir, pdir) != 0) continue;
|
||
|
|
||
|
stillhere = 0;
|
||
|
for (i=0; i < size; i++) {
|
||
|
@@ -1040,7 +1044,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
||
|
return;
|
||
|
default:
|
||
|
/* Parent: just wait on child to exit and return */
|
||
|
- wait(&err);
|
||
|
+ do {
|
||
|
+ pid = wait(&err);
|
||
|
+ } while(pid == -1 && errno != -ECHILD);
|
||
|
+
|
||
|
if (WIFSIGNALED(err))
|
||
|
printerr(0, "WARNING: forked child was killed with signal %d\n",
|
||
|
WTERMSIG(err));
|
||
|
@@ -1088,7 +1095,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
||
|
|
||
|
/* Tell krb5 gss which credentials cache to use */
|
||
|
/* Try first to acquire credentials directly via GSSAPI */
|
||
|
- err = gssd_acquire_user_cred(uid, &gss_cred);
|
||
|
+ err = gssd_acquire_user_cred(&gss_cred);
|
||
|
if (!err)
|
||
|
create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid,
|
||
|
AUTHTYPE_KRB5, gss_cred);
|
||
|
@@ -1320,11 +1327,14 @@ handle_gssd_upcall(struct clnt_info *clp)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (strcmp(mech, "krb5") == 0)
|
||
|
+ if (strcmp(mech, "krb5") == 0 && clp->servername)
|
||
|
process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
|
||
|
- else
|
||
|
- printerr(0, "WARNING: handle_gssd_upcall: "
|
||
|
- "received unknown gss mech '%s'\n", mech);
|
||
|
+ else {
|
||
|
+ if (clp->servername)
|
||
|
+ printerr(0, "WARNING: handle_gssd_upcall: "
|
||
|
+ "received unknown gss mech '%s'\n", mech);
|
||
|
+ do_error_downcall(clp->gssd_fd, uid, -EACCES);
|
||
|
+ }
|
||
|
|
||
|
out:
|
||
|
free(lbuf);
|
||
|
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
|
||
|
index 697d1d2..208c72b 100644
|
||
|
--- a/utils/gssd/krb5_util.c
|
||
|
+++ b/utils/gssd/krb5_util.c
|
||
|
@@ -1359,12 +1359,12 @@ gssd_k5_get_default_realm(char **def_realm)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-gssd_acquire_krb5_cred(gss_name_t name, gss_cred_id_t *gss_cred)
|
||
|
+gssd_acquire_krb5_cred(gss_cred_id_t *gss_cred)
|
||
|
{
|
||
|
OM_uint32 maj_stat, min_stat;
|
||
|
gss_OID_set_desc desired_mechs = { 1, &krb5oid };
|
||
|
|
||
|
- maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE,
|
||
|
+ maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE,
|
||
|
&desired_mechs, GSS_C_INITIATE,
|
||
|
gss_cred, NULL, NULL);
|
||
|
|
||
|
@@ -1379,31 +1379,12 @@ gssd_acquire_krb5_cred(gss_name_t name, gss_cred_id_t *gss_cred)
|
||
|
}
|
||
|
|
||
|
int
|
||
|
-gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred)
|
||
|
+gssd_acquire_user_cred(gss_cred_id_t *gss_cred)
|
||
|
{
|
||
|
- OM_uint32 maj_stat, min_stat;
|
||
|
- gss_buffer_desc name_buf;
|
||
|
- gss_name_t name;
|
||
|
- char buf[11];
|
||
|
+ OM_uint32 min_stat;
|
||
|
int ret;
|
||
|
|
||
|
- ret = snprintf(buf, 11, "%u", uid);
|
||
|
- if (ret < 1 || ret > 10) {
|
||
|
- return -1;
|
||
|
- }
|
||
|
- name_buf.value = buf;
|
||
|
- name_buf.length = ret + 1;
|
||
|
-
|
||
|
- maj_stat = gss_import_name(&min_stat, &name_buf,
|
||
|
- GSS_C_NT_STRING_UID_NAME, &name);
|
||
|
- if (maj_stat != GSS_S_COMPLETE) {
|
||
|
- if (get_verbosity() > 0)
|
||
|
- pgsserr("gss_import_name",
|
||
|
- maj_stat, min_stat, &krb5oid);
|
||
|
- return -1;
|
||
|
- }
|
||
|
-
|
||
|
- ret = gssd_acquire_krb5_cred(name, gss_cred);
|
||
|
+ ret = gssd_acquire_krb5_cred(gss_cred);
|
||
|
|
||
|
/* force validation of cred to check for expiry */
|
||
|
if (ret == 0) {
|
||
|
@@ -1412,7 +1393,6 @@ gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred)
|
||
|
ret = -1;
|
||
|
}
|
||
|
|
||
|
- maj_stat = gss_release_name(&min_stat, &name);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -1443,7 +1423,7 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec)
|
||
|
int err = -1;
|
||
|
|
||
|
if (sec->cred == GSS_C_NO_CREDENTIAL) {
|
||
|
- err = gssd_acquire_krb5_cred(GSS_C_NO_NAME, &sec->cred);
|
||
|
+ err = gssd_acquire_krb5_cred(&sec->cred);
|
||
|
if (err)
|
||
|
return -1;
|
||
|
}
|
||
|
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
|
||
|
index 3f0723e..a319588 100644
|
||
|
--- a/utils/gssd/krb5_util.h
|
||
|
+++ b/utils/gssd/krb5_util.h
|
||
|
@@ -35,7 +35,7 @@ int gssd_refresh_krb5_machine_credential(char *hostname,
|
||
|
char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
|
||
|
void gssd_k5_get_default_realm(char **def_realm);
|
||
|
|
||
|
-int gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred);
|
||
|
+int gssd_acquire_user_cred(gss_cred_id_t *gss_cred);
|
||
|
|
||
|
#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
extern int limit_to_legacy_enctypes;
|
||
|
diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c
|
||
|
index 8aee3b2..0385725 100644
|
||
|
--- a/utils/gssd/svcgssd.c
|
||
|
+++ b/utils/gssd/svcgssd.c
|
||
|
@@ -62,91 +62,7 @@
|
||
|
#include "gss_util.h"
|
||
|
#include "err_util.h"
|
||
|
|
||
|
-/*
|
||
|
- * mydaemon creates a pipe between the partent and child
|
||
|
- * process. The parent process will wait until the
|
||
|
- * child dies or writes a '1' on the pipe signaling
|
||
|
- * that it started successfully.
|
||
|
- */
|
||
|
-int pipefds[2] = { -1, -1};
|
||
|
-
|
||
|
-static void
|
||
|
-mydaemon(int nochdir, int noclose)
|
||
|
-{
|
||
|
- int pid, status, tempfd;
|
||
|
-
|
||
|
- if (pipe(pipefds) < 0) {
|
||
|
- printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n",
|
||
|
- errno, strerror(errno));
|
||
|
- exit(1);
|
||
|
- }
|
||
|
- if ((pid = fork ()) < 0) {
|
||
|
- printerr(1, "mydaemon: fork() failed: errno %d (%s)\n",
|
||
|
- errno, strerror(errno));
|
||
|
- exit(1);
|
||
|
- }
|
||
|
-
|
||
|
- if (pid != 0) {
|
||
|
- /*
|
||
|
- * Parent. Wait for status from child.
|
||
|
- */
|
||
|
- close(pipefds[1]);
|
||
|
- if (read(pipefds[0], &status, 1) != 1)
|
||
|
- exit(1);
|
||
|
- exit (0);
|
||
|
- }
|
||
|
- /* Child. */
|
||
|
- close(pipefds[0]);
|
||
|
- setsid ();
|
||
|
- if (nochdir == 0) {
|
||
|
- if (chdir ("/") == -1) {
|
||
|
- printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n",
|
||
|
- errno, strerror(errno));
|
||
|
- exit(1);
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- while (pipefds[1] <= 2) {
|
||
|
- pipefds[1] = dup(pipefds[1]);
|
||
|
- if (pipefds[1] < 0) {
|
||
|
- printerr(1, "mydaemon: dup() failed: errno %d (%s)\n",
|
||
|
- errno, strerror(errno));
|
||
|
- exit(1);
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- if (noclose == 0) {
|
||
|
- tempfd = open("/dev/null", O_RDWR);
|
||
|
- if (tempfd >= 0) {
|
||
|
- dup2(tempfd, 0);
|
||
|
- dup2(tempfd, 1);
|
||
|
- dup2(tempfd, 2);
|
||
|
- close(tempfd);
|
||
|
- } else {
|
||
|
- printerr(1, "mydaemon: can't open /dev/null: errno %d "
|
||
|
- "(%s)\n", errno, strerror(errno));
|
||
|
- exit(1);
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- return;
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-release_parent(void)
|
||
|
-{
|
||
|
- int status;
|
||
|
-
|
||
|
- if (pipefds[1] > 0) {
|
||
|
- if (write(pipefds[1], &status, 1) != 1) {
|
||
|
- printerr(1,
|
||
|
- "WARN: writing to parent pipe failed: errno %d (%s)\n",
|
||
|
- errno, strerror(errno));
|
||
|
- }
|
||
|
- close(pipefds[1]);
|
||
|
- pipefds[1] = -1;
|
||
|
- }
|
||
|
-}
|
||
|
+static int pipefds[2] = { -1, -1 };
|
||
|
|
||
|
void
|
||
|
sig_die(int signal)
|
||
|
@@ -242,7 +158,7 @@ main(int argc, char *argv[])
|
||
|
}
|
||
|
|
||
|
if (!fg)
|
||
|
- mydaemon(0, 0);
|
||
|
+ mydaemon(0, 0, pipefds);
|
||
|
|
||
|
signal(SIGINT, sig_die);
|
||
|
signal(SIGTERM, sig_die);
|
||
|
@@ -272,7 +188,7 @@ main(int argc, char *argv[])
|
||
|
}
|
||
|
|
||
|
if (!fg)
|
||
|
- release_parent();
|
||
|
+ release_parent(pipefds);
|
||
|
|
||
|
nfs4_init_name_mapping(NULL); /* XXX: should only do this once */
|
||
|
gssd_run();
|
||
|
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
|
||
|
index b6c6231..c02849b 100644
|
||
|
--- a/utils/idmapd/idmapd.c
|
||
|
+++ b/utils/idmapd/idmapd.c
|
||
|
@@ -157,9 +157,6 @@ static int nfsdopenone(struct idmap_client *);
|
||
|
static void nfsdreopen_one(struct idmap_client *);
|
||
|
static void nfsdreopen(void);
|
||
|
|
||
|
-void mydaemon(int, int);
|
||
|
-void release_parent(void);
|
||
|
-
|
||
|
static int verbose = 0;
|
||
|
#define DEFAULT_IDMAP_CACHE_EXPIRY 600 /* seconds */
|
||
|
static int cache_entry_expiration = 0;
|
||
|
@@ -167,6 +164,7 @@ static char pipefsdir[PATH_MAX];
|
||
|
static char *nobodyuser, *nobodygroup;
|
||
|
static uid_t nobodyuid;
|
||
|
static gid_t nobodygid;
|
||
|
+static int pipefds[2] = { -1, -1 };
|
||
|
|
||
|
/* Used by conffile.c in libnfs.a */
|
||
|
char *conf_path;
|
||
|
@@ -305,7 +303,7 @@ main(int argc, char **argv)
|
||
|
errx(1, "Unable to create name to user id mappings.");
|
||
|
|
||
|
if (!fg)
|
||
|
- mydaemon(0, 0);
|
||
|
+ mydaemon(0, 0, pipefds);
|
||
|
|
||
|
event_init();
|
||
|
|
||
|
@@ -382,7 +380,7 @@ main(int argc, char **argv)
|
||
|
if (nfsdret != 0 && fd == 0)
|
||
|
xlog_err("main: Neither NFS client nor NFSd found");
|
||
|
|
||
|
- release_parent();
|
||
|
+ release_parent(pipefds);
|
||
|
|
||
|
if (event_dispatch() < 0)
|
||
|
xlog_err("main: event_dispatch returns errno %d (%s)",
|
||
|
@@ -929,77 +927,3 @@ getfield(char **bpp, char *fld, size_t fldsz)
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
-/*
|
||
|
- * mydaemon creates a pipe between the partent and child
|
||
|
- * process. The parent process will wait until the
|
||
|
- * child dies or writes a '1' on the pipe signaling
|
||
|
- * that it started successfully.
|
||
|
- */
|
||
|
-int pipefds[2] = { -1, -1};
|
||
|
-
|
||
|
-void
|
||
|
-mydaemon(int nochdir, int noclose)
|
||
|
-{
|
||
|
- int pid, status, tempfd;
|
||
|
-
|
||
|
- if (pipe(pipefds) < 0)
|
||
|
- err(1, "mydaemon: pipe() failed: errno %d", errno);
|
||
|
-
|
||
|
- if ((pid = fork ()) < 0)
|
||
|
- err(1, "mydaemon: fork() failed: errno %d", errno);
|
||
|
-
|
||
|
- if (pid != 0) {
|
||
|
- /*
|
||
|
- * Parent. Wait for status from child.
|
||
|
- */
|
||
|
- close(pipefds[1]);
|
||
|
- if (read(pipefds[0], &status, 1) != 1)
|
||
|
- exit(1);
|
||
|
- exit (0);
|
||
|
- }
|
||
|
- /* Child. */
|
||
|
- close(pipefds[0]);
|
||
|
- setsid ();
|
||
|
- if (nochdir == 0) {
|
||
|
- if (chdir ("/") == -1)
|
||
|
- err(1, "mydaemon: chdir() failed: errno %d", errno);
|
||
|
- }
|
||
|
-
|
||
|
- while (pipefds[1] <= 2) {
|
||
|
- pipefds[1] = dup(pipefds[1]);
|
||
|
- if (pipefds[1] < 0)
|
||
|
- err(1, "mydaemon: dup() failed: errno %d", errno);
|
||
|
- }
|
||
|
-
|
||
|
- if (noclose == 0) {
|
||
|
- tempfd = open("/dev/null", O_RDWR);
|
||
|
- if (tempfd < 0)
|
||
|
- tempfd = open("/", O_RDONLY);
|
||
|
- if (tempfd >= 0) {
|
||
|
- dup2(tempfd, 0);
|
||
|
- dup2(tempfd, 1);
|
||
|
- dup2(tempfd, 2);
|
||
|
- close(tempfd);
|
||
|
- } else {
|
||
|
- err(1, "mydaemon: can't open /dev/null: errno %d",
|
||
|
- errno);
|
||
|
- exit(1);
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- return;
|
||
|
-}
|
||
|
-void
|
||
|
-release_parent(void)
|
||
|
-{
|
||
|
- int status;
|
||
|
-
|
||
|
- if (pipefds[1] > 0) {
|
||
|
- if (write(pipefds[1], &status, 1) != 1) {
|
||
|
- err(1, "Writing to parent pipe failed: errno %d (%s)\n",
|
||
|
- errno, strerror(errno));
|
||
|
- }
|
||
|
- close(pipefds[1]);
|
||
|
- pipefds[1] = -1;
|
||
|
- }
|
||
|
-}
|
||
|
diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man
|
||
|
index 58ea9f2..185cd1b 100644
|
||
|
--- a/utils/idmapd/idmapd.man
|
||
|
+++ b/utils/idmapd/idmapd.man
|
||
|
@@ -12,10 +12,7 @@
|
||
|
.Nm rpc.idmapd
|
||
|
.Op Fl v
|
||
|
.Op Fl f
|
||
|
-.Op Fl d Ar domain
|
||
|
.Op Fl p Ar path
|
||
|
-.Op Fl U Ar username
|
||
|
-.Op Fl G Ar groupname
|
||
|
.Op Fl c Ar path
|
||
|
.Sh DESCRIPTION
|
||
|
.Nm
|
||
|
@@ -31,25 +28,10 @@ Increases the verbosity level (can be specified multiple times).
|
||
|
Runs
|
||
|
.Nm
|
||
|
in the foreground and prints all output to the terminal.
|
||
|
-.It Fl d Ar domain
|
||
|
-Set domain to
|
||
|
-.Ar domain .
|
||
|
-This is used internally by NFSv4 and is typically assigned by the
|
||
|
-system administrator. By default,
|
||
|
-.Ar domain
|
||
|
-is set to be the FQDN of the host, minus the hostname.
|
||
|
.It Fl p Ar path
|
||
|
Specifies the location of the RPC pipefs to be
|
||
|
.Ar path .
|
||
|
The default value is \&"/var/lib/nfs/rpc_pipefs\&".
|
||
|
-.It Fl U Ar username
|
||
|
-Specifies the NFSv4 nobody user to be
|
||
|
-.Ar username .
|
||
|
-The default value is \&"nobody\&".
|
||
|
-.It Fl G Ar groupname
|
||
|
-Specifies the NFSv4 nobody group to be
|
||
|
-.Ar groupname .
|
||
|
-The default value is \&"nobody\&".
|
||
|
.It Fl c Ar path
|
||
|
Use configuration file
|
||
|
.Ar path .
|
||
|
@@ -59,11 +41,11 @@ Client-only: perform no idmapping for any NFS server, even if one is detected.
|
||
|
Server-only: perform no idmapping for any NFS client, even if one is detected.
|
||
|
.El
|
||
|
.Sh EXAMPLES
|
||
|
-.Cm rpc.idmapd -d \&"citi.umich.edu\&" -f -vvv
|
||
|
+.Cm rpc.idmapd -f -vvv
|
||
|
.Pp
|
||
|
Runs
|
||
|
.Nm
|
||
|
-with the domain \&"citi.umich.edu\&" in the foreground, printing all
|
||
|
+printing all
|
||
|
messages to console, and with a verbosity level of 3.
|
||
|
.\" This next request is for sections 2 and 3 function return values only.
|
||
|
.\" .Sh RETURN VALUES
|
||
|
diff --git a/utils/mount/network.c b/utils/mount/network.c
|
||
|
index e8e55a5..2fdd2c0 100644
|
||
|
--- a/utils/mount/network.c
|
||
|
+++ b/utils/mount/network.c
|
||
|
@@ -92,6 +92,9 @@ static const char *nfs_version_opttbl[] = {
|
||
|
"v4",
|
||
|
"vers",
|
||
|
"nfsvers",
|
||
|
+ "v4.0",
|
||
|
+ "v4.1",
|
||
|
+ "v4.2",
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
@@ -1242,6 +1245,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
|
||
|
*version = tmp;
|
||
|
return 1;
|
||
|
}
|
||
|
+ nfs_error(_("%s: parsing error on 'vers=' option\n"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
case PO_NOT_FOUND:
|
||
|
nfs_error(_("%s: parsing error on 'vers=' option\n"),
|
||
|
@@ -1259,6 +1264,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
|
||
|
*version = tmp;
|
||
|
return 1;
|
||
|
}
|
||
|
+ nfs_error(_("%s: parsing error on 'nfsvers=' option\n"),
|
||
|
+ progname);
|
||
|
return 0;
|
||
|
case PO_NOT_FOUND:
|
||
|
nfs_error(_("%s: parsing error on 'nfsvers=' option\n"),
|
||
|
@@ -1269,6 +1276,11 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
|
||
|
progname);
|
||
|
return 0;
|
||
|
}
|
||
|
+ case 5: /* v4.0 */
|
||
|
+ case 6: /* v4.1 */
|
||
|
+ case 7: /* v4.2 */
|
||
|
+ *version = 4;
|
||
|
+ return 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
|
||
|
index 67031b5..ef09a31 100644
|
||
|
--- a/utils/mount/nfs.man
|
||
|
+++ b/utils/mount/nfs.man
|
||
|
@@ -288,6 +288,8 @@ attributes of a regular file before it requests
|
||
|
fresh attribute information from a server.
|
||
|
If this option is not specified, the NFS client uses
|
||
|
a 3-second minimum.
|
||
|
+See the DATA AND METADATA COHERENCE section
|
||
|
+for a full discussion of attribute caching.
|
||
|
.TP 1.5i
|
||
|
.BI acregmax= n
|
||
|
The maximum time (in seconds) that the NFS client caches
|
||
|
@@ -295,6 +297,8 @@ attributes of a regular file before it requests
|
||
|
fresh attribute information from a server.
|
||
|
If this option is not specified, the NFS client uses
|
||
|
a 60-second maximum.
|
||
|
+See the DATA AND METADATA COHERENCE section
|
||
|
+for a full discussion of attribute caching.
|
||
|
.TP 1.5i
|
||
|
.BI acdirmin= n
|
||
|
The minimum time (in seconds) that the NFS client caches
|
||
|
@@ -302,6 +306,8 @@ attributes of a directory before it requests
|
||
|
fresh attribute information from a server.
|
||
|
If this option is not specified, the NFS client uses
|
||
|
a 30-second minimum.
|
||
|
+See the DATA AND METADATA COHERENCE section
|
||
|
+for a full discussion of attribute caching.
|
||
|
.TP 1.5i
|
||
|
.BI acdirmax= n
|
||
|
The maximum time (in seconds) that the NFS client caches
|
||
|
@@ -309,6 +315,8 @@ attributes of a directory before it requests
|
||
|
fresh attribute information from a server.
|
||
|
If this option is not specified, the NFS client uses
|
||
|
a 60-second maximum.
|
||
|
+See the DATA AND METADATA COHERENCE section
|
||
|
+for a full discussion of attribute caching.
|
||
|
.TP 1.5i
|
||
|
.BI actimeo= n
|
||
|
Using
|
||
|
@@ -856,6 +864,26 @@ 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.
|
||
|
+.TP 1.5i
|
||
|
+.BR migration " / " nomigration
|
||
|
+Selects whether the client uses an identification string that is compatible
|
||
|
+with NFSv4 Transparent State Migration (TSM).
|
||
|
+If the mounted server supports NFSv4 migration with TSM, specify the
|
||
|
+.B migration
|
||
|
+option.
|
||
|
+.IP
|
||
|
+Some server features misbehave in the face of a migration-compatible
|
||
|
+identification string.
|
||
|
+The
|
||
|
+.B nomigration
|
||
|
+option retains the use of a traditional client indentification string
|
||
|
+which is compatible with legacy NFS servers.
|
||
|
+This is also the behavior if neither option is specified.
|
||
|
+A client's open and lock state cannot be migrated transparently
|
||
|
+when it identifies itself via a traditional identification string.
|
||
|
+.IP
|
||
|
+This mount option has no effect with NFSv4 minor versions newer than zero,
|
||
|
+which always use TSM-compatible client identification strings.
|
||
|
.SH nfs4 FILE SYSTEM TYPE
|
||
|
The
|
||
|
.BR nfs4
|
||
|
@@ -1161,24 +1189,33 @@ perfect cache coherence among their clients.
|
||
|
Perfect cache coherence among disparate NFS clients
|
||
|
is expensive to achieve, especially on wide area networks.
|
||
|
As such, NFS settles for weaker cache coherence that
|
||
|
-satisfies the requirements of most file sharing types. Normally,
|
||
|
-file sharing is completely sequential:
|
||
|
-first client A opens a file, writes something to it, then closes it;
|
||
|
-then client B opens the same file, and reads the changes.
|
||
|
-.DT
|
||
|
+satisfies the requirements of most file sharing types.
|
||
|
.SS "Close-to-open cache consistency"
|
||
|
-When an application opens a file stored on an NFS server,
|
||
|
-the NFS client checks that it still exists on the server
|
||
|
+Typically file sharing is completely sequential.
|
||
|
+First client A opens a file, writes something to it, then closes it.
|
||
|
+Then client B opens the same file, and reads the changes.
|
||
|
+.P
|
||
|
+When an application opens a file stored on an NFS version 3 server,
|
||
|
+the NFS client checks that the file exists on the server
|
||
|
and is permitted to the opener by sending a GETATTR or ACCESS request.
|
||
|
+The NFS client sends these requests
|
||
|
+regardless of the freshness of the file's cached attributes.
|
||
|
+.P
|
||
|
When the application closes the file,
|
||
|
the NFS client writes back any pending changes
|
||
|
to the file so that the next opener can view the changes.
|
||
|
This also gives the NFS client an opportunity to report
|
||
|
-any server write errors to the application
|
||
|
-via the return code from
|
||
|
+write errors to the application via the return code from
|
||
|
.BR close (2).
|
||
|
+.P
|
||
|
The behavior of checking at open time and flushing at close time
|
||
|
-is referred to as close-to-open cache consistency.
|
||
|
+is referred to as
|
||
|
+.IR "close-to-open cache consistency" ,
|
||
|
+or
|
||
|
+.IR CTO .
|
||
|
+It can be disabled for an entire mount point using the
|
||
|
+.B nocto
|
||
|
+mount option.
|
||
|
.SS "Weak cache consistency"
|
||
|
There are still opportunities for a client's data cache
|
||
|
to contain stale data.
|
||
|
@@ -1227,6 +1264,65 @@ If absolute cache coherence among clients is required,
|
||
|
applications should use file locking. Alternatively, applications
|
||
|
can also open their files with the O_DIRECT flag
|
||
|
to disable data caching entirely.
|
||
|
+.SS "File timestamp maintainence"
|
||
|
+NFS servers are responsible for managing file and directory timestamps
|
||
|
+.RB ( atime ,
|
||
|
+.BR ctime ", and"
|
||
|
+.BR mtime ).
|
||
|
+When a file is accessed or updated on an NFS server,
|
||
|
+the file's timestamps are updated just like they would be on a filesystem
|
||
|
+local to an application.
|
||
|
+.P
|
||
|
+NFS clients cache file attributes, including timestamps.
|
||
|
+A file's timestamps are updated on NFS clients when its attributes
|
||
|
+are retrieved from the NFS server.
|
||
|
+Thus there may be some delay before timestamp updates
|
||
|
+on an NFS server appear to applications on NFS clients.
|
||
|
+.P
|
||
|
+To comply with the POSIX filesystem standard, the Linux NFS client
|
||
|
+relies on NFS servers to keep a file's
|
||
|
+.B mtime
|
||
|
+and
|
||
|
+.B ctime
|
||
|
+timestamps properly up to date.
|
||
|
+It does this by flushing local data changes to the server
|
||
|
+before reporting
|
||
|
+.B mtime
|
||
|
+to applications via system calls such as
|
||
|
+.BR stat (2).
|
||
|
+.P
|
||
|
+The Linux client handles
|
||
|
+.B atime
|
||
|
+updates more loosely, however.
|
||
|
+NFS clients maintain good performance by caching data,
|
||
|
+but that means that application reads, which normally update
|
||
|
+.BR atime ,
|
||
|
+are not reflected to the server where a file's
|
||
|
+.B atime
|
||
|
+is actually maintained.
|
||
|
+.P
|
||
|
+Because of this caching behavior,
|
||
|
+the Linux NFS client does not support generic atime-related mount options.
|
||
|
+See
|
||
|
+.BR mount (8)
|
||
|
+for details on these options.
|
||
|
+.P
|
||
|
+In particular, the
|
||
|
+.BR atime / noatime ,
|
||
|
+.BR diratime / nodiratime ,
|
||
|
+.BR relatime / norelatime ,
|
||
|
+and
|
||
|
+.BR strictatime / nostrictatime
|
||
|
+mount options have no effect on NFS mounts.
|
||
|
+.P
|
||
|
+.I /proc/mounts
|
||
|
+may report that the
|
||
|
+.B relatime
|
||
|
+mount option is set on NFS mounts, but in fact the
|
||
|
+.B atime
|
||
|
+semantics are always as described here, and are not like
|
||
|
+.B relatime
|
||
|
+semantics.
|
||
|
.SS "Directory entry caching"
|
||
|
The Linux NFS client caches the result of all NFS LOOKUP requests.
|
||
|
If the requested directory entry exists on the server,
|
||
|
diff --git a/utils/mount/utils.c b/utils/mount/utils.c
|
||
|
index 2778ed7..ede77a8 100644
|
||
|
--- a/utils/mount/utils.c
|
||
|
+++ b/utils/mount/utils.c
|
||
|
@@ -93,7 +93,7 @@ void print_one(char *spec, char *node, char *type, char *opts)
|
||
|
|
||
|
void mount_usage(void)
|
||
|
{
|
||
|
- printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
|
||
|
+ printf(_("usage: %s remotetarget dir [-rvVwfnsh] [-o nfsoptions]\n"),
|
||
|
progname);
|
||
|
printf(_("options:\n"));
|
||
|
printf(_("\t-r\t\tMount file system readonly\n"));
|
||
|
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
|
||
|
index e04b86e..ca35de2 100644
|
||
|
--- a/utils/mountd/cache.c
|
||
|
+++ b/utils/mountd/cache.c
|
||
|
@@ -266,6 +266,27 @@ static int get_uuid(const char *val, size_t uuidlen, char *u)
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+/*
|
||
|
+ * Don't ask libblkid for these filesystems. Note that BTRF is ignored, because
|
||
|
+ * we generate the identifier from statfs->f_fsid. The rest are network or
|
||
|
+ * pseudo filesystems. (See <linux/magic.h> for the basic IDs.)
|
||
|
+ */
|
||
|
+static const long int nonblkid_filesystems[] = {
|
||
|
+ 0x2fc12fc1, /* ZFS_SUPER_MAGIC */
|
||
|
+ 0x9123683E, /* BTRFS_SUPER_MAGIC */
|
||
|
+ 0xFF534D42, /* CIFS_MAGIC_NUMBER */
|
||
|
+ 0x1373, /* DEVFS_SUPER_MAGIC */
|
||
|
+ 0x73757245, /* CODA_SUPER_MAGIC */
|
||
|
+ 0x564C, /* NCP_SUPER_MAGIC */
|
||
|
+ 0x6969, /* NFS_SUPER_MAGIC */
|
||
|
+ 0x9FA0, /* PROC_SUPER_MAGIC */
|
||
|
+ 0x62656572, /* SYSFS_MAGIC */
|
||
|
+ 0x517B, /* SMB_SUPER_MAGIC */
|
||
|
+ 0x01021994, /* TMPFS_SUPER_MAGIC */
|
||
|
+ 0 /* last */
|
||
|
+};
|
||
|
+
|
||
|
static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid)
|
||
|
{
|
||
|
/* get a uuid for the filesystem found at 'path'.
|
||
|
@@ -297,12 +318,23 @@ static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid)
|
||
|
*/
|
||
|
struct statfs64 st;
|
||
|
char fsid_val[17];
|
||
|
- const char *blkid_val;
|
||
|
+ const char *blkid_val = NULL;
|
||
|
const char *val;
|
||
|
+ int rc;
|
||
|
|
||
|
- blkid_val = get_uuid_blkdev(path);
|
||
|
+ rc = statfs64(path, &st);
|
||
|
+
|
||
|
+ if (type == 0 && rc == 0) {
|
||
|
+ const long int *bad;
|
||
|
+ for (bad = nonblkid_filesystems; *bad; bad++) {
|
||
|
+ if (*bad == st.f_type)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (*bad == 0)
|
||
|
+ blkid_val = get_uuid_blkdev(path);
|
||
|
+ }
|
||
|
|
||
|
- if (statfs64(path, &st) == 0 &&
|
||
|
+ if (rc == 0 &&
|
||
|
(st.f_fsid.__val[0] || st.f_fsid.__val[1]))
|
||
|
snprintf(fsid_val, 17, "%08x%08x",
|
||
|
st.f_fsid.__val[0], st.f_fsid.__val[1]);
|
||
|
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
|
||
|
index 6db92f0..a9d77ab 100644
|
||
|
--- a/utils/nfsd/nfsd.c
|
||
|
+++ b/utils/nfsd/nfsd.c
|
||
|
@@ -99,7 +99,7 @@ main(int argc, char **argv)
|
||
|
char *p, *progname, *port;
|
||
|
char *haddr = NULL;
|
||
|
int socket_up = 0;
|
||
|
- int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */
|
||
|
+ int minorvers[NFS4_MAXMINOR + 1] = {0};
|
||
|
unsigned int versbits = NFSCTL_VERDEFAULT;
|
||
|
unsigned int protobits = NFSCTL_ALLBITS;
|
||
|
unsigned int proto4 = 0;
|
||
|
@@ -164,7 +164,7 @@ main(int argc, char **argv)
|
||
|
fprintf(stderr, "%s: unsupported minor version\n", optarg);
|
||
|
exit(1);
|
||
|
}
|
||
|
- NFSCTL_VERUNSET(minorvers, i);
|
||
|
+ minorvers[i] = -1;
|
||
|
break;
|
||
|
}
|
||
|
case 3:
|
||
|
@@ -185,7 +185,7 @@ main(int argc, char **argv)
|
||
|
fprintf(stderr, "%s: unsupported minor version\n", optarg);
|
||
|
exit(1);
|
||
|
}
|
||
|
- NFSCTL_VERSET(minorvers, i);
|
||
|
+ minorvers[i] = 1;
|
||
|
break;
|
||
|
}
|
||
|
case 3:
|
||
|
diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
|
||
|
index 8b85846..1b50aba 100644
|
||
|
--- a/utils/nfsd/nfssvc.c
|
||
|
+++ b/utils/nfsd/nfssvc.c
|
||
|
@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits,
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-nfssvc_setvers(unsigned int ctlbits, int minorvers)
|
||
|
+nfssvc_setvers(unsigned int ctlbits, int minorvers[])
|
||
|
{
|
||
|
int fd, n, off;
|
||
|
char *ptr;
|
||
|
@@ -281,9 +281,9 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers)
|
||
|
return;
|
||
|
|
||
|
for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) {
|
||
|
- if (NFSCTL_VERISSET(minorvers, n))
|
||
|
+ if (minorvers[n] == 1)
|
||
|
off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n);
|
||
|
- else
|
||
|
+ else if (minorvers[n] == -1)
|
||
|
off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n);
|
||
|
}
|
||
|
for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
|
||
|
diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h
|
||
|
index 08de0fe..2bbd3d3 100644
|
||
|
--- a/utils/nfsd/nfssvc.h
|
||
|
+++ b/utils/nfsd/nfssvc.h
|
||
|
@@ -24,5 +24,5 @@ void nfssvc_mount_nfsdfs(char *progname);
|
||
|
int nfssvc_inuse(void);
|
||
|
int nfssvc_set_sockets(const int family, const unsigned int protobits,
|
||
|
const char *host, const char *port);
|
||
|
-void nfssvc_setvers(unsigned int ctlbits, int minorvers4);
|
||
|
+void nfssvc_setvers(unsigned int ctlbits, int minorvers4[]);
|
||
|
int nfssvc_threads(unsigned short port, int nrservs);
|
||
|
diff --git a/utils/statd/statd.c b/utils/statd/statd.c
|
||
|
index 8c51bcc..8f31111 100644
|
||
|
--- a/utils/statd/statd.c
|
||
|
+++ b/utils/statd/statd.c
|
||
|
@@ -238,12 +238,6 @@ int main (int argc, char **argv)
|
||
|
/* Set hostname */
|
||
|
MY_NAME = NULL;
|
||
|
|
||
|
- /* Refuse to start if another statd is running */
|
||
|
- if (nfs_probe_statd()) {
|
||
|
- fprintf(stderr, "Statd service already running!\n");
|
||
|
- exit(1);
|
||
|
- }
|
||
|
-
|
||
|
/* Process command line switches */
|
||
|
while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) {
|
||
|
switch (arg) {
|
||
|
@@ -306,6 +300,12 @@ int main (int argc, char **argv)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ /* Refuse to start if another statd is running */
|
||
|
+ if (nfs_probe_statd()) {
|
||
|
+ fprintf(stderr, "Statd service already running!\n");
|
||
|
+ exit(1);
|
||
|
+ }
|
||
|
+
|
||
|
if (port == out_port && port != 0) {
|
||
|
fprintf(stderr, "Listening and outgoing ports cannot be the same!\n");
|
||
|
exit(-1);
|