From 49f282cd1453d8c3e9d913ab10c154d6b962ef45 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Mon, 10 Apr 2017 09:40:23 -0400 Subject: [PATCH] Updated to the latest RC release: nfs-utils-2-1-2-rc2 (bz 1419351) Signed-off-by: Steve Dickson --- nfs-utils-2.1.1-nfs-config.patch | 42 +- nfs-utils-2.1.2-rc2.patch | 2338 ++++++++++++++++++++++++++++++ nfs-utils.spec | 7 +- 3 files changed, 2363 insertions(+), 24 deletions(-) create mode 100644 nfs-utils-2.1.2-rc2.patch diff --git a/nfs-utils-2.1.1-nfs-config.patch b/nfs-utils-2.1.1-nfs-config.patch index 6abdf20..5bfd7fc 100644 --- a/nfs-utils-2.1.1-nfs-config.patch +++ b/nfs-utils-2.1.1-nfs-config.patch @@ -1,6 +1,6 @@ diff -up nfs-utils-2.1.1/configure.ac.orig nfs-utils-2.1.1/configure.ac --- nfs-utils-2.1.1/configure.ac.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/configure.ac 2017-02-15 10:53:12.623674876 -0500 ++++ nfs-utils-2.1.1/configure.ac 2017-04-09 15:30:50.812286349 -0400 @@ -518,6 +518,11 @@ AC_SUBST([AM_CFLAGS], ["$my_am_cflags"]) # Make sure that $ACLOCAL_FLAGS are used during a rebuild AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \$(ACLOCAL_FLAGS)"]) @@ -22,19 +22,19 @@ diff -up nfs-utils-2.1.1/configure.ac.orig nfs-utils-2.1.1/configure.ac linux-nfs/Makefile support/Makefile diff -up nfs-utils-2.1.1/systemd/Makefile.am.orig nfs-utils-2.1.1/systemd/Makefile.am ---- nfs-utils-2.1.1/systemd/Makefile.am.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/Makefile.am 2017-02-15 10:53:12.623674876 -0500 -@@ -5,6 +5,7 @@ MAINTAINERCLEANFILES = Makefile.in - unit_files = \ +--- nfs-utils-2.1.1/systemd/Makefile.am.orig 2017-04-09 15:29:49.687515444 -0400 ++++ nfs-utils-2.1.1/systemd/Makefile.am 2017-04-09 15:30:50.813286345 -0400 +@@ -6,6 +6,7 @@ unit_files = \ nfs-client.target \ + rpc_pipefs.target \ \ + nfs-config.service \ nfs-mountd.service \ nfs-server.service \ nfs-utils.service \ diff -up nfs-utils-2.1.1/systemd/nfs-blkmap.service.orig nfs-utils-2.1.1/systemd/nfs-blkmap.service ---- nfs-utils-2.1.1/systemd/nfs-blkmap.service.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/nfs-blkmap.service 2017-02-15 10:53:12.624674873 -0500 +--- nfs-utils-2.1.1/systemd/nfs-blkmap.service.orig 2017-04-09 15:29:49.687515444 -0400 ++++ nfs-utils-2.1.1/systemd/nfs-blkmap.service 2017-04-09 15:30:50.813286345 -0400 @@ -10,7 +10,8 @@ PartOf=nfs-utils.service [Service] Type=forking @@ -46,8 +46,8 @@ diff -up nfs-utils-2.1.1/systemd/nfs-blkmap.service.orig nfs-utils-2.1.1/systemd [Install] WantedBy=nfs-client.target diff -up nfs-utils-2.1.1/systemd/nfs-config.service.in.orig nfs-utils-2.1.1/systemd/nfs-config.service.in ---- nfs-utils-2.1.1/systemd/nfs-config.service.in.orig 2017-02-15 10:53:12.624674873 -0500 -+++ nfs-utils-2.1.1/systemd/nfs-config.service.in 2017-02-15 10:53:12.624674873 -0500 +--- nfs-utils-2.1.1/systemd/nfs-config.service.in.orig 2017-04-09 15:30:50.813286345 -0400 ++++ nfs-utils-2.1.1/systemd/nfs-config.service.in 2017-04-09 15:30:50.813286345 -0400 @@ -0,0 +1,13 @@ +[Unit] +Description=Preprocess NFS configuration @@ -63,9 +63,9 @@ diff -up nfs-utils-2.1.1/systemd/nfs-config.service.in.orig nfs-utils-2.1.1/syst +RemainAfterExit=no +ExecStart=@_libexecdir@/nfs-utils/nfs-utils_env.sh diff -up nfs-utils-2.1.1/systemd/nfs-idmapd.service.orig nfs-utils-2.1.1/systemd/nfs-idmapd.service ---- nfs-utils-2.1.1/systemd/nfs-idmapd.service.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/nfs-idmapd.service 2017-02-15 10:53:12.625674869 -0500 -@@ -6,6 +6,10 @@ After=var-lib-nfs-rpc_pipefs.mount local +--- nfs-utils-2.1.1/systemd/nfs-idmapd.service.orig 2017-04-09 15:29:49.687515444 -0400 ++++ nfs-utils-2.1.1/systemd/nfs-idmapd.service 2017-04-09 15:30:50.813286345 -0400 +@@ -6,6 +6,10 @@ After=rpc_pipefs.target local-fs.target BindsTo=nfs-server.service @@ -78,8 +78,8 @@ diff -up nfs-utils-2.1.1/systemd/nfs-idmapd.service.orig nfs-utils-2.1.1/systemd -ExecStart=/usr/sbin/rpc.idmapd +ExecStart=/usr/sbin/rpc.idmapd $RPCIDMAPDARGS diff -up nfs-utils-2.1.1/systemd/nfs-mountd.service.orig nfs-utils-2.1.1/systemd/nfs-mountd.service ---- nfs-utils-2.1.1/systemd/nfs-mountd.service.orig 2017-02-15 10:52:26.501835762 -0500 -+++ nfs-utils-2.1.1/systemd/nfs-mountd.service 2017-02-15 10:53:12.625674869 -0500 +--- nfs-utils-2.1.1/systemd/nfs-mountd.service.orig 2017-04-09 15:29:49.687515444 -0400 ++++ nfs-utils-2.1.1/systemd/nfs-mountd.service 2017-04-09 15:30:50.814286341 -0400 @@ -7,6 +7,10 @@ After=network.target local-fs.target After=rpcbind.socket BindsTo=nfs-server.service @@ -93,8 +93,8 @@ diff -up nfs-utils-2.1.1/systemd/nfs-mountd.service.orig nfs-utils-2.1.1/systemd -ExecStart=/usr/sbin/rpc.mountd +ExecStart=/usr/sbin/rpc.mountd $RPCMOUNTDARGS diff -up nfs-utils-2.1.1/systemd/nfs-server.service.orig nfs-utils-2.1.1/systemd/nfs-server.service ---- nfs-utils-2.1.1/systemd/nfs-server.service.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/nfs-server.service 2017-02-15 10:53:12.626674866 -0500 +--- nfs-utils-2.1.1/systemd/nfs-server.service.orig 2017-04-09 15:29:49.687515444 -0400 ++++ nfs-utils-2.1.1/systemd/nfs-server.service 2017-04-09 15:30:50.814286341 -0400 @@ -16,11 +16,16 @@ Before= rpc-statd-notify.service Wants=auth-rpcgss-module.service After=rpc-gssd.service gssproxy.service rpc-svcgssd.service @@ -115,7 +115,7 @@ diff -up nfs-utils-2.1.1/systemd/nfs-server.service.orig nfs-utils-2.1.1/systemd ExecStopPost=/usr/sbin/exportfs -f diff -up nfs-utils-2.1.1/systemd/README.orig nfs-utils-2.1.1/systemd/README --- nfs-utils-2.1.1/systemd/README.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/README 2017-02-15 10:53:12.626674866 -0500 ++++ nfs-utils-2.1.1/systemd/README 2017-04-09 15:30:50.814286341 -0400 @@ -19,8 +19,8 @@ by a suitable 'preset' setting: can work (if no type is given, ".service" is assumed). @@ -153,8 +153,8 @@ diff -up nfs-utils-2.1.1/systemd/README.orig nfs-utils-2.1.1/systemd/README rpc.gssd and rpc.svcgssd are assumed to be needed if /etc/krb5.keytab is present. diff -up nfs-utils-2.1.1/systemd/rpc-gssd.service.in.orig nfs-utils-2.1.1/systemd/rpc-gssd.service.in ---- nfs-utils-2.1.1/systemd/rpc-gssd.service.in.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/rpc-gssd.service.in 2017-02-15 10:53:12.627674862 -0500 +--- nfs-utils-2.1.1/systemd/rpc-gssd.service.in.orig 2017-04-09 15:29:49.687515444 -0400 ++++ nfs-utils-2.1.1/systemd/rpc-gssd.service.in 2017-04-09 15:30:50.814286341 -0400 @@ -9,6 +9,11 @@ ConditionPathExists=@_sysconfdir@/krb5.k PartOf=nfs-utils.service @@ -170,7 +170,7 @@ diff -up nfs-utils-2.1.1/systemd/rpc-gssd.service.in.orig nfs-utils-2.1.1/system +ExecStart=/usr/sbin/rpc.gssd $RPCGSSDARGS diff -up nfs-utils-2.1.1/systemd/rpc-statd-notify.service.orig nfs-utils-2.1.1/systemd/rpc-statd-notify.service --- nfs-utils-2.1.1/systemd/rpc-statd-notify.service.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/rpc-statd-notify.service 2017-02-15 10:53:12.627674862 -0500 ++++ nfs-utils-2.1.1/systemd/rpc-statd-notify.service 2017-04-09 15:30:50.814286341 -0400 @@ -10,6 +10,10 @@ After=nfs-server.service PartOf=nfs-utils.service @@ -185,7 +185,7 @@ diff -up nfs-utils-2.1.1/systemd/rpc-statd-notify.service.orig nfs-utils-2.1.1/s +ExecStart=-/usr/sbin/sm-notify $SMNOTIFYARGS diff -up nfs-utils-2.1.1/systemd/rpc-statd.service.orig nfs-utils-2.1.1/systemd/rpc-statd.service --- nfs-utils-2.1.1/systemd/rpc-statd.service.orig 2017-01-12 10:21:39.000000000 -0500 -+++ nfs-utils-2.1.1/systemd/rpc-statd.service 2017-02-15 10:53:12.627674862 -0500 ++++ nfs-utils-2.1.1/systemd/rpc-statd.service 2017-04-09 15:30:50.815286338 -0400 @@ -7,8 +7,12 @@ After=network.target nss-lookup.target r PartOf=nfs-utils.service diff --git a/nfs-utils-2.1.2-rc2.patch b/nfs-utils-2.1.2-rc2.patch new file mode 100644 index 0000000..abff896 --- /dev/null +++ b/nfs-utils-2.1.2-rc2.patch @@ -0,0 +1,2338 @@ +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 + #include + #include ++#include ++#include ++#include ++#include + + #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 . ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + #include + ++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 ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++ ++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 + #include + ++#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 + #include + #include ++#include + + #include + #include +@@ -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 diff --git a/nfs-utils.spec b/nfs-utils.spec index 97b338a..64acd74 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 2.1.1 -Release: 4.rc1%{?dist} +Release: 4.rc2%{?dist} Epoch: 1 # group all 32bit related archs @@ -15,7 +15,7 @@ Source3: nfs-utils_env.sh Source4: lockd.conf Source5: 24-nfs-server.conf -Patch001: nfs-utils-2.1.2-rc1.patch +Patch001: nfs-utils-2.1.2-rc2.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -285,7 +285,8 @@ fi /sbin/umount.nfs4 %changelog -* Fri Apr 7 2017 Steve Dickson 2.1.1-4.rc1 +* Mon Apr 10 2017 Steve Dickson 2.1.1-4.rc2 +- Updated to the latest RC release: nfs-utils-2-1-2-rc2 (bz 1419351) - Fixed typo in nfs.sysconfig (bz 1422249) * Tue Mar 28 2017 Steve Dickson 2.1.1-3.rc1