nfs-utils/nfs-utils-2.5.3-rc4.patch
DistroBaker a76d4b5aff Merged update from upstream sources
This is an automated DistroBaker update from upstream sources.
If you do not know what this is about or would like to opt out,
contact the OSCI team.

Source: https://src.fedoraproject.org/rpms/nfs-utils.git#0435d8596e2ab632d45dbbb0a3384cc7d4c97208
2021-01-08 15:23:19 +00:00

1118 lines
30 KiB
Diff

diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
index 8efbfcd..65e53c1 100644
--- a/support/misc/nfsd_path.c
+++ b/support/misc/nfsd_path.c
@@ -110,7 +110,7 @@ nfsd_setup_workqueue(void)
if (!rootdir)
return;
-printf("rootdir %s\n", rootdir);
+
nfsd_wq = xthread_workqueue_alloc();
if (!nfsd_wq)
return;
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index 3d13610..a4ea067 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -52,10 +52,14 @@
#include <libgen.h>
#include <sys/file.h>
#include <time.h>
+#include <dirent.h>
#include "conffile.h"
#include "xlog.h"
+#define CONF_FILE_EXT ".conf"
+#define CONF_FILE_EXT_LEN ((int) (sizeof(CONF_FILE_EXT) - 1))
+
#pragma GCC visibility push(hidden)
static void conf_load_defaults(void);
@@ -456,7 +460,7 @@ conf_parse_line(int trans, char *line, const char *filename, int lineno, char **
free(subconf);
} else {
/* XXX Perhaps should we not ignore errors? */
- conf_set(trans, *section, *subsection, line, val, 0, 0);
+ conf_set(trans, *section, *subsection, line, val, 1, 0);
}
}
@@ -577,6 +581,30 @@ static void conf_free_bindings(void)
}
}
+static int
+conf_load_files(int trans, const char *conf_file)
+{
+ char *conf_data;
+ char *section = NULL;
+ char *subsection = NULL;
+
+ conf_data = conf_readfile(conf_file);
+ if (conf_data == NULL)
+ return 1;
+
+ /* Load default configuration values. */
+ conf_load_defaults();
+
+ /* Parse config contents into the transaction queue */
+ conf_parse(trans, conf_data, &section, &subsection, conf_file);
+ if (section)
+ free(section);
+ if (subsection)
+ free(subsection);
+ free(conf_data);
+
+ return 0;
+}
/* Open the config file and map it into our address space, then parse it. */
static int
conf_load_file(const char *conf_file)
@@ -609,18 +637,129 @@ conf_load_file(const char *conf_file)
return 0;
}
+static void
+conf_init_dir(const char *conf_file)
+{
+ struct dirent **namelist = NULL;
+ char *dname, fname[PATH_MAX], *cname;
+ int n = 0, nfiles = 0, i, fname_len, dname_len;
+ int trans, rv, path_len;
+
+ dname = malloc(strlen(conf_file) + 3);
+ if (dname == NULL) {
+ xlog(L_WARNING, "conf_init_dir: malloc: %s", strerror(errno));
+ return;
+ }
+ sprintf(dname, "%s.d", conf_file);
+
+ n = scandir(dname, &namelist, NULL, versionsort);
+ if (n < 0) {
+ if (errno != ENOENT) {
+ xlog(L_WARNING, "conf_init_dir: scandir %s: %s",
+ dname, strerror(errno));
+ }
+ free(dname);
+ return;
+ } else if (n == 0) {
+ free(dname);
+ return;
+ }
+
+ trans = conf_begin();
+ dname_len = strlen(dname);
+ for (i = 0; i < n; i++ ) {
+ struct dirent *d = namelist[i];
+
+ switch (d->d_type) {
+ case DT_UNKNOWN:
+ case DT_REG:
+ case DT_LNK:
+ break;
+ default:
+ continue;
+ }
+ if (*d->d_name == '.')
+ continue;
+
+ fname_len = strlen(d->d_name);
+ path_len = (fname_len + dname_len);
+ if (!fname_len || path_len > PATH_MAX) {
+ xlog(L_WARNING, "conf_init_dir: Too long file name: %s in %s",
+ d->d_name, dname);
+ continue;
+ }
+
+ /*
+ * Check the naming of the file. Only process files
+ * that end with CONF_FILE_EXT
+ */
+ if (fname_len <= CONF_FILE_EXT_LEN) {
+ xlog(D_GENERAL, "conf_init_dir: %s: name too short",
+ d->d_name);
+ continue;
+ }
+ cname = (d->d_name + (fname_len - CONF_FILE_EXT_LEN));
+ if (strcmp(cname, CONF_FILE_EXT) != 0) {
+ xlog(D_GENERAL, "conf_init_dir: %s: invalid file extension",
+ d->d_name);
+ continue;
+ }
+
+ rv = snprintf(fname, PATH_MAX, "%s/%s", dname, d->d_name);
+ if (rv < path_len) {
+ xlog(L_WARNING, "conf_init_dir: file name: %s/%s too short",
+ d->d_name, dname);
+ continue;
+ }
+
+ if (conf_load_files(trans, fname))
+ continue;
+ nfiles++;
+ }
+
+ if (nfiles) {
+ /* Apply the configuration values */
+ conf_end(trans, 1);
+ }
+ for (i = 0; i < n; i++)
+ free(namelist[i]);
+ free(namelist);
+ free(dname);
+
+ return;
+}
+
int
conf_init_file(const char *conf_file)
{
unsigned int i;
+ int ret;
for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
LIST_INIT (&conf_bindings[i]);
TAILQ_INIT (&conf_trans_queue);
- if (conf_file == NULL) conf_file=NFS_CONFFILE;
- return conf_load_file(conf_file);
+ if (conf_file == NULL)
+ conf_file=NFS_CONFFILE;
+
+ /*
+ * First parse the give config file
+ * then parse the config.conf.d directory
+ * (if it exists)
+ *
+ */
+ ret = conf_load_file(conf_file);
+
+ /*
+ * When the same variable is set in both files
+ * the conf.d file will override the config file.
+ * This allows automated admin systems to
+ * have the final say.
+ */
+ conf_init_dir(conf_file);
+
+ return ret;
}
/*
diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service
index 06c1adb..b432f91 100644
--- a/systemd/nfs-server.service
+++ b/systemd/nfs-server.service
@@ -21,13 +21,13 @@ After=rpc-gssd.service gssproxy.service rpc-svcgssd.service
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStartPre=/usr/sbin/exportfs -r
+ExecStartPre=-/usr/sbin/exportfs -r
ExecStart=/usr/sbin/rpc.nfsd
ExecStop=/usr/sbin/rpc.nfsd 0
ExecStopPost=/usr/sbin/exportfs -au
ExecStopPost=/usr/sbin/exportfs -f
-ExecReload=/usr/sbin/exportfs -r
+ExecReload=-/usr/sbin/exportfs -r
[Install]
WantedBy=multi-user.target
diff --git a/systemd/nfs-v4client.target b/systemd/nfs-v4client.target
new file mode 100644
index 0000000..3d1064e
--- /dev/null
+++ b/systemd/nfs-v4client.target
@@ -0,0 +1,12 @@
+[Unit]
+Description=NFS client services
+Before=remote-fs-pre.target
+Wants=remote-fs-pre.target
+
+# GSS services dependencies and ordering
+Wants=auth-rpcgss-module.service
+After=rpc-gssd.service rpc-svcgssd.service gssproxy.service
+
+[Install]
+WantedBy=multi-user.target
+WantedBy=remote-fs.target
diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man
index 3f1c726..16e0ec4 100644
--- a/systemd/nfs.conf.man
+++ b/systemd/nfs.conf.man
@@ -265,7 +265,15 @@ Only
is recognized.
.SH FILES
+.TP 10n
.I /etc/nfs.conf
+Default NFS client configuration file
+.TP 10n
+.I /etc/nfs.conf.d
+When this directory exists and files ending
+with ".conf" exist, those files will be
+used to set configuration variables. These
+files will override variables set in /etc/nfs.conf
.SH SEE ALSO
.BR nfsdcltrack (8),
.BR rpc.nfsd (8),
diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py
index 25e92a1..23876fc 100755
--- a/tools/mountstats/mountstats.py
+++ b/tools/mountstats/mountstats.py
@@ -378,7 +378,10 @@ class DeviceData:
print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op])))
elif vers == '4':
for op in Nfsv4ops:
- print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op])))
+ try:
+ print('\t%12s: %s' % (op, " ".join(str(x) for x in self.__rpc_data[op])))
+ except KeyError:
+ continue
else:
print('\tnot implemented for version %d' % vers)
print()
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index 9d5e575..9fcae0b 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -176,10 +176,10 @@ main(int argc, char **argv)
xlog(L_ERROR, "-r and -u are incompatible");
return 1;
}
-printf("point 1\n");
+
if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
return 1;
-printf("point 2\n");
+
if (optind == argc && ! f_all) {
if (force_flush) {
cache_flush(1);
@@ -193,7 +193,6 @@ printf("point 2\n");
return 0;
}
}
-printf("point 3\n");
/*
* Serialize things as best we can
diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man
index 1d17184..54b3f87 100644
--- a/utils/exportfs/exports.man
+++ b/utils/exportfs/exports.man
@@ -169,13 +169,6 @@ default. In all releases after 1.0.0,
is the default, and
.I async
must be explicitly requested if needed.
-To help make system administrators aware of this change,
-.B exportfs
-will issue a warning if neither
-.I sync
-nor
-.I async
-is specified.
.TP
.IR no_wdelay
This option has no effect if
diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
index 93fe500..e865998 100644
--- a/utils/mount/configfile.c
+++ b/utils/mount/configfile.c
@@ -1,5 +1,5 @@
/*
- * configfile.c -- mount configuration file manipulation
+ * configfile.c -- mount configuration file manipulation
* Copyright (C) 2008 Red Hat, Inc <nfs@redhat.com>
*
* - Routines use to create mount options from the mount
@@ -34,10 +34,7 @@
#include "parse_opt.h"
#include "network.h"
#include "conffile.h"
-
-char *mountopts_convert(char *value);
-char *is_alias(char *opt);
-char *conf_get_mntopts(char *spec, char *mount_point, char *mount_opts);
+#include "mount_config.h"
#define KBYTES(x) ((x) * (1024))
#define MEGABYTES(x) ((x) * (1048576))
@@ -70,17 +67,31 @@ struct mnt_alias {
{"background", "bg", MNT_NOARG},
{"foreground", "fg", MNT_NOARG},
{"sloppy", "sloppy", MNT_NOARG},
- {"nfsvers", "vers", MNT_UNSET},
};
int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0]));
+static const char *version_keys[] = {
+ "v2", "v3", "v4", "vers", "nfsvers", "minorversion", NULL
+};
+
static int strict;
+static int is_version(const char *field)
+{
+ int i;
+ for (i = 0; version_keys[i] ; i++)
+ if (strcmp(version_keys[i], field) == 0)
+ return 1;
+ if (strncmp(field, "v4.", 3) == 0)
+ return 1;
+ return 0;
+}
+
/*
- * See if the option is an alias, if so return the
+ * See if the option is an alias, if so return the
* real mount option along with the argument type.
*/
-inline static
+inline static
char *mountopts_alias(char *opt, int *argtype)
{
int i;
@@ -99,10 +110,10 @@ char *mountopts_alias(char *opt, int *argtype)
}
/*
* Convert numeric strings that end with 'k', 'm' or 'g'
- * into numeric strings with the real value.
+ * into numeric strings with the real value.
* Meaning '8k' becomes '8094'.
*/
-char *mountopts_convert(char *value)
+static char *mountopts_convert(char *value)
{
unsigned long long factor, num;
static char buf[64];
@@ -136,110 +147,16 @@ char *mountopts_convert(char *value)
return buf;
}
-struct entry {
- SLIST_ENTRY(entry) entries;
- char *opt;
-};
-static SLIST_HEAD(shead, entry) head = SLIST_HEAD_INITIALIZER(head);
-static int list_size;
-
-/*
- * Add option to the link list
- */
-inline static void
-add_entry(char *opt)
-{
- struct entry *entry;
-
- entry = calloc(1, sizeof(struct entry));
- if (entry == NULL) {
- xlog_warn("Unable calloc memory for mount configs");
- return;
- }
- entry->opt = strdup(opt);
- if (entry->opt == NULL) {
- xlog_warn("Unable calloc memory for mount opts");
- free(entry);
- return;
- }
- SLIST_INSERT_HEAD(&head, entry, entries);
-}
-/*
- * Check the alias list to see if the given
- * opt is a alias
- */
-char *is_alias(char *opt)
-{
- int i;
-
- for (i=0; i < mnt_alias_sz; i++) {
- if (strcasecmp(opt, mnt_alias_tab[i].alias) == 0)
- return mnt_alias_tab[i].opt;
- }
- return NULL;
-}
-/*
- * See if the given entry exists if the link list,
- * if so return that entry
- */
-inline static
-char *lookup_entry(char *opt)
-{
- struct entry *entry;
- char *alias = is_alias(opt);
- char *ptr;
-
- SLIST_FOREACH(entry, &head, entries) {
- /*
- * Only check the left side or options that use '='
- */
- if ((ptr = strchr(entry->opt, '=')) != 0) {
- int len = (int) (ptr - entry->opt);
-
- if (strncasecmp(entry->opt, opt, len) == 0)
- return opt;
- }
- if (strcasecmp(entry->opt, opt) == 0)
- return opt;
- if (alias && strcasecmp(entry->opt, alias) == 0)
- return opt;
- if (alias && strcasecmp(alias, "fg") == 0) {
- if (strcasecmp(entry->opt, "bg") == 0)
- return opt;
- }
- if (alias && strcasecmp(alias, "bg") == 0) {
- if (strcasecmp(entry->opt, "fg") == 0)
- return opt;
- }
- }
- return NULL;
-}
-/*
- * Free all entries on the link list
- */
-inline static
-void free_all(void)
-{
- struct entry *entry;
-
- while (!SLIST_EMPTY(&head)) {
- entry = SLIST_FIRST(&head);
- SLIST_REMOVE_HEAD(&head, entries);
- free(entry->opt);
- free(entry);
- }
-}
-
struct nfs_version config_default_vers;
unsigned long config_default_proto;
extern sa_family_t config_default_family;
/*
* Check to see if a default value is being set.
- * If so, set the appropriate global value which will
+ * If so, set the appropriate global value which will
* be used as the initial value in the server negation.
*/
-static int
+static int
default_value(char *mopt)
{
struct mount_options *options = NULL;
@@ -253,11 +170,11 @@ default_value(char *mopt)
if (strncasecmp(field, "proto", strlen("proto")) == 0) {
if ((options = po_split(field)) != NULL) {
if (!nfs_nfs_protocol(options, &config_default_proto)) {
- xlog_warn("Unable to set default protocol : %s",
+ xlog_warn("Unable to set default protocol : %s",
strerror(errno));
}
if (!nfs_nfs_proto_family(options, &config_default_family)) {
- xlog_warn("Unable to set default family : %s",
+ xlog_warn("Unable to set default family : %s",
strerror(errno));
}
} else {
@@ -266,14 +183,13 @@ default_value(char *mopt)
} else if (strncasecmp(field, "vers", strlen("vers")) == 0) {
if ((options = po_split(field)) != NULL) {
if (!nfs_nfs_version("nfs", options, &config_default_vers)) {
- xlog_warn("Unable to set default version: %s",
+ xlog_warn("Unable to set default version: %s",
strerror(errno));
-
}
} else {
xlog_warn("Unable to alloc memory for default version");
}
- } else
+ } else
xlog_warn("Invalid default setting: '%s'", mopt);
if (options)
@@ -282,32 +198,60 @@ default_value(char *mopt)
return 1;
}
/*
- * Parse the given section of the configuration
+ * Parse the given section of the configuration
* file to if there are any mount options set.
* If so, added them to link list.
*/
-static void
-conf_parse_mntopts(char *section, char *arg, char *opts)
+static void
+conf_parse_mntopts(char *section, char *arg, struct mount_options *options)
{
struct conf_list *list;
struct conf_list_node *node;
char buf[BUFSIZ], *value, *field;
char *nvalue, *ptr;
int argtype;
+ int have_version = 0;
+
+ if (po_rightmost(options, version_keys) >= 0 ||
+ po_contains_prefix(options, "v4.", NULL, 0) == PO_FOUND)
+ have_version = 1;
list = conf_get_tag_list(section, arg);
TAILQ_FOREACH(node, &list->fields, link) {
- /* check first if this is an alias for another option */
- field = mountopts_alias(node->field, &argtype);
/*
- * Do not overwrite options if already exists
+ * Do not overwrite options if already exists
*/
- snprintf(buf, BUFSIZ, "%s=", field);
- if (opts && strcasestr(opts, buf) != NULL)
+ field = mountopts_alias(node->field, &argtype);
+ if (po_contains(options, field) == PO_FOUND)
+ continue;
+ /* Some options can be inverted by a "no" prefix.
+ * Check for these.
+ * "no" prefixes are unlikely in the config file as
+ * "option=false" is preferred, but still possible.
+ */
+ if (strncmp(field, "no", 2) == 0 &&
+ po_contains(options, field+2) == PO_FOUND)
continue;
+ if (strlen(field) < BUFSIZ-3) {
+ strcat(strcpy(buf, "no"), field);
+ if (po_contains(options, buf) == PO_FOUND)
+ continue;
+ }
- if (lookup_entry(field) != NULL)
+ /* If fg or bg already present, ignore bg or fg */
+ if (strcmp(field, "fg") == 0 &&
+ po_contains(options, "bg") == PO_FOUND)
continue;
+ if (strcmp(field, "bg") == 0 &&
+ po_contains(options, "fg") == PO_FOUND)
+ continue;
+
+ if (is_version(field)) {
+ if (have_version)
+ continue;
+ have_version = 1;
+ }
+
buf[0] = '\0';
value = conf_get_section(section, arg, node->field);
if (value == NULL)
@@ -333,99 +277,68 @@ conf_parse_mntopts(char *section, char *arg, char *opts)
}
if (buf[0] == '\0')
continue;
- /*
- * Keep a running tally of the list size adding
- * one for the ',' that will be appened later
- */
- list_size += strlen(buf) + 1;
- add_entry(buf);
+ if (default_value(buf))
+ continue;
+
+ po_append(options, buf);
}
conf_free_list(list);
}
/*
- * Concatenate options from the configuration file with the
+ * Concatenate options from the configuration file with the
* given options by building a link list of options from the
- * different sections in the conf file. Options that exists
- * in the either the given options or link list are not
+ * different sections in the conf file. Options that exists
+ * in the either the given options or link list are not
* overwritten so it matter which when each section is
- * parsed.
+ * parsed.
*/
-char *conf_get_mntopts(char *spec, char *mount_point,
- char *mount_opts)
+char *conf_get_mntopts(char *spec, char *mount_point,
+ char *mount_opts)
{
- struct entry *entry;
- char *ptr, *server, *config_opts;
- int optlen = 0;
+ struct mount_options *options;
+ char *ptr, *server;
strict = 0;
- SLIST_INIT(&head);
- list_size = 0;
+ options = po_split(mount_opts);
+ if (!options) {
+ xlog_warn("conf_get_mountops: Unable calloc memory for options");
+ return mount_opts;
+ }
/*
- * First see if there are any mount options relative
+ * First see if there are any mount options relative
* to the mount point.
*/
- conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, mount_opts);
+ conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, options);
- /*
+ /*
* Next, see if there are any mount options relative
* to the server
*/
server = strdup(spec);
if (server == NULL) {
- xlog_warn("conf_get_mountops: Unable calloc memory for server");
- free_all();
+ xlog_warn("conf_get_mountops: Unable calloc memory for server");
+ po_destroy(options);
return mount_opts;
}
if ((ptr = strchr(server, ':')) != NULL)
*ptr='\0';
- conf_parse_mntopts(NFSMOUNT_SERVER, server, mount_opts);
+ conf_parse_mntopts(NFSMOUNT_SERVER, server, options);
free(server);
/*
- * Finally process all the global mount options.
- */
- conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts);
-
- /*
- * If no mount options were found in the configuration file
- * just return what was passed in .
+ * Finally process all the global mount options.
*/
- if (SLIST_EMPTY(&head))
- return mount_opts;
+ conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, options);
/*
- * Found options in the configuration file. So
- * concatenate the configuration options with the
- * options that were passed in
+ * Strip out defaults, which have already been handled,
+ * then join the rest and return.
*/
- if (mount_opts)
- optlen = strlen(mount_opts);
-
- /* list_size + optlen + ',' + '\0' */
- config_opts = calloc(1, (list_size+optlen+2));
- if (config_opts == NULL) {
- xlog_warn("conf_get_mountops: Unable calloc memory for config_opts");
- free_all();
- return mount_opts;
- }
-
- if (mount_opts) {
- strcpy(config_opts, mount_opts);
- strcat(config_opts, ",");
- }
- SLIST_FOREACH(entry, &head, entries) {
- if (default_value(entry->opt))
- continue;
- strcat(config_opts, entry->opt);
- strcat(config_opts, ",");
- }
- if ((ptr = strrchr(config_opts, ',')) != NULL)
- *ptr = '\0';
+ po_remove_all(options, "default");
- free_all();
- if (mount_opts)
- free(mount_opts);
+ po_join(options, &mount_opts);
+ po_destroy(options);
- return config_opts;
+ return mount_opts;
}
diff --git a/utils/mount/network.c b/utils/mount/network.c
index d9c0b51..e803dbb 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -1269,27 +1269,31 @@ int
nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *version)
{
char *version_key, *version_val = NULL, *cptr;
- int i, found = 0;
+ int i, found = -1;
version->v_mode = V_DEFAULT;
for (i = 0; nfs_version_opttbl[i]; i++) {
if (po_contains_prefix(options, nfs_version_opttbl[i],
- &version_key) == PO_FOUND) {
- found++;
- break;
+ &version_key, 0) == PO_FOUND) {
+ if (found >= 0)
+ goto ret_error_multiple;
+ if (po_contains_prefix(options, nfs_version_opttbl[i],
+ NULL, 1) == PO_FOUND)
+ goto ret_error_multiple;
+ found = i;
}
}
- if (!found && strcmp(type, "nfs4") == 0)
+ if (found < 0 && strcmp(type, "nfs4") == 0)
version_val = type + 3;
- else if (!found)
+ else if (found < 0)
return 1;
- else if (i <= 2 ) {
+ else if (found <= 2 ) {
/* v2, v3, v4 */
version_val = version_key + 1;
version->v_mode = V_SPECIFIC;
- } else if (i > 2 ) {
+ } else if (found > 2 ) {
/* vers=, nfsvers= */
version_val = po_get(options, version_key);
}
@@ -1303,7 +1307,7 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v
if (version->major == 4 && *cptr != '.' &&
(version_val = po_get(options, "minorversion")) != NULL) {
version->minor = strtol(version_val, &cptr, 10);
- i = -1;
+ found = -1;
if (*cptr)
goto ret_error;
version->v_mode = V_SPECIFIC;
@@ -1319,7 +1323,7 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v
if (version_val != NULL) {
version->minor = strtol(version_val, &cptr, 10);
version->v_mode = V_SPECIFIC;
- } else
+ } else
version->v_mode = V_GENERAL;
}
if (*cptr != '\0')
@@ -1327,17 +1331,21 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v
return 1;
+ret_error_multiple:
+ nfs_error(_("%s: multiple version options not permitted"),
+ progname);
+ found = 10; /* avoid other errors */
ret_error:
- if (i < 0) {
+ if (found < 0) {
nfs_error(_("%s: parsing error on 'minorversion=' option"),
progname);
- } else if (i <= 2 ) {
+ } else if (found <= 2 ) {
nfs_error(_("%s: parsing error on 'v' option"),
progname);
- } else if (i == 3 ) {
+ } else if (found == 3 ) {
nfs_error(_("%s: parsing error on 'vers=' option"),
progname);
- } else if (i == 4) {
+ } else if (found == 4) {
nfs_error(_("%s: parsing error on 'nfsvers=' option"),
progname);
}
diff --git a/utils/mount/nfsmount.conf.man b/utils/mount/nfsmount.conf.man
index 3aa3456..73c3e11 100644
--- a/utils/mount/nfsmount.conf.man
+++ b/utils/mount/nfsmount.conf.man
@@ -1,53 +1,84 @@
-.\"@(#)nfsmount.conf.5"
-.TH NFSMOUNT.CONF 5 "9 October 2012"
+."@(#)nfsmount.conf.5"
+.TH NFSMOUNT.CONF 5 "16 December 2020"
.SH NAME
nfsmount.conf - Configuration file for NFS mounts
.SH SYNOPSIS
Configuration file for NFS mounts that allows options
to be set globally, per server or per mount point.
.SH DESCRIPTION
-The configuration file is made up of multiple sections
-followed by variables associated with that section.
-A section is defined by a string enclosed by
+The configuration file is made up of multiple section headers
+followed by variable assignments associated with that section.
+A section header is defined by a string enclosed by
.BR [
-and
+and
.BR ]
-branches.
-Variables are assignment statements that assign values
-to particular variables using the
-.BR =
-operator, as in
+brackets.
+Variable assignments are assignment statements that assign values
+to particular variables using the
+.BR =
+operator, as in
.BR Proto=Tcp .
-The variables that can be assigned are exactly the set of NFS specific
+The variables that can be assigned are the set of NFS specific
mount options listed in
-.BR nfs (5).
+.BR nfs (5)
+together with the filesystem-independant mount options listed in
+.BR mount (8)
+and three additions:
+.B Sloppy=True
+has the same effect as the
+.B -s
+option to
+.IR mount ,
+and
+.B Foreground=True
+and
+.B Background=True
+have the same effect as
+.B bg
+and
+.BR fg .
+.PP
+Options in the config file may be given in upper, lower, or mixed case
+and will be shifted to lower case before being passed to the filesystem.
+.PP
+Boolean mount options which do not need an equals sign must be given as
+.RI \[dq] option =True".
+Instead of preceeding such an option with
+.RB \[dq] no \[dq]
+its negation must be given as
+.RI \[dq] option =False".
.PP
Sections are broken up into three basic categories:
Global options, Server options and Mount Point options.
.HP
.B [ NFSMount_Global_Options ]
- This statically named section
-defines all of the global mount options that can be
+defines all of the global mount options that can be
applied to every NFS mount.
.HP
-.B [ Server \(lqServer_Name\(rq ]
-- This section defines all the mount options that should
-be used on mounts to a particular NFS server. The
-.I \(lqServer_Name\(rq
-strings needs to be surrounded by '\(lq' and
-be an exact match of the server name used in the
+.B [ Server \[dq]Server_Name\[dq] ]
+- This section defines all the mount options that should
+be used on mounts to a particular NFS server. The
+.I \[dq]Server_Name\[dq]
+strings needs to be surrounded by '\[dq]' and be an exact match
+(ignoring case) of the server name used in the
.B mount
-command.
+command.
.HP
-.B [ MountPoint \(lqMount_Point\(rq ]
-- This section defines all the mount options that
+.B [ MountPoint \[dq]Mount_Point\[dq] ]
+- This section defines all the mount options that
should be used on a particular mount point.
-The
-.I \(lqMount_Point\(rq
-string needs to be surrounded by '\(lq' and be an
-exact match of the mount point used in the
-.BR mount
-command.
+The
+.I \[dq]Mount_Point\[dq]
+string needs to be surrounded by '\[dq]' and be an
+exact match of the mount point used in the
+.BR mount
+command. Though path names are usually case-sensitive, the Mount_Point
+name is matched insensitive to case.
+.PP
+The sections are processed in the reverse of the order listed above, and
+any options already seen, either in a previous section or on the
+command line, will be ignored when seen again.
.SH EXAMPLES
.PP
These are some example lines of how sections and variables
@@ -57,37 +88,43 @@ are defined in the configuration file.
.br
Proto=Tcp
.RS
-.HP
+.PP
The TCP/IPv4 protocol will be used on every NFS mount.
-.HP
.RE
-[ Server \(lqnfsserver.foo.com\(rq ]
+.PP
+[ Server \[dq]nfsserver.foo.com\[dq] ]
.br
rsize=32k
.br
wsize=32k
.br
proto=udp6
-.HP
.RS
+.PP
A 32k (32768 bytes) block size will be used as the read and write
size on all mounts to the 'nfsserver.foo.com' server. UDP/IPv6
is the protocol to be used.
-.HP
.RE
-.BR
-[ MountPoint \(lq/export/home\(rq ]
+.PP
+[ MountPoint \[dq]/export/home\[dq] ]
.br
Background=True
.RS
-.HP
+.PP
All mounts to the '/export/home' export will be performed in
the background (i.e. done asynchronously).
-.HP
+.RE
.SH FILES
.TP 10n
.I /etc/nfsmount.conf
Default NFS mount configuration file
+.TP 10n
+.I /etc/nfsmount.conf.d
+When this directory exists and files ending
+with ".conf" exist, those files will be
+used to set configuration variables. These
+files will override variables set
+in /etc/nfsmount.conf
.PD
.SH SEE ALSO
.BR nfs (5),
diff --git a/utils/mount/parse_opt.c b/utils/mount/parse_opt.c
index 7ba61c4..b6065ca 100644
--- a/utils/mount/parse_opt.c
+++ b/utils/mount/parse_opt.c
@@ -414,19 +414,25 @@ po_found_t po_contains(struct mount_options *options, char *keyword)
* @options: pointer to mount options
* @prefix: pointer to prefix to match against a keyword
* @keyword: pointer to a C string containing the option keyword if found
+ * @n: number of instances to skip, so '0' returns the first.
*
* On success, *keyword contains the pointer of the matching option's keyword.
*/
po_found_t po_contains_prefix(struct mount_options *options,
- const char *prefix, char **keyword)
+ const char *prefix, char **keyword, int n)
{
struct mount_option *option;
if (options && prefix) {
for (option = options->head; option; option = option->next)
if (strncmp(option->keyword, prefix, strlen(prefix)) == 0) {
- *keyword = option->keyword;
- return PO_FOUND;
+ if (n > 0) {
+ n -= 1;
+ } else {
+ if (keyword)
+ *keyword = option->keyword;
+ return PO_FOUND;
+ }
}
}
diff --git a/utils/mount/parse_opt.h b/utils/mount/parse_opt.h
index 0745e0f..0a15376 100644
--- a/utils/mount/parse_opt.h
+++ b/utils/mount/parse_opt.h
@@ -46,7 +46,8 @@ po_return_t po_join(struct mount_options *, char **);
po_return_t po_append(struct mount_options *, char *);
po_found_t po_contains(struct mount_options *, char *);
po_found_t po_contains_prefix(struct mount_options *options,
- const char *prefix, char **keyword);
+ const char *prefix, char **keyword,
+ int n);
char * po_get(struct mount_options *, char *);
po_found_t po_get_numeric(struct mount_options *,
char *, long *);
diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c
index dd9828e..6f640aa 100644
--- a/utils/mountd/v4root.c
+++ b/utils/mountd/v4root.c
@@ -34,9 +34,9 @@ static nfs_export pseudo_root = {
.m_export = {
.e_hostname = "*",
.e_path = "/",
- .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
+ .e_flags = NFSEXP_READONLY
| NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
- | NFSEXP_V4ROOT,
+ | NFSEXP_V4ROOT | NFSEXP_INSECURE_PORT,
.e_anonuid = 65534,
.e_anongid = 65534,
.e_squids = NULL,
@@ -55,15 +55,11 @@ static nfs_export pseudo_root = {
};
static void
-set_pseudofs_security(struct exportent *pseudo, int flags)
+set_pseudofs_security(struct exportent *pseudo)
{
struct flav_info *flav;
int i;
- if (flags & NFSEXP_INSECURE_PORT)
- pseudo->e_flags |= NFSEXP_INSECURE_PORT;
- if ((flags & NFSEXP_ROOTSQUASH) == 0)
- pseudo->e_flags &= ~NFSEXP_ROOTSQUASH;
for (flav = flav_map; flav < flav_map + flav_map_size; flav++) {
struct sec_entry *new;
@@ -73,8 +69,7 @@ set_pseudofs_security(struct exportent *pseudo, int flags)
i = secinfo_addflavor(flav, pseudo);
new = &pseudo->e_secinfo[i];
- if (flags & NFSEXP_INSECURE_PORT)
- new->flags |= NFSEXP_INSECURE_PORT;
+ new->flags |= NFSEXP_INSECURE_PORT;
}
}
@@ -93,7 +88,7 @@ v4root_create(char *path, nfs_export *export)
strncpy(eep.e_path, path, sizeof(eep.e_path)-1);
if (strcmp(path, "/") != 0)
eep.e_flags &= ~NFSEXP_FSID;
- set_pseudofs_security(&eep, curexp->e_flags);
+ set_pseudofs_security(&eep);
exp = export_create(&eep, 0);
if (exp == NULL)
return NULL;
@@ -141,7 +136,7 @@ pseudofs_update(char *hostname, char *path, nfs_export *source)
return 0;
}
/* Update an existing V4ROOT export: */
- set_pseudofs_security(&exp->m_export, source->m_export.e_flags);
+ set_pseudofs_security(&exp->m_export);
return 0;
}
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
index a412a02..c9f0385 100644
--- a/utils/nfsd/nfsd.c
+++ b/utils/nfsd/nfsd.c
@@ -162,7 +162,7 @@ main(int argc, char **argv)
}
}
- while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTituUrG:L:", longopts, NULL)) != EOF) {
+ while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTuUrG:L:", longopts, NULL)) != EOF) {
switch(c) {
case 'd':
xlog_config(D_ALL, 1);