From 4897093455a2bf08f3db3a1132cc2f6f5484d77c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 08:03:02 +0200 Subject: Adding upstream version 1:2.6.4. Signed-off-by: Daniel Baumann --- utils/mount/configfile.c | 347 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 utils/mount/configfile.c (limited to 'utils/mount/configfile.c') diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c new file mode 100644 index 0000000..1d88cbf --- /dev/null +++ b/utils/mount/configfile.c @@ -0,0 +1,347 @@ +/* + * configfile.c -- mount configuration file manipulation + * Copyright (C) 2008 Red Hat, Inc + * + * - Routines use to create mount options from the mount + * configuration file. + * + * This program 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, or (at your option) + * any later version. + * + * This program 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. + * + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "xlog.h" +#include "mount.h" +#include "parse_opt.h" +#include "network.h" +#include "conffile.h" +#include "mount_config.h" + +#define KBYTES(x) ((x) * (1024)) +#define MEGABYTES(x) ((x) * (1048576)) +#define GIGABYTES(x) ((x) * (1073741824)) + +#ifndef NFSMOUNT_GLOBAL_OPTS +#define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options" +#endif + +#ifndef NFSMOUNT_MOUNTPOINT +#define NFSMOUNT_MOUNTPOINT "MountPoint" +#endif + +#ifndef NFSMOUNT_SERVER +#define NFSMOUNT_SERVER "Server" +#endif + +enum { + MNT_NOARG=0, + MNT_INTARG, + MNT_STRARG, + MNT_SPEC, + MNT_UNSET +}; +struct mnt_alias { + char *alias; + char *opt; + int argtype; +} mnt_alias_tab[] = { + {"background", "bg", MNT_NOARG}, + {"foreground", "fg", MNT_NOARG}, + {"sloppy", "sloppy", MNT_NOARG}, +}; +int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); + +static const char *version_keys[] = { + "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 + * real mount option along with the argument type. + */ +inline static +char *mountopts_alias(char *opt, int *argtype) +{ + int i; + + *argtype = MNT_UNSET; + for (i=0; i < mnt_alias_sz; i++) { + if (strcasecmp(opt, mnt_alias_tab[i].alias) != 0) + continue; + *argtype = mnt_alias_tab[i].argtype; + return mnt_alias_tab[i].opt; + } + /* Make option names case-insensitive */ + upper2lower(opt); + + return opt; +} +/* + * Convert numeric strings that end with 'k', 'm' or 'g' + * into numeric strings with the real value. + * Meaning '8k' becomes '8094'. + */ +static char *mountopts_convert(char *value) +{ + unsigned long long factor, num; + static char buf[64]; + char *ch; + + ch = &value[strlen(value)-1]; + switch (tolower(*ch)) { + case 'k': + factor = KBYTES(1); + break; + case 'm': + factor = MEGABYTES(1); + break; + case 'g': + factor = GIGABYTES(1); + break; + default: + return value; + } + *ch = '\0'; + if (strncmp(value, "0x", 2) == 0) { + num = strtol(value, (char **)NULL, 16); + } else if (strncmp(value, "0", 1) == 0) { + num = strtol(value, (char **)NULL, 8); + } else { + num = strtol(value, (char **)NULL, 10); + } + num *= factor; + snprintf(buf, 64, "%lld", num); + + return buf; +} + +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 + * be used as the initial value in the server negation. + */ +static int +default_value(char *mopt) +{ + struct mount_options *options = NULL; + int dftlen = strlen("default"); + char *field; + + if (strncasecmp(mopt, "default", dftlen) != 0) + return 0; + + field = mopt + dftlen; + 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", + strerror(errno)); + } + if (!nfs_nfs_proto_family(options, &config_default_family)) { + xlog_warn("Unable to set default family : %s", + strerror(errno)); + } + } else { + xlog_warn("Unable to alloc memory for default protocol"); + } + } 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", + strerror(errno)); + } + } else { + xlog_warn("Unable to alloc memory for default version"); + } + } else + xlog_warn("Invalid default setting: '%s'", mopt); + + if (options) + po_destroy(options); + + return 1; +} +/* + * 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, 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) { + /* + * Do not overwrite options if already exists + */ + 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 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) + continue; + if (strcasecmp(value, "false") == 0) { + if (argtype != MNT_NOARG) + snprintf(buf, BUFSIZ, "no%s", field); + else if (strcasecmp(field, "bg") == 0) + snprintf(buf, BUFSIZ, "fg"); + else if (strcasecmp(field, "fg") == 0) + snprintf(buf, BUFSIZ, "bg"); + else if (strcasecmp(field, "sloppy") == 0) + strict = 1; + } else if (strcasecmp(value, "true") == 0) { + if ((strcasecmp(field, "sloppy") == 0) && strict) + continue; + snprintf(buf, BUFSIZ, "%s", field); + } else { + nvalue = strdup(value); + ptr = mountopts_convert(nvalue); + snprintf(buf, BUFSIZ, "%s=%s", field, ptr); + free(nvalue); + } + if (buf[0] == '\0') + continue; + + po_append(options, buf); + default_value(buf); + } + conf_free_list(list); +} + +/* + * 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 + * overwritten so it matter which when each section is + * parsed. + */ +char *conf_get_mntopts(char *spec, char *mount_point, + char *mount_opts) +{ + struct mount_options *options; + char *ptr, *server; + + strict = 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 + * to the mount point. + */ + 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"); + po_destroy(options); + return mount_opts; + } + if ((ptr = strchr(server, ':')) != NULL) + *ptr='\0'; + conf_parse_mntopts(NFSMOUNT_SERVER, server, options); + free(server); + + /* + * Finally process all the global mount options. + */ + conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, options); + + /* + * Strip out defaults, which have already been handled, + * then join the rest and return. + */ + while (po_contains_prefix(options, "default", &ptr, 0) == PO_FOUND) { + ptr = strdup(ptr); + po_remove_all(options, ptr); + free(ptr); + } + + po_join(options, &mount_opts); + po_destroy(options); + + return mount_opts; +} -- cgit v1.2.3