Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / nfs-utils / utils / mount / parse_opt.c
blob1dfee8aafe1b97bad1582361becc64d8dc69eb51
1 /*
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.
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
43 #include <ctype.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <errno.h>
50 #include "parse_opt.h"
51 #include "token.h"
54 struct mount_option {
55 struct mount_option *next, *prev;
56 char *keyword;
57 char *value;
60 struct mount_options {
61 struct mount_option *head, *tail;
62 unsigned int count;
65 static struct mount_option *option_create(char *str)
67 struct mount_option *option;
68 char *opteq;
70 if (!str)
71 return NULL;
73 option = malloc(sizeof(*option));
74 if (!option)
75 return NULL;
77 option->next = NULL;
78 option->prev = NULL;
80 opteq = strchr(str, '=');
81 if (opteq) {
82 option->keyword = strndup(str, opteq - str);
83 if (!option->keyword)
84 goto fail;
85 option->value = strdup(opteq + 1);
86 if (!option->value) {
87 free(option->keyword);
88 goto fail;
90 } else {
91 option->keyword = strdup(str);
92 if (!option->keyword)
93 goto fail;
94 option->value = NULL;
97 return option;
99 fail:
100 free(option);
101 return NULL;
104 static void option_destroy(struct mount_option *option)
106 free(option->keyword);
107 free(option->value);
108 free(option);
111 static void options_init(struct mount_options *options)
113 options->head = options->tail = NULL;
114 options->count = 0;
117 static struct mount_options *options_create(void)
119 struct mount_options *options;
121 options = malloc(sizeof(*options));
122 if (options)
123 options_init(options);
125 return options;
128 static int options_empty(struct mount_options *options)
130 return options->count == 0;
133 static void options_tail_insert(struct mount_options *options,
134 struct mount_option *option)
136 struct mount_option *prev = options->tail;
138 option->next = NULL;
139 option->prev = prev;
141 if (prev)
142 prev->next = option;
143 else
144 options->head = option;
145 options->tail = option;
147 options->count++;
150 static void options_delete(struct mount_options *options,
151 struct mount_option *option)
153 struct mount_option *prev = option->prev;
154 struct mount_option *next = option->next;
156 if (!options_empty(options)) {
157 if (prev)
158 prev->next = option->next;
159 if (next)
160 next->prev = option->prev;
162 if (options->head == option)
163 options->head = option->next;
164 if (options->tail == option)
165 options->tail = prev;
167 options->count--;
169 option_destroy(option);
175 * po_destroy - deallocate a group of mount options
176 * @options: pointer to mount options to free
179 void po_destroy(struct mount_options *options)
181 if (options) {
182 while (!options_empty(options))
183 options_delete(options, options->head);
184 free(options);
189 * po_split - split options string into group of options
190 * @options: pointer to C string containing zero or more comma-delimited options
192 * Convert our mount options string to a list to make it easier
193 * to adjust the options as we go. This is just an exercise in
194 * lexical parsing -- this function doesn't pay attention to the
195 * meaning of the options themselves.
197 * Returns a new group of mount options if successful; otherwise NULL
198 * is returned if some failure occurred.
200 struct mount_options *po_split(char *str)
202 struct mount_options *options;
203 struct tokenizer_state *tstate;
204 char *opt;
206 if (!str)
207 return options_create();
209 options = options_create();
210 if (options) {
211 tstate = init_tokenizer(str, ',');
212 for (opt = next_token(tstate); opt; opt = next_token(tstate)) {
213 struct mount_option *option = option_create(opt);
214 free(opt);
215 if (!option)
216 goto fail;
217 options_tail_insert(options, option);
219 if (tokenizer_error(tstate))
220 goto fail;
221 end_tokenizer(tstate);
223 return options;
225 fail:
226 end_tokenizer(tstate);
227 po_destroy(options);
228 return NULL;
232 * po_replace - replace mount options in one mount_options object with another
233 * @target: pointer to previously instantiated object to replace
234 * @source: pointer to object containing source mount options
236 * Side effect: the object referred to by source is emptied.
238 void po_replace(struct mount_options *target, struct mount_options *source)
240 if (target) {
241 while (!options_empty(target))
242 options_delete(target, target->head);
244 if (source) {
245 target->head = source->head;
246 target->tail = source->tail;
247 target->count = source->count;
249 options_init(source);
255 * po_join - recombine group of mount options into a C string
256 * @options: pointer to mount options to recombine
257 * @str: handle on string to replace (input and output)
259 * Convert our mount options object back into a string that the
260 * rest of the world can use.
262 * Upon return, @string contains the address of a replacement
263 * C string containing a comma-delimited list of mount options
264 * and values; or the passed-in string is freed and NULL is
265 * returned if some failure occurred.
267 po_return_t po_join(struct mount_options *options, char **str)
269 size_t len = 0;
270 struct mount_option *option;
272 if (!str || !options)
273 return PO_FAILED;
275 free(*str);
276 *str = NULL;
278 if (options_empty(options)) {
279 *str = strdup("");
280 return *str ? PO_SUCCEEDED : PO_FAILED;
283 for (option = options->head; option; option = option->next) {
284 len += strlen(option->keyword);
285 if (option->value)
286 len +=strlen(option->value) + 1; /* equals sign */
287 if (option->next)
288 len++; /* comma */
291 len++; /* NULL on the end */
293 *str = malloc(len);
294 if (!*str)
295 return PO_FAILED;
296 *str[0] = '\0';
298 for (option = options->head; option; option = option->next) {
299 strcat(*str, option->keyword);
300 if (option->value) {
301 strcat(*str, "=");
302 strcat(*str, option->value);
304 if (option->next)
305 strcat(*str, ",");
308 return PO_SUCCEEDED;
312 * po_append - concatenate an option onto a group of options
313 * @options: pointer to mount options
314 * @option: pointer to a C string containing the option to add
317 po_return_t po_append(struct mount_options *options, char *str)
319 struct mount_option *option = option_create(str);
321 if (option) {
322 options_tail_insert(options, option);
323 return PO_SUCCEEDED;
325 return PO_FAILED;
329 * po_contains - check for presense of an option in a group
330 * @options: pointer to mount options
331 * @keyword: pointer to a C string containing option keyword for which to search
334 po_found_t 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)
341 return PO_FOUND;
344 return PO_NOT_FOUND;
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
357 * have a value.
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;
369 return NULL;
373 * po_get_numeric - return numeric value of rightmost instance of keyword option
374 * @options: pointer to mount options
375 * @keyword: pointer to a C string containing option keyword for which to search
376 * @value: OUT: set to the value of the keyword
378 * This is specifically for parsing keyword options that take only a numeric
379 * value. If multiple instances of the same option are present in a mount
380 * option list, the rightmost instance is always the effective one.
382 * Returns:
383 * * PO_FOUND if the keyword was found and the value is numeric; @value is
384 * set to the keyword's value
385 * * PO_NOT_FOUND if the keyword was not found
386 * * PO_BAD_VALUE if the keyword was found, but the value is not numeric
388 * These last two are separate in case the caller wants to warn about bad mount
389 * options instead of silently using a default.
391 #ifdef HAVE_STRTOL
392 po_found_t po_get_numeric(struct mount_options *options, char *keyword, long *value)
394 char *option, *endptr;
395 long tmp;
397 option = po_get(options, keyword);
398 if (option == NULL)
399 return PO_NOT_FOUND;
401 errno = 0;
402 tmp = strtol(option, &endptr, 10);
403 if (errno == 0 && endptr != option) {
404 *value = tmp;
405 return PO_FOUND;
407 return PO_BAD_VALUE;
409 #else /* HAVE_STRTOL */
410 po_found_t po_get_numeric(struct mount_options *options, char *keyword, long *value)
412 char *option;
414 option = po_get(options, keyword);
415 if (option == NULL)
416 return PO_NOT_FOUND;
418 *value = atoi(option);
419 return PO_FOUND;
421 #endif /* HAVE_STRTOL */
424 * po_rightmost - determine the relative position of several options
425 * @options: pointer to mount options
426 * @keys: pointer to an array of C strings containing option keywords
428 * This function can be used to determine which of several similar
429 * options will be the one to take effect.
431 * The kernel parses the mount option string from left to right.
432 * If an option is specified more than once (for example, "intr"
433 * and "nointr", the rightmost option is the last to be parsed,
434 * and it therefore takes precedence over previous similar options.
436 * This can also distinguish among multiple synonymous options, such
437 * as "proto=," "udp" and "tcp."
439 * Returns the index into @keys of the option that is rightmost.
440 * If none of the options listed in @keys is present in @options, or
441 * if @options is NULL, returns -1.
443 int po_rightmost(struct mount_options *options, const char *keys[])
445 struct mount_option *option;
446 unsigned int i;
448 if (options) {
449 for (option = options->tail; option; option = option->prev) {
450 for (i = 0; keys[i] != NULL; i++)
451 if (strcmp(option->keyword, keys[i]) == 0)
452 return i;
456 return -1;
460 * po_remove_all - remove instances of an option from a group
461 * @options: pointer to mount options
462 * @keyword: pointer to a C string containing an option keyword to remove
464 * Side-effect: the passed-in list is truncated on success.
466 po_found_t po_remove_all(struct mount_options *options, char *keyword)
468 struct mount_option *option, *next;
469 int found = PO_NOT_FOUND;
471 if (options && keyword) {
472 for (option = options->head; option; option = next) {
473 next = option->next;
474 if (strcmp(option->keyword, keyword) == 0) {
475 options_delete(options, option);
476 found = PO_FOUND;
481 return found;