From 553dad6540dc9ba32fc407169588b3609cc6d7b4 Mon Sep 17 00:00:00 2001 From: DistroBaker Date: Thu, 17 Dec 2020 15:50:29 +0000 Subject: [PATCH] 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#fdde30c3d1aba1cd1ecd6e076fe11ad8984704e8 --- ...utils-2.3.1-systemd-gssproxy-restart.patch | 10 +- nfs-utils-2.5.3-rc3.patch | 1054 +++++++++++++++++ nfs-utils.spec | 7 +- 3 files changed, 1064 insertions(+), 7 deletions(-) create mode 100644 nfs-utils-2.5.3-rc3.patch diff --git a/nfs-utils-2.3.1-systemd-gssproxy-restart.patch b/nfs-utils-2.3.1-systemd-gssproxy-restart.patch index 60762e8..08b8dd1 100644 --- a/nfs-utils-2.3.1-systemd-gssproxy-restart.patch +++ b/nfs-utils-2.3.1-systemd-gssproxy-restart.patch @@ -1,9 +1,9 @@ -diff -up nfs-utils-2.3.1/systemd/nfs-server.service.orig nfs-utils-2.3.1/systemd/nfs-server.service ---- nfs-utils-2.3.1/systemd/nfs-server.service.orig 2018-01-19 10:25:38.153513857 -0500 -+++ nfs-utils-2.3.1/systemd/nfs-server.service 2018-01-19 10:30:52.977245126 -0500 -@@ -26,6 +26,7 @@ Type=oneshot +diff -up nfs-utils-2.5.2/systemd/nfs-server.service.orig nfs-utils-2.5.2/systemd/nfs-server.service +--- nfs-utils-2.5.2/systemd/nfs-server.service.orig 2020-12-16 12:31:27.677558163 -0500 ++++ nfs-utils-2.5.2/systemd/nfs-server.service 2020-12-16 12:33:56.751806659 -0500 +@@ -23,6 +23,7 @@ Type=oneshot RemainAfterExit=yes - ExecStartPre=/usr/sbin/exportfs -r + ExecStartPre=-/usr/sbin/exportfs -r ExecStart=/usr/sbin/rpc.nfsd +ExecStart=-/bin/sh -c 'if systemctl -q is-active gssproxy; then systemctl reload gssproxy ; fi' ExecStop=/usr/sbin/rpc.nfsd 0 diff --git a/nfs-utils-2.5.3-rc3.patch b/nfs-utils-2.5.3-rc3.patch new file mode 100644 index 0000000..6413e07 --- /dev/null +++ b/nfs-utils-2.5.3-rc3.patch @@ -0,0 +1,1054 @@ +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 + #include + #include ++#include + + #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, §ion, &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..7934f4f 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 + * + * - 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,66 @@ 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); ++ po_append(options, buf); ++ default_value(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. ++ * Finally process all the global mount options. + */ +- conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts); ++ conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, options); + + /* +- * If no mount options were found in the configuration file +- * just return what was passed in . ++ * Strip out defaults, which have already been handled, ++ * then join the rest and return. + */ +- if (SLIST_EMPTY(&head)) +- return mount_opts; +- +- /* +- * Found options in the configuration file. So +- * concatenate the configuration options with the +- * options that were passed in +- */ +- 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/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); diff --git a/nfs-utils.spec b/nfs-utils.spec index aeef9fa..860b693 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://linux-nfs.org/ Version: 2.5.2 -Release: 1.rc1%{?dist} +Release: 1.rc3%{?dist} Epoch: 1 # group all 32bit related archs @@ -16,7 +16,7 @@ Source4: nfsconvert.py Source5: nfsconvert.sh Source6: nfs-convert.service -Patch001: nfs-utils-2.5.3-rc1.patch +Patch001: nfs-utils-2.5.3-rc3.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -365,6 +365,9 @@ fi %{_pkgdir}/*/var-lib-nfs-rpc_pipefs.mount %changelog +* Thu Dec 17 2020 Steve Dickson 2.5.2-1.rc3 +- Updated to the latest RC release: nfs-utils-2-5-3-rc3 (bz 1906841) + * Tue Nov 10 2020 Steve Dickson 2.5.2-1.rc1 - Updated to the latest RC release: nfs-utils-2-5-3-rc1 (bz 1896543)