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)
199 if (strncmp("mountvers", field, strlen("mountvers")) != 0) {
200 for (i=0; versions[i]; i++)
201 if (strcasestr(mopt, versions[i]) != NULL)
207 unsigned long config_default_vers;
208 unsigned long config_default_proto;
210 * Check to see if a default value is being set.
211 * If so, set the appropriate global value which will
212 * be used as the initial value in the server negation.
214 int inline default_value(char *mopt)
216 struct mount_options *options = NULL;
217 int dftlen = strlen("default");
220 if (strncasecmp(mopt, "default", dftlen) != 0)
223 field = mopt + dftlen;
224 if (strncasecmp(field, "proto", strlen("proto")) == 0) {
225 if ((options = po_split(field)) != NULL) {
226 if (!nfs_nfs_protocol(options, &config_default_proto)) {
227 xlog_warn("Unable to set default protocol : %s",
231 xlog_warn("Unable to alloc memory for default protocol");
233 } else if (strncasecmp(field, "vers", strlen("vers")) == 0) {
234 if ((options = po_split(field)) != NULL) {
235 if (!nfs_nfs_version(options, &config_default_vers)) {
236 xlog_warn("Unable to set default version: %s",
241 xlog_warn("Unable to alloc memory for default version");
244 xlog_warn("Invalid default setting: '%s'", mopt);
252 * Parse the given section of the configuration
253 * file to if there are any mount options set.
254 * If so, added them to link list.
257 conf_parse_mntopts(char *section, char *arg, char *opts)
259 struct conf_list *list;
260 struct conf_list_node *node;
261 char buf[BUFSIZ], *value, *field;
265 list = conf_get_tag_list(section);
266 TAILQ_FOREACH(node, &list->fields, link) {
268 * Do not overwrite options if already exists
270 snprintf(buf, BUFSIZ, "%s=", node->field);
271 if (opts && strcasestr(opts, buf) != NULL)
274 * Protocol verions can be set in a number of ways
276 if (opts && check_vers(opts, node->field))
279 if (lookup_entry(node->field) != NULL)
282 value = conf_get_section(section, arg, node->field);
285 field = mountopts_alias(node->field, &argtype);
286 if (strcasecmp(value, "false") == 0) {
287 if (argtype != MNT_NOARG)
288 snprintf(buf, BUFSIZ, "no%s", field);
289 } else if (strcasecmp(value, "true") == 0) {
290 snprintf(buf, BUFSIZ, "%s", field);
292 nvalue = strdup(value);
293 ptr = mountopts_convert(nvalue);
294 snprintf(buf, BUFSIZ, "%s=%s", field, ptr);
300 * Keep a running tally of the list size adding
301 * one for the ',' that will be appened later
303 list_size += strlen(buf) + 1;
306 conf_free_list(list);
310 * Concatenate options from the configuration file with the
311 * given options by building a link list of options from the
312 * different sections in the conf file. Options that exists
313 * in the either the given options or link list are not
314 * overwritten so it matter which when each section is
317 char *conf_get_mntopts(char *spec, char *mount_point,
321 char *ptr, *server, *config_opts;
327 * First see if there are any mount options relative
328 * to the mount point.
330 conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, mount_opts);
333 * Next, see if there are any mount options relative
336 server = strdup(spec);
337 if (server == NULL) {
338 xlog_warn("conf_get_mountops: Unable calloc memory for server");
342 if ((ptr = strchr(server, ':')) != NULL)
344 conf_parse_mntopts(NFSMOUNT_SERVER, server, mount_opts);
348 * Finally process all the global mount options.
350 conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts);
353 * If no mount options were found in the configuration file
354 * just return what was passed in .
356 if (SLIST_EMPTY(&head))
360 * Found options in the configuration file. So
361 * concatenate the configuration options with the
362 * options that were passed in
365 optlen = strlen(mount_opts);
367 /* list_size + optlen + ',' + '\0' */
368 config_opts = calloc(1, (list_size+optlen+2));
369 if (server == NULL) {
370 xlog_warn("conf_get_mountops: Unable calloc memory for config_opts");
376 strcpy(config_opts, mount_opts);
377 strcat(config_opts, ",");
379 SLIST_FOREACH(entry, &head, entries) {
380 if (default_value(entry->opt))
382 strcat(config_opts, entry->opt);
383 strcat(config_opts, ",");
385 if ((ptr = strrchr(config_opts, ',')) != NULL)