2 * configfile.c -- mount configuration file manipulation
3 * Copyright (C) 2008 Red Hat, Inc <nfs@redhat.com>
5 * - Routines use to create mount options from the mount
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
34 #include "parse_opt.h"
38 #define KBYTES(x) ((x) * (1024))
39 #define MEGABYTES(x) ((x) * (1048576))
40 #define GIGABYTES(x) ((x) * (1073741824))
42 #ifndef NFSMOUNT_GLOBAL_OPTS
43 #define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options"
46 #ifndef NFSMOUNT_MOUNTPOINT
47 #define NFSMOUNT_MOUNTPOINT "MountPoint"
50 #ifndef NFSMOUNT_SERVER
51 #define NFSMOUNT_SERVER "Server"
54 #ifndef MOUNTOPTS_CONFFILE
55 #define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf"
57 char *conf_path = MOUNTOPTS_CONFFILE;
70 {"background", "bg", MNT_NOARG},
71 {"foreground", "fg", MNT_NOARG},
72 {"sloppy", "sloppy", MNT_NOARG},
74 int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0]));
77 * See if the option is an alias, if so return the
78 * real mount option along with the argument type.
81 char *mountopts_alias(char *opt, int *argtype)
86 for (i=0; i < mnt_alias_sz; i++) {
87 if (strcasecmp(opt, mnt_alias_tab[i].alias) != 0)
89 *argtype = mnt_alias_tab[i].argtype;
90 return mnt_alias_tab[i].opt;
92 /* Make option names case-insensitive */
98 * Convert numeric strings that end with 'k', 'm' or 'g'
99 * into numeric strings with the real value.
100 * Meaning '8k' becomes '8094'.
102 char *mountopts_convert(char *value)
104 unsigned long long factor, num;
108 ch = &value[strlen(value)-1];
109 switch (tolower(*ch)) {
114 factor = MEGABYTES(1);
117 factor = GIGABYTES(1);
123 if (strncmp(value, "0x", 2) == 0) {
124 num = strtol(value, (char **)NULL, 16);
125 } else if (strncmp(value, "0", 1) == 0) {
126 num = strtol(value, (char **)NULL, 8);
128 num = strtol(value, (char **)NULL, 10);
131 snprintf(buf, 64, "%lld", num);
137 SLIST_ENTRY(entry) entries;
140 static SLIST_HEAD(shead, entry) head = SLIST_HEAD_INITIALIZER(head);
141 static int list_size;
144 * Add option to the link list
151 entry = calloc(1, sizeof(struct entry));
153 xlog_warn("Unable calloc memory for mount configs");
156 entry->opt = strdup(opt);
157 if (entry->opt == NULL) {
158 xlog_warn("Unable calloc memory for mount opts");
162 SLIST_INSERT_HEAD(&head, entry, entries);
165 * See if the given entry exists if the link list,
166 * if so return that entry
169 char *lookup_entry(char *opt)
173 SLIST_FOREACH(entry, &head, entries) {
174 if (strcasecmp(entry->opt, opt) == 0)
180 * Free all entries on the link list
187 while (!SLIST_EMPTY(&head)) {
188 entry = SLIST_FIRST(&head);
189 SLIST_REMOVE_HEAD(&head, entries);
194 static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
195 int inline check_vers(char *mopt, char *field)
200 * First check to see if the config setting is one
201 * of the many version settings
203 for (i=0; versions[i]; i++) {
204 if (strcasestr(field, versions[i]) != NULL) {
212 * It appears the version is being set, now see
213 * if the version appears on the command
215 for (i=0; versions[i]; i++) {
216 if (strcasestr(mopt, versions[i]) != NULL)
223 unsigned long config_default_vers;
224 unsigned long config_default_proto;
225 extern sa_family_t config_default_family;
228 * Check to see if a default value is being set.
229 * If so, set the appropriate global value which will
230 * be used as the initial value in the server negation.
232 int inline default_value(char *mopt)
234 struct mount_options *options = NULL;
235 int dftlen = strlen("default");
238 if (strncasecmp(mopt, "default", dftlen) != 0)
241 field = mopt + dftlen;
242 if (strncasecmp(field, "proto", strlen("proto")) == 0) {
243 if ((options = po_split(field)) != NULL) {
244 if (!nfs_nfs_protocol(options, &config_default_proto)) {
245 xlog_warn("Unable to set default protocol : %s",
248 if (!nfs_nfs_proto_family(options, &config_default_family)) {
249 xlog_warn("Unable to set default family : %s",
253 xlog_warn("Unable to alloc memory for default protocol");
255 } else if (strncasecmp(field, "vers", strlen("vers")) == 0) {
256 if ((options = po_split(field)) != NULL) {
257 if (!nfs_nfs_version(options, &config_default_vers)) {
258 xlog_warn("Unable to set default version: %s",
263 xlog_warn("Unable to alloc memory for default version");
266 xlog_warn("Invalid default setting: '%s'", mopt);
274 * Parse the given section of the configuration
275 * file to if there are any mount options set.
276 * If so, added them to link list.
279 conf_parse_mntopts(char *section, char *arg, char *opts)
281 struct conf_list *list;
282 struct conf_list_node *node;
283 char buf[BUFSIZ], *value, *field;
287 list = conf_get_tag_list(section);
288 TAILQ_FOREACH(node, &list->fields, link) {
290 * Do not overwrite options if already exists
292 snprintf(buf, BUFSIZ, "%s=", node->field);
293 if (opts && strcasestr(opts, buf) != NULL)
296 * Protocol verions can be set in a number of ways
298 if (opts && check_vers(opts, node->field))
301 if (lookup_entry(node->field) != NULL)
304 value = conf_get_section(section, arg, node->field);
307 field = mountopts_alias(node->field, &argtype);
308 if (strcasecmp(value, "false") == 0) {
309 if (argtype != MNT_NOARG)
310 snprintf(buf, BUFSIZ, "no%s", field);
311 } else if (strcasecmp(value, "true") == 0) {
312 snprintf(buf, BUFSIZ, "%s", field);
314 nvalue = strdup(value);
315 ptr = mountopts_convert(nvalue);
316 snprintf(buf, BUFSIZ, "%s=%s", field, ptr);
322 * Keep a running tally of the list size adding
323 * one for the ',' that will be appened later
325 list_size += strlen(buf) + 1;
328 conf_free_list(list);
332 * Concatenate options from the configuration file with the
333 * given options by building a link list of options from the
334 * different sections in the conf file. Options that exists
335 * in the either the given options or link list are not
336 * overwritten so it matter which when each section is
339 char *conf_get_mntopts(char *spec, char *mount_point,
343 char *ptr, *server, *config_opts;
349 * First see if there are any mount options relative
350 * to the mount point.
352 conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, mount_opts);
355 * Next, see if there are any mount options relative
358 server = strdup(spec);
359 if (server == NULL) {
360 xlog_warn("conf_get_mountops: Unable calloc memory for server");
364 if ((ptr = strchr(server, ':')) != NULL)
366 conf_parse_mntopts(NFSMOUNT_SERVER, server, mount_opts);
370 * Finally process all the global mount options.
372 conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts);
375 * If no mount options were found in the configuration file
376 * just return what was passed in .
378 if (SLIST_EMPTY(&head))
382 * Found options in the configuration file. So
383 * concatenate the configuration options with the
384 * options that were passed in
387 optlen = strlen(mount_opts);
389 /* list_size + optlen + ',' + '\0' */
390 config_opts = calloc(1, (list_size+optlen+2));
391 if (server == NULL) {
392 xlog_warn("conf_get_mountops: Unable calloc memory for config_opts");
398 strcpy(config_opts, mount_opts);
399 strcat(config_opts, ",");
401 SLIST_FOREACH(entry, &head, entries) {
402 if (default_value(entry->opt))
404 strcat(config_opts, entry->opt);
405 strcat(config_opts, ",");
407 if ((ptr = strrchr(config_opts, ',')) != NULL)