nfs-utils/nfs-utils-2.5.3-rc4.patch

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);