2 * parse_opt.c -- mount option string parsing helpers
4 * Copyright (C) 2007 Oracle. All rights reserved.
5 * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 021110-1307, USA.
25 * Converting a C string containing mount options to a data object
26 * and manipulating that object is cleaner in C than manipulating
27 * the C string itself. This is similar to the way Python handles
28 * string manipulation.
30 * The current implementation uses a linked list as the data object
31 * since lists are simple, and we don't need to worry about more
32 * than ten or twenty options at a time.
34 * Hopefully the interface is abstract enough that the underlying
35 * data structure can be replaced if needed without changing the API.
46 #include "parse_opt.h"
51 struct mount_option *next, *prev;
56 struct mount_options {
57 struct mount_option *head, *tail;
61 static struct mount_option *option_create(char *str)
63 struct mount_option *option;
69 option = malloc(sizeof(*option));
76 opteq = strchr(str, '=');
78 option->keyword = strndup(str, opteq - str);
81 option->value = strdup(opteq + 1);
83 free(option->keyword);
87 option->keyword = strdup(str);
100 static void option_destroy(struct mount_option *option)
102 free(option->keyword);
107 static void options_init(struct mount_options *options)
109 options->head = options->tail = NULL;
113 static struct mount_options *options_create(void)
115 struct mount_options *options;
117 options = malloc(sizeof(*options));
119 options_init(options);
124 static int options_empty(struct mount_options *options)
126 return options->count == 0;
129 static void options_tail_insert(struct mount_options *options,
130 struct mount_option *option)
132 struct mount_option *prev = options->tail;
140 options->head = option;
141 options->tail = option;
146 static void options_delete(struct mount_options *options,
147 struct mount_option *option)
149 struct mount_option *prev = option->prev;
150 struct mount_option *next = option->next;
152 if (!options_empty(options)) {
154 prev->next = option->next;
156 next->prev = option->prev;
158 if (options->head == option)
159 options->head = option->next;
160 if (options->tail == option)
161 options->tail = prev;
165 option_destroy(option);
171 * po_destroy - deallocate a group of mount options
172 * @options: pointer to mount options to free
175 void po_destroy(struct mount_options *options)
178 while (!options_empty(options))
179 options_delete(options, options->head);
185 * po_split - split options string into group of options
186 * @options: pointer to C string containing zero or more comma-delimited options
188 * Convert our mount options string to a list to make it easier
189 * to adjust the options as we go. This is just an exercise in
190 * lexical parsing -- this function doesn't pay attention to the
191 * meaning of the options themselves.
193 * Returns a new group of mount options if successful; otherwise NULL
194 * is returned if some failure occurred.
196 struct mount_options *po_split(char *str)
198 struct mount_options *options;
199 struct tokenizer_state *tstate;
203 return options_create();
205 options = options_create();
207 tstate = init_tokenizer(str, ',');
208 for (opt = next_token(tstate); opt; opt = next_token(tstate)) {
209 struct mount_option *option = option_create(opt);
213 options_tail_insert(options, option);
215 if (tokenizer_error(tstate))
217 end_tokenizer(tstate);
222 end_tokenizer(tstate);
228 * po_replace - replace mount options in one mount_options object with another
229 * @target: pointer to previously instantiated object to replace
230 * @source: pointer to object containing source mount options
232 * Side effect: the object referred to by source is emptied.
234 void po_replace(struct mount_options *target, struct mount_options *source)
237 while (!options_empty(target))
238 options_delete(target, target->head);
241 target->head = source->head;
242 target->tail = source->tail;
243 target->count = source->count;
245 options_init(source);
251 * po_join - recombine group of mount options into a C string
252 * @options: pointer to mount options to recombine
253 * @str: handle on string to replace (input and output)
255 * Convert our mount options object back into a string that the
256 * rest of the world can use.
258 * Returns 1 if the string was successfully created; otherwise
259 * zero. Upon return, @string contains the address of a
260 * replacement C string containing a comma-delimited list of
261 * mount options and values; or the passed-in string is freed
262 * and NULL is returned if some failure occurred.
264 int po_join(struct mount_options *options, char **str)
267 struct mount_option *option;
269 if (!str || !options)
275 if (options_empty(options)) {
277 return *str ? PO_SUCCEEDED : PO_FAILED;
280 for (option = options->head; option; option = option->next) {
281 len += strlen(option->keyword);
283 len +=strlen(option->value) + 1; /* equals sign */
288 len++; /* NULL on the end */
295 for (option = options->head; option; option = option->next) {
296 strcat(*str, option->keyword);
299 strcat(*str, option->value);
309 * po_append - concatenate an option onto a group of options
310 * @options: pointer to mount options
311 * @option: pointer to a C string containing the option to add
313 * Returns 1 if the list was successfully concatenated; otherwise
316 int po_append(struct mount_options *options, char *str)
318 struct mount_option *option = option_create(str);
321 options_tail_insert(options, option);
328 * po_contains - check for presense of an option in a group
329 * @options: pointer to mount options
330 * @keyword: pointer to a C string containing option keyword for which to search
332 * Returns 1 if the option is present in the list; otherwise zero.
334 int po_contains(struct mount_options *options, char *keyword)
336 struct mount_option *option;
338 if (options && keyword) {
339 for (option = options->head; option; option = option->next)
340 if (strcmp(option->keyword, keyword) == 0)
348 * po_get - return the value of the rightmost instance of an option
349 * @options: pointer to mount options
350 * @keyword: pointer to a C string containing option keyword for which to search
352 * If multiple instances of the same option are present in a mount option
353 * list, the rightmost instance is always the effective one.
355 * Returns pointer to C string containing the value of the option.
356 * Returns NULL if the option isn't found, or if the option doesn't
359 char *po_get(struct mount_options *options, char *keyword)
361 struct mount_option *option;
363 if (options && keyword) {
364 for (option = options->tail; option; option = option->prev)
365 if (strcmp(option->keyword, keyword) == 0)
366 return option->value;
373 * po_rightmost - determine the relative position of two options
374 * @options: pointer to mount options
375 * @key1: pointer to a C string containing an option keyword
376 * @key2: pointer to a C string containing another option keyword
378 * The kernel parses the mount option string from left to right.
379 * If an option is specified more than once (for example, "intr"
380 * and "nointr", the rightmost option is the last to be parsed,
381 * and it therefore takes precedence over previous similar options.
383 * This function can be used to determine which of two similar
384 * options will be the one to take effect.
386 * Returns 1 if key2 is rightmost or key1 is not present.
387 * Returns -1 if key1 is rightmost or key2 is not present.
388 * Returns 0 if neither key is present.
390 int po_rightmost(struct mount_options *options, char *key1, char *key2)
392 struct mount_option *option;
395 for (option = options->tail; option; option = option->prev) {
396 if (key2 && strcmp(option->keyword, key2) == 0)
397 return PO_KEY2_RIGHTMOST;
398 if (key1 && strcmp(option->keyword, key1) == 0)
399 return PO_KEY1_RIGHTMOST;
407 * po_remove_all - remove instances of an option from a group
408 * @options: pointer to mount options
409 * @keyword: pointer to a C string containing an option keyword to remove
411 * Returns 1 if the option was found and removed; passed-in list is
412 * truncated upon return; otherwise zero.
414 int po_remove_all(struct mount_options *options, char *keyword)
416 struct mount_option *option, *next;
417 int found = PO_NOT_FOUND;
419 if (options && keyword) {
420 for (option = options->head; option; option = next) {
422 if (strcmp(option->keyword, keyword) == 0) {
423 options_delete(options, option);