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>
32 #define KBYTES(x) ((x) * (1024))
33 #define MEGABYTES(x) ((x) * (1048576))
34 #define GIGABYTES(x) ((x) * (1073741824))
36 #ifndef NFSMOUNT_GLOBAL_OPTS
37 #define NFSMOUNT_GLOBAL_OPTS "NFSMount_Global_Options"
40 #ifndef NFSMOUNT_MOUNTPOINT
41 #define NFSMOUNT_MOUNTPOINT "MountPoint"
44 #ifndef NFSMOUNT_SERVER
45 #define NFSMOUNT_SERVER "Server"
48 #ifndef MOUNTOPTS_CONFFILE
49 #define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf"
51 char *conf_path = MOUNTOPTS_CONFFILE;
64 {"background", "bg", MNT_NOARG},
65 {"foreground", "fg", MNT_NOARG},
66 {"sloppy", "sloppy", MNT_NOARG},
68 int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0]));
71 * See if the option is an alias, if so return the
72 * real mount option along with the argument type.
75 char *mountopts_alias(char *opt, int *argtype)
80 for (i=0; i < mnt_alias_sz; i++) {
81 if (strcasecmp(opt, mnt_alias_tab[i].alias) != 0)
83 *argtype = mnt_alias_tab[i].argtype;
84 return mnt_alias_tab[i].opt;
86 /* Make option names case-insensitive */
92 * Convert numeric strings that end with 'k', 'm' or 'g'
93 * into numeric strings with the real value.
94 * Meaning '8k' becomes '8094'.
96 char *mountopts_convert(char *value)
98 unsigned long long factor, num;
102 ch = &value[strlen(value)-1];
103 switch (tolower(*ch)) {
108 factor = MEGABYTES(1);
111 factor = GIGABYTES(1);
117 if (strncmp(value, "0x", 2) == 0) {
118 num = strtol(value, (char **)NULL, 16);
119 } else if (strncmp(value, "0", 1) == 0) {
120 num = strtol(value, (char **)NULL, 8);
122 num = strtol(value, (char **)NULL, 10);
125 snprintf(buf, 64, "%lld", num);
131 SLIST_ENTRY(entry) entries;
134 static SLIST_HEAD(shead, entry) head = SLIST_HEAD_INITIALIZER(head);
135 static int list_size;
138 * Add option to the link list
145 entry = calloc(1, sizeof(struct entry));
147 xlog_warn("Unable calloc memory for mount configs");
150 entry->opt = strdup(opt);
151 if (entry->opt == NULL) {
152 xlog_warn("Unable calloc memory for mount opts");
156 SLIST_INSERT_HEAD(&head, entry, entries);
159 * See if the given entry exists if the link list,
160 * if so return that entry
163 char *lookup_entry(char *opt)
167 SLIST_FOREACH(entry, &head, entries) {
168 if (strcasecmp(entry->opt, opt) == 0)
174 * Free all entries on the link list
181 while (!SLIST_EMPTY(&head)) {
182 entry = SLIST_FIRST(&head);
183 SLIST_REMOVE_HEAD(&head, entries);
188 static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
189 int inline check_vers(char *mopt, char *field)
193 if (strncmp("mountvers", field, strlen("mountvers") != 0 &&
194 (strcasecmp(field, "nfsvers") == 0 ||
195 strcasecmp(field, "vers") == 0))) {
196 for (i=0; versions[i]; i++)
197 if (strcasestr(mopt, versions[i]) != NULL)
203 * Parse the given section of the configuration
204 * file to if there are any mount options set.
205 * If so, added them to link list.
208 conf_parse_mntopts(char *section, char *arg, char *opts)
210 struct conf_list *list;
211 struct conf_list_node *node;
212 char buf[BUFSIZ], *value, *field;
216 list = conf_get_tag_list(section);
217 TAILQ_FOREACH(node, &list->fields, link) {
219 * Do not overwrite options if already exists
221 snprintf(buf, BUFSIZ, "%s=", node->field);
222 if (opts && strcasestr(opts, buf) != NULL)
225 * Protocol verions can be set in a number of ways
227 if (opts && check_vers(opts, node->field))
230 if (lookup_entry(node->field) != NULL)
233 value = conf_get_section(section, arg, node->field);
236 field = mountopts_alias(node->field, &argtype);
237 if (strcasecmp(value, "false") == 0) {
238 if (argtype != MNT_NOARG)
239 snprintf(buf, BUFSIZ, "no%s", field);
240 } else if (strcasecmp(value, "true") == 0) {
241 snprintf(buf, BUFSIZ, "%s", field);
243 nvalue = strdup(value);
244 ptr = mountopts_convert(nvalue);
245 snprintf(buf, BUFSIZ, "%s=%s", field, ptr);
251 * Keep a running tally of the list size adding
252 * one for the ',' that will be appened later
254 list_size += strlen(buf) + 1;
257 conf_free_list(list);
261 * Concatenate options from the configuration file with the
262 * given options by building a link list of options from the
263 * different sections in the conf file. Options that exists
264 * in the either the given options or link list are not
265 * overwritten so it matter which when each section is
268 char *conf_get_mntopts(char *spec, char *mount_point,
272 char *ptr, *server, *config_opts;
278 * First see if there are any mount options relative
279 * to the mount point.
281 conf_parse_mntopts(NFSMOUNT_MOUNTPOINT, mount_point, mount_opts);
284 * Next, see if there are any mount options relative
287 server = strdup(spec);
288 if (server == NULL) {
289 xlog_warn("conf_get_mountops: Unable calloc memory for server");
293 if ((ptr = strchr(server, ':')) != NULL)
295 conf_parse_mntopts(NFSMOUNT_SERVER, server, mount_opts);
299 * Finally process all the global mount options.
301 conf_parse_mntopts(NFSMOUNT_GLOBAL_OPTS, NULL, mount_opts);
304 * If no mount options were found in the configuration file
305 * just return what was passed in .
307 if (SLIST_EMPTY(&head))
311 * Found options in the configuration file. So
312 * concatenate the configuration options with the
313 * options that were passed in
316 optlen = strlen(mount_opts);
318 /* list_size + optlen + ',' + '\0' */
319 config_opts = calloc(1, (list_size+optlen+2));
320 if (server == NULL) {
321 xlog_warn("conf_get_mountops: Unable calloc memory for config_opts");
326 strcpy(config_opts, mount_opts);
327 strcat(config_opts, ",");
329 SLIST_FOREACH(entry, &head, entries) {
330 strcat(config_opts, entry->opt);
331 strcat(config_opts, ",");
333 *(strrchr(config_opts, ',')) = '\0';