nfs-utils/nfs-utils-2.1.2-rc2.patch
Steve Dickson 49f282cd14 Updated to the latest RC release: nfs-utils-2-1-2-rc2 (bz 1419351)
Signed-off-by: Steve Dickson <steved@redhat.com>
2017-04-10 09:40:23 -04:00

2339 lines
64 KiB
Diff

diff --git a/.gitignore b/.gitignore
index 126d12c..941aca0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,6 +70,7 @@ tests/nsm_client/nlm_sm_inter_svc.c
tests/nsm_client/nlm_sm_inter_xdr.c
utils/nfsidmap/nfsidmap
systemd/nfs-server-generator
+systemd/rpc-pipefs-generator
systemd/nfs-config.service
systemd/rpc-gssd.service
# cscope database files
diff --git a/nfs.conf b/nfs.conf
index 81ece06..0d0ec9b 100644
--- a/nfs.conf
+++ b/nfs.conf
@@ -1,7 +1,10 @@
#
-# This is a general conifguration for the
+# This is a general configuration for the
# NFS daemons and tools
#
+#[general]
+# pipefs-directory=/var/lib/nfs/rpc_pipefs
+#
#[exportfs]
# debug=0
#
@@ -12,7 +15,6 @@
# limit-to-legacy-enctypes=0
# context-timeout=0
# rpc-timeout=5
-# pipefs-directory=/var/lib/nfs/rpc_pipefs
# keytab-file=/etc/krb5.keytab
# cred-cache-directory=
# preferred-realm=
@@ -42,7 +44,7 @@
# port=0
# grace-time=90
# lease-time=90
-# udp=y
+# udp=n
# tcp=y
# vers2=n
# vers3=y
@@ -65,6 +67,7 @@
# retry-time=900
# outgoing-port=
# outgoing-addr=
+# lift-grace=y
#
#[svcgssd]
# principal=
diff --git a/support/export/xtab.c b/support/export/xtab.c
index 22cf539..d42eeef 100644
--- a/support/export/xtab.c
+++ b/support/export/xtab.c
@@ -14,12 +14,20 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <libgen.h>
#include "nfslib.h"
#include "exportfs.h"
#include "xio.h"
#include "xlog.h"
#include "v4root.h"
+#include "misc.h"
+
+static char state_base_dirname[PATH_MAX] = NFS_STATEDIR;
+extern struct state_paths etab;
int v4root_needed;
static void cond_rename(char *newfile, char *oldfile);
@@ -65,7 +73,7 @@ xtab_read(char *xtab, char *lockfn, int is_export)
int
xtab_export_read(void)
{
- return xtab_read(_PATH_ETAB, _PATH_ETABLCK, 1);
+ return xtab_read(etab.statefn, etab.lockfn, 1);
}
/*
@@ -112,7 +120,7 @@ xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export)
int
xtab_export_write()
{
- return xtab_write(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1);
+ return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1);
}
/*
@@ -158,3 +166,74 @@ static void cond_rename(char *newfile, char *oldfile)
rename(newfile, oldfile);
return;
}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs. Caller must free the returned result with free(3).
+ */
+static char *
+state_make_pathname(const char *tabname)
+{
+ return generic_make_pathname(state_base_dirname, tabname);
+}
+
+/**
+ * state_setup_basedir - set up basedir
+ * @progname: C string containing name of program, for error messages
+ * @parentdir: C string containing pathname to on-disk state, or NULL
+ *
+ * This runs before logging is set up, so error messages are directed
+ * to stderr.
+ *
+ * Returns true and sets up our basedir, if @parentdir was valid
+ * and usable; otherwise false is returned.
+ */
+_Bool
+state_setup_basedir(const char *progname, const char *parentdir)
+{
+ return generic_setup_basedir(progname, parentdir, state_base_dirname,
+ PATH_MAX);
+}
+
+int
+setup_state_path_names(const char *progname, const char *statefn,
+ const char *tmpfn, const char *lockfn,
+ struct state_paths *paths)
+{
+ paths->statefn = state_make_pathname(statefn);
+ if (!paths->statefn) {
+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
+ progname, statefn);
+ goto out_err;
+ }
+ paths->tmpfn = state_make_pathname(tmpfn);
+ if (!paths->tmpfn) {
+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
+ progname, tmpfn);
+ goto out_free_statefn;
+ }
+ paths->lockfn = state_make_pathname(lockfn);
+ if (!paths->lockfn) {
+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
+ progname, lockfn);
+ goto out_free_tmpfn;
+ }
+ return 1;
+
+out_free_tmpfn:
+ free(paths->tmpfn);
+out_free_statefn:
+ free(paths->statefn);
+out_err:
+ return 0;
+
+}
+
+void
+free_state_path_names(struct state_paths *paths)
+{
+ free(paths->statefn);
+ free(paths->tmpfn);
+ free(paths->lockfn);
+}
diff --git a/support/include/misc.h b/support/include/misc.h
index eedc1fe..06e2a0c 100644
--- a/support/include/misc.h
+++ b/support/include/misc.h
@@ -15,6 +15,9 @@
int randomkey(unsigned char *keyout, int len);
int weakrandomkey(unsigned char *keyout, int len);
+char *generic_make_pathname(const char *, const char *);
+_Bool generic_setup_basedir(const char *, const char *, char *, const size_t);
+
extern int is_mountpoint(char *path);
/* size of the file pointer buffers for rpc procfs files */
diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h
index 15ecc6b..7933ff5 100644
--- a/support/include/nfs/nfs.h
+++ b/support/include/nfs/nfs.h
@@ -16,8 +16,8 @@
#define NFSD_MINVERS 2
#define NFSD_MAXVERS 4
-#define NFS4_MINMINOR 1
-#define NFS4_MAXMINOR WORD_BIT
+#define NFS4_MINMINOR 0
+#define NFS4_MAXMINOR (WORD_BIT-1)
struct nfs_fh_len {
int fh_size;
@@ -27,21 +27,24 @@ struct nfs_fh_len {
#define NFSCTL_UDPBIT (1 << (17 - 1))
#define NFSCTL_TCPBIT (1 << (18 - 1))
+#define NFSCTL_PROTODEFAULT (NFSCTL_TCPBIT)
#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1)))
+#define NFSCTL_MINORUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v)))
#define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_UDPBIT)
#define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_TCPBIT)
#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1)))
+#define NFSCTL_MINORISSET(_cltbits, _v) ((_cltbits) & (1 << (_v)))
#define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT)
#define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT)
#define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */
#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1)))
+#define NFSCTL_MINORSET(_cltbits, _v) ((_cltbits) |= (1 << (_v)))
#define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT)
#define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT)
#define NFSCTL_ANYPROTO(_cltbits) ((_cltbits) & (NFSCTL_UDPBIT | NFSCTL_TCPBIT))
-#define NFSCTL_ALLBITS (~0)
#endif /* _NFS_NFS_H */
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
index 1498977..ab8b2bf 100644
--- a/support/include/nfslib.h
+++ b/support/include/nfslib.h
@@ -35,29 +35,24 @@
#ifndef _PATH_IDMAPDCONF
#define _PATH_IDMAPDCONF "/etc/idmapd.conf"
#endif
-#ifndef _PATH_ETAB
-#define _PATH_ETAB NFS_STATEDIR "/etab"
-#endif
-#ifndef _PATH_ETABTMP
-#define _PATH_ETABTMP NFS_STATEDIR "/etab.tmp"
-#endif
-#ifndef _PATH_ETABLCK
-#define _PATH_ETABLCK NFS_STATEDIR "/.etab.lock"
-#endif
-#ifndef _PATH_RMTAB
-#define _PATH_RMTAB NFS_STATEDIR "/rmtab"
-#endif
-#ifndef _PATH_RMTABTMP
-#define _PATH_RMTABTMP _PATH_RMTAB ".tmp"
-#endif
-#ifndef _PATH_RMTABLCK
-#define _PATH_RMTABLCK NFS_STATEDIR "/.rmtab.lock"
-#endif
#ifndef _PATH_PROC_EXPORTS
#define _PATH_PROC_EXPORTS "/proc/fs/nfs/exports"
#define _PATH_PROC_EXPORTS_ALT "/proc/fs/nfsd/exports"
#endif
+#define ETAB "etab"
+#define ETABTMP "etab.tmp"
+#define ETABLCK ".etab.lock"
+#define RMTAB "rmtab"
+#define RMTABTMP "rmtab.tmp"
+#define RMTABLCK ".rmtab.lock"
+
+struct state_paths {
+ char *statefn;
+ char *tmpfn;
+ char *lockfn;
+};
+
/* Maximum number of security flavors on an export: */
#define SECFLAVOR_COUNT 8
@@ -120,6 +115,10 @@ void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos);
void fendrmtabent(FILE *fp);
void frewindrmtabent(FILE *fp);
+_Bool state_setup_basedir(const char *, const char *);
+int setup_state_path_names(const char *, const char *, const char *, const char *, struct state_paths *);
+void free_state_path_names(struct state_paths *);
+
/* mydaemon */
void daemon_init(bool fg);
void daemon_ready(void);
diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am
index 1048580..8936b0d 100644
--- a/support/misc/Makefile.am
+++ b/support/misc/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
noinst_LIBRARIES = libmisc.a
-libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c
+libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c
MAINTAINERCLEANFILES = Makefile.in
diff --git a/support/misc/file.c b/support/misc/file.c
new file mode 100644
index 0000000..63597df
--- /dev/null
+++ b/support/misc/file.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2009 Oracle. All rights reserved.
+ * Copyright 2017 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+
+#include <string.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "xlog.h"
+#include "misc.h"
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs. Caller must free the returned result with free(3).
+ */
+__attribute__((__malloc__))
+char *
+generic_make_pathname(const char *base, const char *leaf)
+{
+ size_t size;
+ char *path;
+ int len;
+
+ size = strlen(base) + strlen(leaf) + 2;
+ if (size > PATH_MAX)
+ return NULL;
+
+ path = malloc(size);
+ if (path == NULL)
+ return NULL;
+
+ len = snprintf(path, size, "%s/%s", base, leaf);
+ if ((len < 0) || ((size_t)len >= size)) {
+ free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+
+/**
+ * generic_setup_basedir - set up basedir
+ * @progname: C string containing name of program, for error messages
+ * @parentdir: C string containing pathname to on-disk state, or NULL
+ * @base: character buffer to contain the basedir that is set up
+ * @baselen: size of @base in bytes
+ *
+ * This runs before logging is set up, so error messages are directed
+ * to stderr.
+ *
+ * Returns true and sets up our basedir, if @parentdir was valid
+ * and usable; otherwise false is returned.
+ */
+_Bool
+generic_setup_basedir(const char *progname, const char *parentdir, char *base,
+ const size_t baselen)
+{
+ static char buf[PATH_MAX];
+ struct stat st;
+ char *path;
+
+ /* First: test length of name and whether it exists */
+ if ((strlen(parentdir) >= baselen) || (strlen(parentdir) >= PATH_MAX)) {
+ (void)fprintf(stderr, "%s: Directory name too long: %s",
+ progname, parentdir);
+ return false;
+ }
+ if (lstat(parentdir, &st) == -1) {
+ (void)fprintf(stderr, "%s: Failed to stat %s: %s",
+ progname, parentdir, strerror(errno));
+ return false;
+ }
+
+ /* Ensure we have a clean directory pathname */
+ strncpy(buf, parentdir, sizeof(buf));
+ path = dirname(buf);
+ if (*path == '.') {
+ (void)fprintf(stderr, "%s: Unusable directory %s",
+ progname, parentdir);
+ return false;
+ }
+
+ xlog(D_CALL, "Using %s as the state directory", parentdir);
+ strcpy(base, parentdir);
+ return true;
+}
diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
index e5e2579..9912afa 100644
--- a/support/nfs/cacheio.c
+++ b/support/nfs/cacheio.c
@@ -27,6 +27,8 @@
#include <time.h>
#include <errno.h>
+extern struct state_paths etab;
+
void qword_add(char **bpp, int *lp, char *str)
{
char *bp = *bpp;
@@ -199,7 +201,7 @@ int qword_get_uint(char **bpp, unsigned int *anint)
}
/* flush the kNFSd caches.
- * Set the flush time to the mtime of _PATH_ETAB or
+ * Set the flush time to the mtime of the etab state file or
* if force, to now.
* the caches to flush are:
* auth.unix.ip nfsd.export nfsd.fh
@@ -228,7 +230,7 @@ cache_flush(int force)
};
now = time(0);
if (force ||
- stat(_PATH_ETAB, &stb) != 0 ||
+ stat(etab.statefn, &stb) != 0 ||
stb.st_mtime > now)
stb.st_mtime = time(0);
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index e717c1e..203efd2 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -533,7 +533,7 @@ retry:
* or from environment
*/
char *env = getenv(cb->value+1);
- if (env)
+ if (env && *env)
return env;
section = "environment";
tag = cb->value + 1;
diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c
index 59dfbdf..2ecb2cc 100644
--- a/support/nfs/rmtab.c
+++ b/support/nfs/rmtab.c
@@ -33,12 +33,14 @@
static FILE *rmfp = NULL;
+extern struct state_paths rmtab;
+
int
setrmtabent(char *type)
{
if (rmfp)
fclose(rmfp);
- rmfp = fsetrmtabent(_PATH_RMTAB, type);
+ rmfp = fsetrmtabent(rmtab.statefn, type);
return (rmfp != NULL);
}
diff --git a/support/nsm/file.c b/support/nsm/file.c
index aafa755..52f5401 100644
--- a/support/nsm/file.c
+++ b/support/nsm/file.c
@@ -88,6 +88,7 @@
#include "xlog.h"
#include "nsm.h"
+#include "misc.h"
#define RPCARGSLEN (4 * (8 + 1))
#define LINELEN (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1)
@@ -170,25 +171,7 @@ __attribute__((__malloc__))
static char *
nsm_make_pathname(const char *directory)
{
- size_t size;
- char *path;
- int len;
-
- size = strlen(nsm_base_dirname) + strlen(directory) + 2;
- if (size > PATH_MAX)
- return NULL;
-
- path = malloc(size);
- if (path == NULL)
- return NULL;
-
- len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory);
- if (error_check(len, size)) {
- free(path);
- return NULL;
- }
-
- return path;
+ return generic_make_pathname(nsm_base_dirname, directory);
}
/*
@@ -293,29 +276,8 @@ out:
_Bool
nsm_setup_pathnames(const char *progname, const char *parentdir)
{
- static char buf[PATH_MAX];
- struct stat st;
- char *path;
-
- /* First: test length of name and whether it exists */
- if (lstat(parentdir, &st) == -1) {
- (void)fprintf(stderr, "%s: Failed to stat %s: %s",
- progname, parentdir, strerror(errno));
- return false;
- }
-
- /* Ensure we have a clean directory pathname */
- strncpy(buf, parentdir, sizeof(buf));
- path = dirname(buf);
- if (*path == '.') {
- (void)fprintf(stderr, "%s: Unusable directory %s",
- progname, parentdir);
- return false;
- }
-
- xlog(D_CALL, "Using %s as the state directory", parentdir);
- strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname));
- return true;
+ return generic_setup_basedir(progname, parentdir, nsm_base_dirname,
+ PATH_MAX);
}
/**
diff --git a/systemd/Makefile.am b/systemd/Makefile.am
index 0d15b9f..eef53c4 100644
--- a/systemd/Makefile.am
+++ b/systemd/Makefile.am
@@ -4,6 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in
unit_files = \
nfs-client.target \
+ rpc_pipefs.target \
\
nfs-mountd.service \
nfs-server.service \
@@ -42,14 +43,23 @@ EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS)
unit_dir = /usr/lib/systemd/system
generator_dir = /usr/lib/systemd/system-generators
-EXTRA_PROGRAMS = nfs-server-generator
+EXTRA_PROGRAMS = nfs-server-generator rpc-pipefs-generator
genexecdir = $(generator_dir)
+
+COMMON_SRCS = systemd.c systemd.h
+
+nfs_server_generator_SOURCES = $(COMMON_SRCS) nfs-server-generator.c
+
+rpc_pipefs_generator_SOURCES = $(COMMON_SRCS) rpc-pipefs-generator.c
+
nfs_server_generator_LDADD = ../support/export/libexport.a \
../support/nfs/libnfs.a \
../support/misc/libmisc.a
+rpc_pipefs_generator_LDADD = ../support/nfs/libnfs.a
+
if INSTALL_SYSTEMD
-genexec_PROGRAMS = nfs-server-generator
+genexec_PROGRAMS = nfs-server-generator rpc-pipefs-generator
install-data-hook: $(unit_files)
mkdir -p $(DESTDIR)/$(unitdir)
cp $(unit_files) $(DESTDIR)/$(unitdir)
diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service
index ddc324e..2bbcee6 100644
--- a/systemd/nfs-blkmap.service
+++ b/systemd/nfs-blkmap.service
@@ -2,8 +2,8 @@
Description=pNFS block layout mapping daemon
DefaultDependencies=no
Conflicts=umount.target
-After=var-lib-nfs-rpc_pipefs.mount
-Requires=var-lib-nfs-rpc_pipefs.mount
+After=rpc_pipefs.target
+Requires=rpc_pipefs.target
PartOf=nfs-utils.service
diff --git a/systemd/nfs-idmapd.service b/systemd/nfs-idmapd.service
index acca86b..f38fe52 100644
--- a/systemd/nfs-idmapd.service
+++ b/systemd/nfs-idmapd.service
@@ -1,8 +1,8 @@
[Unit]
Description=NFSv4 ID-name mapping service
DefaultDependencies=no
-Requires=var-lib-nfs-rpc_pipefs.mount
-After=var-lib-nfs-rpc_pipefs.mount local-fs.target
+Requires=rpc_pipefs.target
+After=rpc_pipefs.target local-fs.target
BindsTo=nfs-server.service
diff --git a/systemd/nfs-mountd.service b/systemd/nfs-mountd.service
index 15e828b..fec0399 100644
--- a/systemd/nfs-mountd.service
+++ b/systemd/nfs-mountd.service
@@ -2,8 +2,9 @@
Description=NFS Mount Daemon
DefaultDependencies=no
Requires=proc-fs-nfsd.mount
+Wants=network-online.target
After=proc-fs-nfsd.mount
-After=network.target local-fs.target
+After=rpcbind.socket
BindsTo=nfs-server.service
[Service]
diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c
index cc99969..737f109 100644
--- a/systemd/nfs-server-generator.c
+++ b/systemd/nfs-server-generator.c
@@ -29,6 +29,7 @@
#include "misc.h"
#include "nfslib.h"
#include "exportfs.h"
+#include "systemd.h"
/* A simple "set of strings" to remove duplicates
* found in /etc/exports
@@ -55,38 +56,31 @@ static int is_unique(struct list **lp, char *path)
return 1;
}
-/* We need to convert a path name to a systemd unit
- * name. This requires some translation ('/' -> '-')
- * and some escaping.
- */
-static void systemd_escape(FILE *f, char *path)
+static int has_noauto_flag(char *path)
{
- while (*path == '/')
- path++;
- if (!*path) {
- /* "/" becomes "-", otherwise leading "/" is ignored */
- fputs("-", f);
- return;
- }
- while (*path) {
- char c = *path++;
-
- if (c == '/') {
- /* multiple non-trailing slashes become '-' */
- while (*path == '/')
- path++;
- if (*path)
- fputs("-", f);
- } else if (isalnum(c) || c == ':' || c == '.')
- fputc(c, f);
- else
- fprintf(f, "\\x%02x", c & 0xff);
+ FILE *fstab;
+ struct mntent *mnt;
+
+ fstab = setmntent("/etc/fstab", "r");
+ if (!fstab)
+ return 0;
+
+ while ((mnt = getmntent(fstab)) != NULL) {
+ int l = strlen(mnt->mnt_dir);
+ if (strncmp(mnt->mnt_dir, path, l) != 0)
+ continue;
+ if (path[l] && path[l] != '/')
+ continue;
+ if (hasmntopt(mnt, "noauto"))
+ break;
}
+ fclose(fstab);
+ return mnt != NULL;
}
int main(int argc, char *argv[])
{
- char *path;
+ char *path, *spath;
char dirbase[] = "/nfs-server.service.d";
char filebase[] = "/order-with-mounts.conf";
nfs_export *exp;
@@ -124,6 +118,10 @@ int main(int argc, char *argv[])
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
if (!is_unique(&list, exp->m_export.e_path))
continue;
+ if (exp->m_export.e_mountpoint)
+ continue;
+ if (has_noauto_flag(exp->m_export.e_path))
+ continue;
if (strchr(exp->m_export.e_path, ' '))
fprintf(f, "RequiresMountsFor=\"%s\"\n",
exp->m_export.e_path);
@@ -141,9 +139,15 @@ int main(int argc, char *argv[])
if (strcmp(mnt->mnt_type, "nfs") != 0 &&
strcmp(mnt->mnt_type, "nfs4") != 0)
continue;
- fprintf(f, "Before= ");
- systemd_escape(f, mnt->mnt_dir);
- fprintf(f, ".mount\n");
+
+ spath = systemd_escape(mnt->mnt_dir, ".mount");
+ if (!spath) {
+ fprintf(stderr,
+ "nfs-server-generator: convert path failed: %s\n",
+ mnt->mnt_dir);
+ continue;
+ }
+ fprintf(f, "Before=%s\n", spath);
}
fclose(fstab);
diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service
index 5be5de6..e6b8f58 100644
--- a/systemd/nfs-server.service
+++ b/systemd/nfs-server.service
@@ -3,12 +3,12 @@ Description=NFS server and services
DefaultDependencies=no
Requires= network.target proc-fs-nfsd.mount
Requires= nfs-mountd.service
-Wants=rpcbind.socket
+Wants=rpcbind.socket network-online.target
Wants=rpc-statd.service nfs-idmapd.service
Wants=rpc-statd-notify.service
After= local-fs.target
-After= network.target proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
+After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
After= nfs-idmapd.service rpc-statd.service
Before= rpc-statd-notify.service
diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man
index 91c49a0..189b052 100644
--- a/systemd/nfs.conf.man
+++ b/systemd/nfs.conf.man
@@ -96,6 +96,18 @@ value, which can be one or more from the list
.BR all .
When a list is given, the members should be comma-separated.
.TP
+.B general
+Recognized values:
+.BR pipefs-directory .
+
+See
+.BR blkmapd (8),
+.BR rpc.idmapd (8),
+and
+.BR rpc.gssd (8)
+for details.
+
+.TP
.B nfsdcltrack
Recognized values:
.BR storagedir .
@@ -154,6 +166,13 @@ section, are used to configure mountd. See
.BR rpc.mountd (8)
for details.
+The
+.B state-directory-path
+value in the
+.B [mountd]
+section is also used by
+.BR exportfs (8).
+
.TP
.B statd
Recognized values:
@@ -198,7 +217,6 @@ Recognized values:
.BR limit-to-legacy-enctypes ,
.BR context-timeout ,
.BR rpc-timeout ,
-.BR pipefs-directory ,
.BR keytab-file ,
.BR cred-cache-directory ,
.BR preferred-realm .
diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in
index b353027..6807db3 100644
--- a/systemd/rpc-gssd.service.in
+++ b/systemd/rpc-gssd.service.in
@@ -2,8 +2,8 @@
Description=RPC security service for NFS client and server
DefaultDependencies=no
Conflicts=umount.target
-Requires=var-lib-nfs-rpc_pipefs.mount
-After=var-lib-nfs-rpc_pipefs.mount
+Requires=rpc_pipefs.target
+After=rpc_pipefs.target
ConditionPathExists=@_sysconfdir@/krb5.keytab
diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c
new file mode 100644
index 0000000..66addb9
--- /dev/null
+++ b/systemd/rpc-pipefs-generator.c
@@ -0,0 +1,138 @@
+/*
+ * rpc-pipefs-generator:
+ * systemd generator to create ordering dependencies between
+ * nfs services and the rpc_pipefs mountpoint
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <mntent.h>
+
+#include "nfslib.h"
+#include "conffile.h"
+#include "systemd.h"
+
+#define RPC_PIPEFS_DEFAULT "/var/lib/nfs/rpc_pipefs"
+char *conf_path = NFS_CONFFILE;
+
+static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit,
+ const char *dirname)
+{
+ char *path;
+ FILE *f;
+
+ path = malloc(strlen(dirname) + 1 + strlen(pipefs_unit));
+ if (!path)
+ return 1;
+ sprintf(path, "%s/%s", dirname, pipefs_unit);
+ f = fopen(path, "w");
+ if (!f)
+ return 1;
+
+ fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n");
+ fprintf(f, "Description=RPC Pipe File System\n");
+ fprintf(f, "DefaultDependencies=no\n");
+ fprintf(f, "After=systemd-tmpfiles-setup.service\n");
+ fprintf(f, "Conflicts=umount.target\n");
+ fprintf(f, "\n[Mount]\n");
+ fprintf(f, "What=sunrpc\n");
+ fprintf(f, "Where=%s\n", pipefs_path);
+ fprintf(f, "Type=rpc_pipefs\n");
+
+ fclose(f);
+ return 0;
+}
+
+static
+int generate_target(char *pipefs_path, const char *dirname)
+{
+ char *path;
+ char filebase[] = "/rpc_pipefs.target";
+ char *pipefs_unit;
+ FILE *f;
+ int ret = 0;
+
+ pipefs_unit = systemd_escape(pipefs_path, ".mount");
+ if (!pipefs_unit)
+ return 1;
+
+ ret = generate_mount_unit(pipefs_path, pipefs_unit, dirname);
+ if (ret)
+ return ret;
+
+ path = malloc(strlen(dirname) + 1 + sizeof(filebase));
+ if (!path)
+ return 2;
+ sprintf(path, "%s", dirname);
+ mkdir(path, 0755);
+ strcat(path, filebase);
+ f = fopen(path, "w");
+ if (!f)
+ return 1;
+
+ fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n");
+ fprintf(f, "Requires=%s\n", pipefs_unit);
+ fprintf(f, "After=%s\n", pipefs_unit);
+ fclose(f);
+
+ return 0;
+}
+
+static int is_non_pipefs_mountpoint(char *path)
+{
+ FILE *mtab;
+ struct mntent *mnt;
+
+ mtab = setmntent("/etc/mtab", "r");
+ if (!mtab)
+ return 0;
+
+ while ((mnt = getmntent(mtab)) != NULL) {
+ if (strlen(mnt->mnt_dir) != strlen(path))
+ continue;
+ if (strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir)))
+ continue;
+ if (strncmp(mnt->mnt_type, "rpc_pipefs", strlen(mnt->mnt_type)))
+ break;
+ }
+ fclose(mtab);
+ return mnt != NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ char *s;
+
+ /* Avoid using any external services */
+ xlog_syslog(0);
+
+ if (argc != 4 || argv[1][0] != '/') {
+ fprintf(stderr, "rpc-pipefs-generator: create systemd dependencies for nfs services\n");
+ fprintf(stderr, "Usage: normal-dir early-dir late-dir\n");
+ exit(1);
+ }
+
+ conf_init();
+ s = conf_get_str("general", "pipefs-directory");
+ if (!s)
+ exit(0);
+ if (strlen(s) == strlen(RPC_PIPEFS_DEFAULT) &&
+ strcmp(s, RPC_PIPEFS_DEFAULT) == 0)
+ exit(0);
+
+ if (is_non_pipefs_mountpoint(s))
+ exit(1);
+
+ ret = generate_target(s, argv[1]);
+ exit(ret);
+}
diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service
index 7bfc9b1..f54d4c5 100644
--- a/systemd/rpc-statd-notify.service
+++ b/systemd/rpc-statd-notify.service
@@ -1,7 +1,7 @@
[Unit]
Description=Notify NFS peers of a restart
DefaultDependencies=no
-Requires=network.target
+Wants=network-online.target
After=local-fs.target network.target nss-lookup.target
# if we run an nfs server, it needs to be running before we
diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service
index 60d600f..8cef022 100644
--- a/systemd/rpc-statd.service
+++ b/systemd/rpc-statd.service
@@ -3,7 +3,8 @@ Description=NFS status monitor for NFSv2/3 locking.
DefaultDependencies=no
Conflicts=umount.target
Requires=nss-lookup.target rpcbind.socket
-After=network.target nss-lookup.target rpcbind.socket
+Wants=network-online.target
+After=nss-lookup.target rpcbind.socket
PartOf=nfs-utils.service
diff --git a/systemd/rpc-svcgssd.service b/systemd/rpc-svcgssd.service
index 7187e3c..cb2bcd4 100644
--- a/systemd/rpc-svcgssd.service
+++ b/systemd/rpc-svcgssd.service
@@ -1,8 +1,7 @@
[Unit]
Description=RPC security service for NFS server
DefaultDependencies=no
-Requires=var-lib-nfs-rpc_pipefs.mount
-After=var-lib-nfs-rpc_pipefs.mount local-fs.target
+After=local-fs.target
PartOf=nfs-server.service
PartOf=nfs-utils.service
diff --git a/systemd/rpc_pipefs.target b/systemd/rpc_pipefs.target
new file mode 100644
index 0000000..01d4d27
--- /dev/null
+++ b/systemd/rpc_pipefs.target
@@ -0,0 +1,3 @@
+[Unit]
+Requires=var-lib-nfs-rpc_pipefs.mount
+After=var-lib-nfs-rpc_pipefs.mount
diff --git a/systemd/systemd.c b/systemd/systemd.c
new file mode 100644
index 0000000..17820d4
--- /dev/null
+++ b/systemd/systemd.c
@@ -0,0 +1,133 @@
+/*
+ * Helper functions for systemd generators in nfs-utils.
+ *
+ * Currently just systemd_escape().
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+static const char hex[16] =
+{
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+};
+
+/*
+ * determine length of the string that systemd_escape() needs to allocate
+ */
+static int systemd_len(char *path)
+{
+ char *p;
+ int len = 0;
+
+ p = path;
+ while (*p == '/')
+ /* multiple leading "/" are ignored */
+ p++;
+
+ if (!*p)
+ /* root directory "/" becomes is encoded as a single "-" */
+ return 1;
+
+ if (*p == '.')
+ /*
+ * replace "." with "\x2d" escape sequence if
+ * it's the first character in escaped path
+ * */
+ len += 4;
+
+ while (*p) {
+ unsigned char c = *p++;
+
+ if (c == '/') {
+ /* multiple non-trailing slashes become '-' */
+ while (*p == '/')
+ p++;
+ if (*p)
+ len++;
+ } else if (isalnum(c) || c == ':' || c == '.' || c == '_')
+ /* these characters are not replaced */
+ len++;
+ else
+ /* replace with "\x2d" escape sequence */
+ len += 4;
+ }
+
+ return len;
+}
+
+/*
+ * convert c to "\x2d" escape sequence and append to string
+ * at position p, advancing p
+ */
+static char *hexify(unsigned char c, char *p)
+{
+ *p++ = '\\';
+ *p++ = 'x';
+ *p++ = hex[c >> 4];
+ *p++ = hex[c & 0xf];
+ return p;
+}
+
+/*
+ * convert a path to a unit name according to the logic in systemd.unit(5):
+ *
+ * Basically, given a path, "/" is replaced by "-", and all other
+ * characters which are not ASCII alphanumerics are replaced by C-style
+ * "\x2d" escapes (except that "_" is never replaced and "." is only
+ * replaced when it would be the first character in the escaped path).
+ * The root directory "/" is encoded as single dash, while otherwise the
+ * initial and ending "/" are removed from all paths during
+ * transformation.
+ *
+ * NB: Although the systemd.unit(5) doesn't mention it, the ':' character
+ * is not escaped.
+ */
+char *systemd_escape(char *path, char *suffix)
+{
+ char *result;
+ char *p;
+ int len;
+
+ len = systemd_len(path);
+ result = malloc(len + strlen(suffix) + 1);
+ p = result;
+ while (*path == '/')
+ /* multiple leading "/" are ignored */
+ path++;
+ if (!*path) {
+ /* root directory "/" becomes is encoded as a single "-" */
+ *p++ = '-';
+ goto out;
+ }
+ if (*path == '.')
+ /*
+ * replace "." with "\x2d" escape sequence if
+ * it's the first character in escaped path
+ * */
+ p = hexify(*path++, p);
+
+ while (*path) {
+ unsigned char c = *path++;
+
+ if (c == '/') {
+ /* multiple non-trailing slashes become '-' */
+ while (*path == '/')
+ path++;
+ if (*path)
+ *p++ = '-';
+ } else if (isalnum(c) || c == ':' || c == '.' || c == '_')
+ /* these characters are not replaced */
+ *p++ = c;
+ else
+ /* replace with "\x2d" escape sequence */
+ p = hexify(c, p);
+ }
+
+out:
+ sprintf(p, "%s", suffix);
+ return result;
+}
diff --git a/systemd/systemd.h b/systemd/systemd.h
new file mode 100644
index 0000000..25235ec
--- /dev/null
+++ b/systemd/systemd.h
@@ -0,0 +1,6 @@
+#ifndef SYSTEMD_H
+#define SYSTEMD_H
+
+char *systemd_escape(char *path, char *suffix);
+
+#endif /* SYSTEMD_H */
diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man
index 914b80f..4b3d3f0 100644
--- a/utils/blkmapd/blkmapd.man
+++ b/utils/blkmapd/blkmapd.man
@@ -43,9 +43,24 @@ Performs device discovery only then exits.
Runs
.B blkmapd
in the foreground and sends output to stderr (as opposed to syslogd)
+.SH CONFIGURATION FILE
+The
+.B blkmapd
+daemon recognizes the following value from the
+.B [general]
+section of the
+.I /etc/nfs.conf
+configuration file:
+.TP
+.B pipefs-directory
+Tells
+.B blkmapd
+where to look for the rpc_pipefs filesystem. The default value is
+.IR /var/lib/nfs/rpc_pipefs .
.SH SEE ALSO
.BR nfs (5),
-.BR dmsetup (8)
+.BR dmsetup (8),
+.BR nfs.conf (5)
.sp
RFC 5661 for the NFS version 4.1 specification.
.br
diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c
index 8eb3fd0..d2da764 100644
--- a/utils/blkmapd/device-discovery.c
+++ b/utils/blkmapd/device-discovery.c
@@ -50,20 +50,36 @@
#include <errno.h>
#include <libdevmapper.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include "device-discovery.h"
#include "xcommon.h"
+#include "nfslib.h"
+#include "conffile.h"
#define EVENT_SIZE (sizeof(struct inotify_event))
#define EVENT_BUFSIZE (1024 * EVENT_SIZE)
-#define BL_PIPE_FILE "/var/lib/nfs/rpc_pipefs/nfs/blocklayout"
-#define NFSPIPE_DIR "/var/lib/nfs/rpc_pipefs/nfs"
#define RPCPIPE_DIR "/var/lib/nfs/rpc_pipefs"
#define PID_FILE "/var/run/blkmapd.pid"
+#define CONF_SAVE(w, f) do { \
+ char *p = f; \
+ if (p != NULL) \
+ (w) = p; \
+} while (0)
+
+static char bl_pipe_file[PATH_MAX];
+static char nfspipe_dir[PATH_MAX];
+static char rpcpipe_dir[PATH_MAX];
+
struct bl_disk *visible_disk_list;
int bl_watch_fd, bl_pipe_fd, nfs_pipedir_wfd, rpc_pipedir_wfd;
int pidfd = -1;
+char *conf_path = NULL;
+
struct bl_disk_path *bl_get_path(const char *filepath,
struct bl_disk_path *paths)
@@ -358,8 +374,8 @@ static void bl_rpcpipe_cb(void)
continue;
if (event->mask & IN_CREATE) {
BL_LOG_WARNING("nfs pipe dir created\n");
- bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd);
- bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
+ bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd);
+ bl_pipe_fd = open(bl_pipe_file, O_RDWR);
} else if (event->mask & IN_DELETE) {
BL_LOG_WARNING("nfs pipe dir deleted\n");
inotify_rm_watch(bl_watch_fd, nfs_pipedir_wfd);
@@ -372,7 +388,7 @@ static void bl_rpcpipe_cb(void)
continue;
if (event->mask & IN_CREATE) {
BL_LOG_WARNING("blocklayout pipe file created\n");
- bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
+ bl_pipe_fd = open(bl_pipe_file, O_RDWR);
if (bl_pipe_fd < 0)
BL_LOG_ERR("open %s failed: %s\n",
event->name, strerror(errno));
@@ -437,6 +453,19 @@ int main(int argc, char **argv)
{
int opt, dflag = 0, fg = 0, ret = 1;
char pidbuf[64];
+ char *xrpcpipe_dir = NULL;
+
+ strncpy(rpcpipe_dir, RPCPIPE_DIR, sizeof(rpcpipe_dir));
+ conf_path = NFS_CONFFILE;
+ conf_init();
+ CONF_SAVE(xrpcpipe_dir, conf_get_str("general", "pipefs-directory"));
+ if (xrpcpipe_dir != NULL)
+ strlcpy(rpcpipe_dir, xrpcpipe_dir, sizeof(rpcpipe_dir));
+
+ strncpy(nfspipe_dir, rpcpipe_dir, sizeof(nfspipe_dir));
+ strlcat(nfspipe_dir, "/nfs", sizeof(nfspipe_dir));
+ strncpy(bl_pipe_file, rpcpipe_dir, sizeof(bl_pipe_file));
+ strlcat(bl_pipe_file, "/nfs/blocklayout", sizeof(bl_pipe_file));
while ((opt = getopt(argc, argv, "hdf")) != -1) {
switch (opt) {
@@ -496,12 +525,12 @@ int main(int argc, char **argv)
}
/* open pipe file */
- bl_watch_dir(RPCPIPE_DIR, &rpc_pipedir_wfd);
- bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd);
+ bl_watch_dir(rpcpipe_dir, &rpc_pipedir_wfd);
+ bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd);
- bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
+ bl_pipe_fd = open(bl_pipe_file, O_RDWR);
if (bl_pipe_fd < 0)
- BL_LOG_ERR("open pipe file %s failed: %s\n", BL_PIPE_FILE, strerror(errno));
+ BL_LOG_ERR("open pipe file %s failed: %s\n", bl_pipe_file, strerror(errno));
while (1) {
/* discover device when needed */
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index 61dddfb..02d5b6d 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -52,6 +52,8 @@ static const char *lockfile = EXP_LOCKFILE;
static int _lockfd = -1;
char *conf_path = NFS_CONFFILE;
+struct state_paths etab;
+
/*
* If we aren't careful, changes made by exportfs can be lost
* when multiple exports process run at once:
@@ -95,6 +97,7 @@ main(int argc, char **argv)
int f_ignore = 0;
int i, c;
int force_flush = 0;
+ char *s;
if ((progname = strrchr(argv[0], '/')) != NULL)
progname++;
@@ -108,6 +111,11 @@ main(int argc, char **argv)
conf_init();
xlog_from_conffile("exportfs");
+ /* NOTE: following uses "mountd" section of nfs.conf !!!! */
+ s = conf_get_str("mountd", "state-directory-path");
+ if (s && !state_setup_basedir(argv[0], s))
+ exit(1);
+
while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) {
switch(c) {
case 'a':
@@ -159,13 +167,17 @@ main(int argc, char **argv)
xlog(L_ERROR, "-r and -u are incompatible");
return 1;
}
+ if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
+ return 1;
if (optind == argc && ! f_all) {
if (force_flush) {
cache_flush(1);
+ free_state_path_names(&etab);
return 0;
} else {
xtab_export_read();
dump(f_verbose, f_export_format);
+ free_state_path_names(&etab);
return 0;
}
}
@@ -206,6 +218,7 @@ main(int argc, char **argv)
}
xtab_export_write();
cache_flush(force_flush);
+ free_state_path_names(&etab);
return export_errno;
}
diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
index 45b6d83..91d3589 100644
--- a/utils/exportfs/exportfs.man
+++ b/utils/exportfs/exportfs.man
@@ -148,6 +148,29 @@ options.
.TP
.B -s
Display the current export list suitable for /etc/exports.
+
+.SH CONFIGURATION FILE
+The
+.B [exportfs]
+section of the
+.I /etc/nfs.conf
+configuration file can contain a
+.B debug
+value, which can be one or more from the list
+.BR general ,
+.BR call ,
+.BR auth ,
+.BR parse ,
+.BR all .
+When a list is given, the members should be comma-separated.
+
+.B exportfs
+will also recognize the
+.B state-directory-path
+value from the
+.B [mountd]
+section.
+
.SH DISCUSSION
.SS Exporting Directories
The first synopsis shows how to invoke
diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man
index 0c516fa..9efa29f 100644
--- a/utils/exportfs/nfsd.man
+++ b/utils/exportfs/nfsd.man
@@ -105,11 +105,6 @@ clients have for different filesystems.
The caches are:
.TP
-.B auth.domain
-This cache maps the name of a client (or domain) to an internal data
-structure. The only access that is possible is to flush the cache.
-
-.TP
.B auth.unix.ip
This cache contains a mapping from IP address to the name of the
authentication domain that the ipaddress should be treated as part of.
@@ -133,7 +128,8 @@ are:
.B flush
When a number of seconds since epoch (1 Jan 1970) is written to this
file, all entries in the cache that were last updated before that file
-become invalidated and will be flushed out. Writing 1 will flush
+become invalidated and will be flushed out. Writing a time in the
+future (in seconds since epoch) will flush
everything. This is the only file that will always be present.
.TP
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
index 4d18d35..28f9649 100644
--- a/utils/gssd/gssd.c
+++ b/utils/gssd/gssd.c
@@ -87,6 +87,7 @@ int root_uses_machine_creds = 1;
unsigned int context_timeout = 0;
unsigned int rpc_timeout = 5;
char *preferred_realm = NULL;
+char *ccachedir = NULL;
/* Avoid DNS reverse lookups on server names */
static bool avoid_dns = true;
int thread_started = false;
@@ -837,18 +838,9 @@ usage(char *progname)
exit(1);
}
-int
-main(int argc, char *argv[])
+inline static void
+read_gss_conf(void)
{
- int fg = 0;
- int verbosity = 0;
- int rpc_verbosity = 0;
- int opt;
- int i;
- extern char *optarg;
- char *progname;
- char *ccachedir = NULL;
- struct event sighup_ev;
char *s;
conf_init();
@@ -865,6 +857,10 @@ main(int argc, char *argv[])
s = conf_get_str("gssd", "pipefs-directory");
if (!s)
s = conf_get_str("general", "pipefs-directory");
+ else
+ printerr(0, "WARNING: Specifying pipefs-directory in the [gssd] "
+ "section of %s is deprecated. Use the [general] "
+ "section instead.", NFS_CONFFILE);
if (s)
pipefs_path = s;
s = conf_get_str("gssd", "keytab-file");
@@ -877,6 +873,22 @@ main(int argc, char *argv[])
if (s)
preferred_realm = s;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fg = 0;
+ int verbosity = 0;
+ int rpc_verbosity = 0;
+ int opt;
+ int i;
+ extern char *optarg;
+ char *progname;
+ struct event sighup_ev;
+
+ read_gss_conf();
+
while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) {
switch (opt) {
case 'f':
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
index 87eef02..e620f0d 100644
--- a/utils/gssd/gssd.man
+++ b/utils/gssd/gssd.man
@@ -335,10 +335,6 @@ Equivalent to
Equivalent to
.BR -t .
.TP
-.B pipefs-directory
-Equivalent to
-.BR -p .
-.TP
.B keytab-file
Equivalent to
.BR -k .
@@ -350,6 +346,14 @@ Equivalent to
.B preferred-realm
Equivalent to
.BR -R .
+.P
+In addtion, the following value is recognized from the
+.B [general]
+section:
+.TP
+.B pipefs-directory
+Equivalent to
+.BR -p .
.SH SEE ALSO
.BR rpc.svcgssd (8),
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index d74d372..4fc81c3 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -729,10 +729,18 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
char *target = NULL;
char *service = NULL;
char *enctypes = NULL;
+ char *upcall_str;
+ char *pbuf = info->lbuf;
printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
- for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) {
+ upcall_str = strdup(info->lbuf);
+ if (upcall_str == NULL) {
+ printerr(0, "ERROR: malloc failure\n");
+ goto out_nomem;
+ }
+
+ while ((p = strsep(&pbuf, " "))) {
if (!strncmp(p, "mech=", strlen("mech=")))
mech = p + strlen("mech=");
else if (!strncmp(p, "uid=", strlen("uid=")))
@@ -748,7 +756,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
if (!mech || strlen(mech) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to find gss mechanism name "
- "in upcall string '%s'\n", info->lbuf);
+ "in upcall string '%s'\n", upcall_str);
goto out;
}
@@ -761,7 +769,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
if (!uidstr) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to find uid "
- "in upcall string '%s'\n", info->lbuf);
+ "in upcall string '%s'\n", upcall_str);
goto out;
}
@@ -774,7 +782,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
if (target && strlen(target) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to parse target name "
- "in upcall string '%s'\n", info->lbuf);
+ "in upcall string '%s'\n", upcall_str);
goto out;
}
@@ -789,7 +797,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
if (service && strlen(service) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to parse service type "
- "in upcall string '%s'\n", info->lbuf);
+ "in upcall string '%s'\n", upcall_str);
goto out;
}
@@ -802,6 +810,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
do_error_downcall(clp->gssd_fd, uid, -EACCES);
}
out:
+ free(upcall_str);
+out_nomem:
free(info);
return;
}
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
index f4e083a..56bf67e 100644
--- a/utils/idmapd/idmapd.c
+++ b/utils/idmapd/idmapd.c
@@ -166,7 +166,7 @@ static uid_t nobodyuid;
static gid_t nobodygid;
/* Used by conffile.c in libnfs.a */
-char *conf_path;
+char *conf_path = NULL;
static int
flush_nfsd_cache(char *path, time_t now)
@@ -220,7 +220,6 @@ main(int argc, char **argv)
int ret;
char *progname;
- conf_path = _PATH_IDMAPDCONF;
nobodyuser = NFS4NOBODY_USER;
nobodygroup = NFS4NOBODY_GROUP;
strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir));
@@ -234,8 +233,11 @@ main(int argc, char **argv)
#define GETOPTSTR "hvfd:p:U:G:c:CS"
opterr=0; /* Turn off error messages */
while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) {
- if (opt == 'c')
+ if (opt == 'c') {
+ warnx("-c is deprecated and may be removed in the "
+ "future. See idmapd(8).");
conf_path = optarg;
+ }
if (opt == '?') {
if (strchr(GETOPTSTR, optopt))
warnx("'-%c' option requires an argument.", optopt);
@@ -247,17 +249,33 @@ main(int argc, char **argv)
}
optind = 1;
- if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) {
- warn("Skipping configuration file \"%s\"", conf_path);
- conf_path = NULL;
+ if (conf_path) { /* deprecated -c option was specified */
+ if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) {
+ warn("Skipping configuration file \"%s\"", conf_path);
+ conf_path = NULL;
+ } else {
+ conf_init();
+ verbose = conf_get_num("General", "Verbosity", 0);
+ cache_entry_expiration = conf_get_num("General",
+ "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY);
+ CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory"));
+ if (xpipefsdir != NULL)
+ strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir));
+ CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User"));
+ CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group"));
+ }
} else {
+ conf_path = NFS_CONFFILE;
conf_init();
- verbose = conf_get_num("General", "Verbosity", 0);
- cache_entry_expiration = conf_get_num("General",
- "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY);
CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory"));
if (xpipefsdir != NULL)
strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir));
+
+ conf_path = _PATH_IDMAPDCONF;
+ conf_init();
+ verbose = conf_get_num("General", "Verbosity", 0);
+ cache_entry_expiration = conf_get_num("General",
+ "cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY);
CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User"));
CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group"));
}
diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man
index d4ab894..5f34d2b 100644
--- a/utils/idmapd/idmapd.man
+++ b/utils/idmapd/idmapd.man
@@ -73,11 +73,28 @@ The default value is \&"/var/lib/nfs/rpc_pipefs\&".
.It Fl c Ar path
Use configuration file
.Ar path .
+This option is deprecated.
.It Fl C
Client-only: perform no idmapping for any NFS server, even if one is detected.
.It Fl S
Server-only: perform no idmapping for any NFS client, even if one is detected.
.El
+.Sh CONFIGURATION FILES
+.Nm
+recognizes the following value from the
+.Sy [general]
+section of the
+.Pa /etc/nfs.conf
+configuration file:
+.Bl -tag -width Ds_imagedir
+.It Sy pipefs-directory
+Equivalent to
+.Sy -p .
+.El
+.Pp
+All other settings related to id mapping are found in the
+.Pa /etc/idmapd.conf
+configuration file.
.Sh EXAMPLES
.Cm rpc.idmapd -f -vvv
.Pp
@@ -94,9 +111,11 @@ messages to console, and with a verbosity level of 3.
.\" This next request is for sections 1, 6, 7 & 8 only.
.\" .Sh ENVIRONMENT
.Sh FILES
-.Pa /etc/idmapd.conf
+.Pa /etc/idmapd.conf ,
+.Pa /etc/nfs.conf
.Sh SEE ALSO
.Xr idmapd.conf 5 ,
+.Xr nfs.conf 5 ,
.Xr nfsidmap 8
.\".Sh SEE ALSO
.\".Xr nylon.conf 4
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 7dceb2d..281e935 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -33,6 +33,7 @@
#include <errno.h>
#include <netdb.h>
#include <time.h>
+#include <grp.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -804,6 +805,7 @@ int start_statd(void)
pid_t pid = fork();
switch (pid) {
case 0: /* child */
+ setgroups(0, NULL);
setgid(0);
setuid(0);
execle(START_STATD, START_STATD, NULL, envp);
@@ -1638,6 +1640,7 @@ int nfs_options2pmap(struct mount_options *options,
struct pmap *nfs_pmap, struct pmap *mnt_pmap)
{
struct nfs_version version;
+ memset(&version, 0, sizeof(version));
if (!nfs_nfs_program(options, &nfs_pmap->pm_prog))
return 0;
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index 387d734..a9ff95d 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -517,6 +517,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4)
unsigned long protocol;
struct pmap mnt_pmap;
+ /* initialize structs */
+ memset(&nfs_pmap, 0, sizeof(struct pmap));
+ memset(&mnt_pmap, 0, sizeof(struct pmap));
+
/*
* Version and transport negotiation is not required
* and does not work for RDMA mounts.
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
index d065830..8299256 100644
--- a/utils/mountd/auth.c
+++ b/utils/mountd/auth.c
@@ -41,6 +41,8 @@ static nfs_client my_client;
extern int use_ipaddr;
+extern struct state_paths etab;
+
void
auth_init(void)
{
@@ -84,10 +86,10 @@ auth_reload()
static unsigned int counter;
int fd;
- if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) {
- xlog(L_FATAL, "couldn't open %s", _PATH_ETAB);
+ if ((fd = open(etab.statefn, O_RDONLY)) < 0) {
+ xlog(L_FATAL, "couldn't open %s", etab.statefn);
} else if (fstat(fd, &stb) < 0) {
- xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB);
+ xlog(L_FATAL, "couldn't stat %s", etab.statefn);
close(fd);
} else if (last_fd != -1 && stb.st_ino == last_inode) {
/* We opened the etab file before, and its inode
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
index 61699e6..bbadfaf 100644
--- a/utils/mountd/mountd.c
+++ b/utils/mountd/mountd.c
@@ -29,6 +29,7 @@
#include "mountd.h"
#include "rpcmisc.h"
#include "pseudoflavors.h"
+#include "nfslib.h"
extern void my_svc_run(void);
@@ -40,6 +41,9 @@ int reverse_resolve = 0;
int manage_gids;
int use_ipaddr = -1;
+struct state_paths etab;
+struct state_paths rmtab;
+
char *conf_path = NFS_CONFFILE;
/* PRC: a high-availability callout program can be specified with -H
@@ -110,8 +114,8 @@ unregister_services (void)
static void
cleanup_lockfiles (void)
{
- unlink(_PATH_ETABLCK);
- unlink(_PATH_RMTABLCK);
+ unlink(etab.lockfn);
+ unlink(rmtab.lockfn);
}
/* Wait for all worker child processes to exit and reap them */
@@ -181,6 +185,8 @@ fork_workers(void)
wait_for_workers();
unregister_services();
cleanup_lockfiles();
+ free_state_path_names(&etab);
+ free_state_path_names(&rmtab);
xlog(L_NOTICE, "mountd: no more workers, exiting\n");
exit(0);
}
@@ -198,6 +204,8 @@ killer (int sig)
wait_for_workers();
}
cleanup_lockfiles();
+ free_state_path_names(&etab);
+ free_state_path_names(&rmtab);
xlog (L_NOTICE, "Caught signal %d, un-registering and exiting.", sig);
exit(0);
}
@@ -656,7 +664,6 @@ get_exportlist(void)
int
main(int argc, char **argv)
{
- char *state_dir = NFS_STATEDIR;
char *progname;
char *s;
unsigned int listeners = 0;
@@ -684,8 +691,8 @@ main(int argc, char **argv)
ha_callout_prog = conf_get_str("mountd", "ha-callout");
s = conf_get_str("mountd", "state-directory-path");
- if (s)
- state_dir = s;
+ if (s && !state_setup_basedir(argv[0], s))
+ exit(1);
/* NOTE: following uses "nfsd" section of nfs.conf !!!! */
if (conf_get_bool("nfsd", "udp", NFSCTL_UDPISSET(_rpcprotobits)))
@@ -758,7 +765,8 @@ main(int argc, char **argv)
reverse_resolve = 1;
break;
case 's':
- state_dir = xstrdup(optarg);
+ if (!state_setup_basedir(argv[0], optarg))
+ exit(1);
break;
case 't':
num_threads = atoi (optarg);
@@ -790,11 +798,10 @@ main(int argc, char **argv)
fprintf(stderr, "%s: No protocol versions specified!\n", progname);
usage(progname, 1);
}
- if (chdir(state_dir)) {
- fprintf(stderr, "%s: chdir(%s) failed: %s\n",
- progname, state_dir, strerror(errno));
- exit(1);
- }
+ if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
+ return 1;
+ if (!setup_state_path_names(progname, RMTAB, RMTABTMP, RMTABLCK, &rmtab))
+ return 1;
if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
@@ -888,6 +895,8 @@ main(int argc, char **argv)
xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n");
unregister_services();
+ free_state_path_names(&etab);
+ free_state_path_names(&rmtab);
exit(1);
}
diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
index 9f0a51f..9978afc 100644
--- a/utils/mountd/mountd.man
+++ b/utils/mountd/mountd.man
@@ -144,7 +144,7 @@ Instead, mount the nfsd filesystem on
.IR /proc/fs/nfsd .
.TP
.BI "\-s," "" " \-\-state\-directory\-path " directory
-Specify a directory in which to place statd state information.
+Specify a directory in which to place state information (etab and rmtab).
If this option is not specified the default of
.I /var/lib/nfs
is used.
diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c
index 527377f..3ae0dbb 100644
--- a/utils/mountd/rmtab.c
+++ b/utils/mountd/rmtab.c
@@ -28,6 +28,8 @@
extern int reverse_resolve;
+extern struct state_paths rmtab;
+
/* If new path is a link do not destroy it but place the
* file where the link points.
*/
@@ -59,7 +61,7 @@ mountlist_add(char *host, const char *path)
int lockid;
long pos;
- if ((lockid = xflock(_PATH_RMTABLCK, "a")) < 0)
+ if ((lockid = xflock(rmtab.lockfn, "a")) < 0)
return;
setrmtabent("r+");
while ((rep = getrmtabent(1, &pos)) != NULL) {
@@ -99,13 +101,13 @@ mountlist_del(char *hname, const char *path)
int lockid;
int match;
- if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
+ if ((lockid = xflock(rmtab.lockfn, "w")) < 0)
return;
if (!setrmtabent("r")) {
xfunlock(lockid);
return;
}
- if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) {
+ if (!(fp = fsetrmtabent(rmtab.tmpfn, "w"))) {
endrmtabent();
xfunlock(lockid);
return;
@@ -121,9 +123,9 @@ mountlist_del(char *hname, const char *path)
if (!match || rep->r_count)
fputrmtabent(fp, rep, NULL);
}
- if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
+ if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) {
xlog(L_ERROR, "couldn't rename %s to %s",
- _PATH_RMTABTMP, _PATH_RMTAB);
+ rmtab.tmpfn, rmtab.statefn);
}
endrmtabent(); /* close & unlink */
fendrmtabent(fp);
@@ -138,7 +140,7 @@ mountlist_del_all(const struct sockaddr *sap)
FILE *fp;
int lockid;
- if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
+ if ((lockid = xflock(rmtab.lockfn, "w")) < 0)
return;
hostname = host_canonname(sap);
if (hostname == NULL) {
@@ -151,7 +153,7 @@ mountlist_del_all(const struct sockaddr *sap)
if (!setrmtabent("r"))
goto out_free;
- if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w")))
+ if (!(fp = fsetrmtabent(rmtab.tmpfn, "w")))
goto out_close;
while ((rep = getrmtabent(1, NULL)) != NULL) {
@@ -160,9 +162,9 @@ mountlist_del_all(const struct sockaddr *sap)
continue;
fputrmtabent(fp, rep, NULL);
}
- if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
+ if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) {
xlog(L_ERROR, "couldn't rename %s to %s",
- _PATH_RMTABTMP, _PATH_RMTAB);
+ rmtab.tmpfn, rmtab.statefn);
}
fendrmtabent(fp);
out_close:
@@ -195,11 +197,11 @@ mountlist_list(void)
struct stat stb;
int lockid;
- if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
+ if ((lockid = xflock(rmtab.lockfn, "r")) < 0)
return NULL;
- if (stat(_PATH_RMTAB, &stb) < 0) {
+ if (stat(rmtab.statefn, &stb) < 0) {
xlog(L_ERROR, "can't stat %s: %s",
- _PATH_RMTAB, strerror(errno));
+ rmtab.statefn, strerror(errno));
xfunlock(lockid);
return NULL;
}
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
index 20f4b79..cea850d 100644
--- a/utils/nfsd/nfsd.c
+++ b/utils/nfsd/nfsd.c
@@ -44,7 +44,9 @@ static struct option longopts[] =
{ "help", 0, 0, 'h' },
{ "no-nfs-version", 1, 0, 'N' },
{ "nfs-version", 1, 0, 'V' },
+ { "tcp", 0, 0, 't' },
{ "no-tcp", 0, 0, 'T' },
+ { "udp", 0, 0, 'u' },
{ "no-udp", 0, 0, 'U' },
{ "port", 1, 0, 'P' },
{ "port", 1, 0, 'p' },
@@ -67,8 +69,9 @@ main(int argc, char **argv)
int socket_up = 0;
unsigned int minorvers = 0;
unsigned int minorversset = 0;
+ unsigned int minormask = 0;
unsigned int versbits = NFSCTL_VERDEFAULT;
- unsigned int protobits = NFSCTL_ALLBITS;
+ unsigned int protobits = NFSCTL_PROTODEFAULT;
int grace = -1;
int lease = -1;
@@ -104,10 +107,16 @@ main(int argc, char **argv)
else
NFSCTL_VERUNSET(versbits, i);
}
+
+ nfssvc_get_minormask(&minormask);
/* We assume the kernel will default all minor versions to 'on',
* and allow the config file to disable some.
*/
- for (i = NFS4_MINMINOR; i <= NFS4_MAXMINOR; i++) {
+ if (NFSCTL_VERISSET(versbits, 4)) {
+ NFSCTL_MINORSET(minorversset, 0);
+ NFSCTL_MINORSET(minorvers, 0);
+ }
+ for (i = 1; i <= NFS4_MAXMINOR; i++) {
char tag[20];
sprintf(tag, "vers4.%d", i);
/* The default for minor version support is to let the
@@ -119,12 +128,12 @@ main(int argc, char **argv)
* (i.e. don't set the bit in minorversset).
*/
if (!conf_get_bool("nfsd", tag, 1)) {
- NFSCTL_VERSET(minorversset, i);
- NFSCTL_VERUNSET(minorvers, i);
+ NFSCTL_MINORSET(minorversset, i);
+ NFSCTL_MINORUNSET(minorvers, i);
}
if (conf_get_bool("nfsd", tag, 0)) {
- NFSCTL_VERSET(minorversset, i);
- NFSCTL_VERSET(minorvers, i);
+ NFSCTL_MINORSET(minorversset, i);
+ NFSCTL_MINORSET(minorvers, i);
}
}
@@ -138,7 +147,7 @@ main(int argc, char **argv)
}
}
- while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTUrG:L:", longopts, NULL)) != EOF) {
+ while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTitUrG:L:", longopts, NULL)) != EOF) {
switch(c) {
case 'd':
xlog_config(D_ALL, 1);
@@ -179,13 +188,17 @@ main(int argc, char **argv)
case 4:
if (*p == '.') {
int i = atoi(p+1);
- if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) {
+ if (i < 0 || i > NFS4_MAXMINOR) {
fprintf(stderr, "%s: unsupported minor version\n", optarg);
exit(1);
}
- NFSCTL_VERSET(minorversset, i);
- NFSCTL_VERUNSET(minorvers, i);
- break;
+ NFSCTL_MINORSET(minorversset, i);
+ NFSCTL_MINORUNSET(minorvers, i);
+ if (minorvers != 0)
+ break;
+ } else {
+ minorvers = 0;
+ minorversset = minormask;
}
case 3:
case 2:
@@ -201,14 +214,14 @@ main(int argc, char **argv)
case 4:
if (*p == '.') {
int i = atoi(p+1);
- if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) {
+ if (i < 0 || i > NFS4_MAXMINOR) {
fprintf(stderr, "%s: unsupported minor version\n", optarg);
exit(1);
}
- NFSCTL_VERSET(minorversset, i);
- NFSCTL_VERSET(minorvers, i);
- break;
- }
+ NFSCTL_MINORSET(minorversset, i);
+ NFSCTL_MINORSET(minorvers, i);
+ } else
+ minorvers = minorversset = minormask;
case 3:
case 2:
NFSCTL_VERSET(versbits, c);
@@ -222,9 +235,15 @@ main(int argc, char **argv)
xlog_syslog(1);
xlog_stderr(0);
break;
+ case 't':
+ NFSCTL_TCPSET(protobits);
+ break;
case 'T':
NFSCTL_TCPUNSET(protobits);
break;
+ case 'u':
+ NFSCTL_UDPSET(protobits);
+ break;
case 'U':
NFSCTL_UDPUNSET(protobits);
break;
@@ -372,9 +391,9 @@ usage(const char *prog)
{
fprintf(stderr, "Usage:\n"
"%s [-d|--debug] [-H hostname] [-p|-P|--port port]\n"
- " [-N|--no-nfs-version version] [-V|--nfs-version version]\n"
- " [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] [-r|--rdma=]\n"
- " [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n",
+ " [-N|--no-nfs-version version] [-V|--nfs-version version]\n"
+ " [-s|--syslog] [-t|--tcp] [-T|--no-tcp] [-u|--udp] [-U|--no-udp]\n"
+ " [-r|--rdma=] [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n",
prog);
exit(2);
}
diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man
index 8901fb6..d83ef86 100644
--- a/utils/nfsd/nfsd.man
+++ b/utils/nfsd/nfsd.man
@@ -57,7 +57,7 @@ This option can be used to request that
.B rpc.nfsd
does not offer certain versions of NFS. The current version of
.B rpc.nfsd
-can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2.
+can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2.
.TP
.B \-s " or " \-\-syslog
By default,
@@ -67,22 +67,24 @@ logs error messages (and debug messages, if enabled) to stderr. This option make
log these messages to syslog instead. Note that errors encountered during
option processing will still be logged to stderr regardless of this option.
.TP
+.B \-t " or " \-\-tcp
+Instruct the kernel nfs server to open and listen on a TCP socket. This is the default.
+.TP
.B \-T " or " \-\-no-tcp
-Disable
-.B rpc.nfsd
-from accepting TCP connections from clients.
+Instruct the kernel nfs server not to open and listen on a TCP socket.
+.TP
+.B \-u " or " \-\-udp
+Instruct the kernel nfs server to open and listen on a UDP socket.
.TP
.B \-U " or " \-\-no-udp
-Disable
-.B rpc.nfsd
-from accepting UDP connections from clients.
+Instruct the kernel nfs server not to open and listen on a UDP socket. This is the default.
.TP
.B \-V " or " \-\-nfs-version vers
This option can be used to request that
.B rpc.nfsd
offer certain versions of NFS. The current version of
.B rpc.nfsd
-can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2.
+can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2.
.TP
.B \-L " or " \-\-lease-time seconds
Set the lease-time used for NFSv4. This corresponds to how often
diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
index 07f6ff1..e8609c1 100644
--- a/utils/nfsd/nfssvc.c
+++ b/utils/nfsd/nfssvc.c
@@ -330,36 +330,78 @@ nfssvc_set_time(const char *type, const int seconds)
}
void
+nfssvc_get_minormask(unsigned int *mask)
+{
+ int fd;
+ char *ptr = buf;
+ ssize_t size;
+
+ fd = open(NFSD_VERS_FILE, O_RDONLY);
+ if (fd < 0)
+ return;
+
+ size = read(fd, buf, sizeof(buf));
+ if (size < 0) {
+ xlog(L_ERROR, "Getting versions failed: errno %d (%m)", errno);
+ goto out;
+ }
+ ptr[size] = '\0';
+ for (;;) {
+ unsigned vers, minor = 0;
+ char *token = strtok(ptr, " ");
+
+ if (!token)
+ break;
+ ptr = NULL;
+ if (*token != '+' && *token != '-')
+ continue;
+ if (sscanf(++token, "%u.%u", &vers, &minor) > 0 &&
+ vers == 4 && minor <= NFS4_MAXMINOR)
+ NFSCTL_MINORSET(*mask, minor);
+ }
+out:
+ close(fd);
+ return;
+}
+
+static int
+nfssvc_print_vers(char *ptr, unsigned size, unsigned vers, unsigned minorvers,
+ int isset)
+{
+ char sign = isset ? '+' : '-';
+ if (minorvers == 0)
+ return snprintf(ptr, size, "%c%u ", sign, vers);
+ return snprintf(ptr, size, "%c%u.%u ", sign, vers, minorvers);
+}
+
+void
nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers, unsigned int minorversset)
{
int fd, n, off;
- char *ptr;
- ptr = buf;
off = 0;
fd = open(NFSD_VERS_FILE, O_WRONLY);
if (fd < 0)
return;
- for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) {
- if (NFSCTL_VERISSET(minorversset, n)) {
- if (NFSCTL_VERISSET(minorvers, n))
- off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n);
- else
- off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n);
- }
- }
- for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) {
- if (NFSCTL_VERISSET(ctlbits, n))
- off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n);
- else
- off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n);
+ for (n = NFSD_MINVERS; n <= ((NFSD_MAXVERS < 3) ? NFSD_MAXVERS : 3); n++)
+ off += nfssvc_print_vers(&buf[off], sizeof(buf) - off,
+ n, 0, NFSCTL_VERISSET(ctlbits, n));
+
+ for (n = 0; n <= NFS4_MAXMINOR; n++) {
+ if (!NFSCTL_MINORISSET(minorversset, n))
+ continue;
+ off += nfssvc_print_vers(&buf[off], sizeof(buf) - off,
+ 4, n, NFSCTL_MINORISSET(minorvers, n));
}
+ if (!off--)
+ goto out;
+ buf[off] = '\0';
xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
- snprintf(ptr+off, sizeof(buf) - off, "\n");
+ snprintf(&buf[off], sizeof(buf) - off, "\n");
if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
-
+out:
close(fd);
return;
diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h
index cd5a7e8..39ebf37 100644
--- a/utils/nfsd/nfssvc.h
+++ b/utils/nfsd/nfssvc.h
@@ -28,3 +28,4 @@ void nfssvc_set_time(const char *type, const int seconds);
int nfssvc_set_rdmaport(const char *port);
void nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers4, unsigned int minorvers4set);
int nfssvc_threads(int nrservs);
+void nfssvc_get_minormask(unsigned int *mask);
diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am
index 152b680..ea32075 100644
--- a/utils/statd/Makefile.am
+++ b/utils/statd/Makefile.am
@@ -18,6 +18,7 @@ statd_LDADD = ../../support/nsm/libnsm.a \
$(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC)
sm_notify_LDADD = ../../support/nsm/libnsm.a \
../../support/nfs/libnfs.a \
+ ../../support/misc/libmisc.a \
$(LIBNSL) $(LIBCAP) $(LIBTIRPC)
EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c
diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c
index 623213e..0c6766f 100644
--- a/utils/statd/sm-notify.c
+++ b/utils/statd/sm-notify.c
@@ -45,6 +45,8 @@
#define NLM_END_GRACE_FILE "/proc/fs/lockd/nlm_end_grace"
+int lift_grace = 1;
+
struct nsm_host {
struct nsm_host * next;
char * name;
@@ -494,6 +496,7 @@ main(int argc, char **argv)
opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60;
opt_srcport = conf_get_str("sm-notify", "outgoing-port");
opt_srcaddr = conf_get_str("sm-notify", "outgoing-addr");
+ lift_grace = conf_get_bool("sm-notify", "lift-grace", lift_grace);
s = conf_get_str("statd", "state-directory-path");
if (s && !nsm_setup_pathnames(argv[0], s))
exit(1);
@@ -570,7 +573,8 @@ usage: fprintf(stderr,
(void)nsm_retire_monitored_hosts();
if (nsm_load_notify_list(smn_get_host) == 0) {
xlog(D_GENERAL, "No hosts to notify; exiting");
- nsm_lift_grace_period();
+ if (lift_grace)
+ nsm_lift_grace_period();
return 0;
}
diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man
index bb7f6e0..cfe1e4b 100644
--- a/utils/statd/sm-notify.man
+++ b/utils/statd/sm-notify.man
@@ -241,6 +241,24 @@ These have the same effect as the command line options
.B v
respectively.
+An additional value recognized in the
+.B [sm-notify]
+section is
+.BR lift-grace .
+By default,
+.B sm-notify
+will lift lockd's grace period early if it has no hosts to notify.
+Some high availability configurations will run one
+.B sm-notify
+per floating IP address. In these configurations, lifting the
+grace period early may prevent clients from reclaiming locks.
+.RB "Setting " lift-grace " to " n
+will prevent
+.B sm-notify
+from ending the grace period early.
+.B lift-grace
+has no corresponding command line option.
+
The value recognized in the
.B [statd]
section is