1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * String manipulation functions.
37  *
38  * libcfs/libcfs/libcfs_string.c
39  *
40  * Author: Nathan Rutman <nathan.rutman@sun.com>
41  */
42 
43 #include "../../include/linux/libcfs/libcfs.h"
44 
45 /* Convert a text string to a bitmask */
cfs_str2mask(const char * str,const char * (* bit2str)(int bit),int * oldmask,int minmask,int allmask)46 int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
47 		 int *oldmask, int minmask, int allmask)
48 {
49 	const char *debugstr;
50 	char op = '\0';
51 	int newmask = minmask, i, len, found = 0;
52 
53 	/* <str> must be a list of tokens separated by whitespace
54 	 * and optionally an operator ('+' or '-').  If an operator
55 	 * appears first in <str>, '*oldmask' is used as the starting point
56 	 * (relative), otherwise minmask is used (absolute).  An operator
57 	 * applies to all following tokens up to the next operator. */
58 	while (*str != '\0') {
59 		while (isspace(*str))
60 			str++;
61 		if (*str == '\0')
62 			break;
63 		if (*str == '+' || *str == '-') {
64 			op = *str++;
65 			if (!found)
66 				/* only if first token is relative */
67 				newmask = *oldmask;
68 			while (isspace(*str))
69 				str++;
70 			if (*str == '\0')  /* trailing op */
71 				return -EINVAL;
72 		}
73 
74 		/* find token length */
75 		len = 0;
76 		while (str[len] != '\0' && !isspace(str[len]) &&
77 		       str[len] != '+' && str[len] != '-')
78 			len++;
79 
80 		/* match token */
81 		found = 0;
82 		for (i = 0; i < 32; i++) {
83 			debugstr = bit2str(i);
84 			if (debugstr != NULL &&
85 			    strlen(debugstr) == len &&
86 			    strncasecmp(str, debugstr, len) == 0) {
87 				if (op == '-')
88 					newmask &= ~(1 << i);
89 				else
90 					newmask |= (1 << i);
91 				found = 1;
92 				break;
93 			}
94 		}
95 		if (!found && len == 3 &&
96 		    (strncasecmp(str, "ALL", len) == 0)) {
97 			if (op == '-')
98 				newmask = minmask;
99 			else
100 				newmask = allmask;
101 			found = 1;
102 		}
103 		if (!found) {
104 			CWARN("unknown mask '%.*s'.\n"
105 			      "mask usage: [+|-]<all|type> ...\n", len, str);
106 			return -EINVAL;
107 		}
108 		str += len;
109 	}
110 
111 	*oldmask = newmask;
112 	return 0;
113 }
114 
115 /* get the first string out of @str */
cfs_firststr(char * str,size_t size)116 char *cfs_firststr(char *str, size_t size)
117 {
118 	size_t i = 0;
119 	char  *end;
120 
121 	/* trim leading spaces */
122 	while (i < size && *str && isspace(*str)) {
123 		++i;
124 		++str;
125 	}
126 
127 	/* string with all spaces */
128 	if (*str == '\0')
129 		goto out;
130 
131 	end = str;
132 	while (i < size && *end != '\0' && !isspace(*end)) {
133 		++i;
134 		++end;
135 	}
136 
137 	*end = '\0';
138 out:
139 	return str;
140 }
141 EXPORT_SYMBOL(cfs_firststr);
142 
143 char *
cfs_trimwhite(char * str)144 cfs_trimwhite(char *str)
145 {
146 	char *end;
147 
148 	while (isspace(*str))
149 		str++;
150 
151 	end = str + strlen(str);
152 	while (end > str) {
153 		if (!isspace(end[-1]))
154 			break;
155 		end--;
156 	}
157 
158 	*end = 0;
159 	return str;
160 }
161 EXPORT_SYMBOL(cfs_trimwhite);
162 
163 /**
164  * Extracts tokens from strings.
165  *
166  * Looks for \a delim in string \a next, sets \a res to point to
167  * substring before the delimiter, sets \a next right after the found
168  * delimiter.
169  *
170  * \retval 1 if \a res points to a string of non-whitespace characters
171  * \retval 0 otherwise
172  */
173 int
cfs_gettok(struct cfs_lstr * next,char delim,struct cfs_lstr * res)174 cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
175 {
176 	char *end;
177 
178 	if (next->ls_str == NULL)
179 		return 0;
180 
181 	/* skip leading white spaces */
182 	while (next->ls_len) {
183 		if (!isspace(*next->ls_str))
184 			break;
185 		next->ls_str++;
186 		next->ls_len--;
187 	}
188 
189 	if (next->ls_len == 0) /* whitespaces only */
190 		return 0;
191 
192 	if (*next->ls_str == delim) {
193 		/* first non-writespace is the delimiter */
194 		return 0;
195 	}
196 
197 	res->ls_str = next->ls_str;
198 	end = memchr(next->ls_str, delim, next->ls_len);
199 	if (end == NULL) {
200 		/* there is no the delimeter in the string */
201 		end = next->ls_str + next->ls_len;
202 		next->ls_str = NULL;
203 	} else {
204 		next->ls_str = end + 1;
205 		next->ls_len -= (end - res->ls_str + 1);
206 	}
207 
208 	/* skip ending whitespaces */
209 	while (--end != res->ls_str) {
210 		if (!isspace(*end))
211 			break;
212 	}
213 
214 	res->ls_len = end - res->ls_str + 1;
215 	return 1;
216 }
217 
218 /**
219  * Converts string to integer.
220  *
221  * Accepts decimal and hexadecimal number recordings.
222  *
223  * \retval 1 if first \a nob chars of \a str convert to decimal or
224  * hexadecimal integer in the range [\a min, \a max]
225  * \retval 0 otherwise
226  */
227 int
cfs_str2num_check(char * str,int nob,unsigned * num,unsigned min,unsigned max)228 cfs_str2num_check(char *str, int nob, unsigned *num,
229 		  unsigned min, unsigned max)
230 {
231 	char	*endp;
232 
233 	str = cfs_trimwhite(str);
234 	*num = strtoul(str, &endp, 0);
235 	if (endp == str)
236 		return 0;
237 
238 	for (; endp < str + nob; endp++) {
239 		if (!isspace(*endp))
240 			return 0;
241 	}
242 
243 	return (*num >= min && *num <= max);
244 }
245 
246 /**
247  * Parses \<range_expr\> token of the syntax. If \a bracketed is false,
248  * \a src should only have a single token which can be \<number\> or  \*
249  *
250  * \retval pointer to allocated range_expr and initialized
251  * range_expr::re_lo, range_expr::re_hi and range_expr:re_stride if \a
252  `* src parses to
253  * \<number\> |
254  * \<number\> '-' \<number\> |
255  * \<number\> '-' \<number\> '/' \<number\>
256  * \retval 0 will be returned if it can be parsed, otherwise -EINVAL or
257  * -ENOMEM will be returned.
258  */
259 static int
cfs_range_expr_parse(struct cfs_lstr * src,unsigned min,unsigned max,int bracketed,struct cfs_range_expr ** expr)260 cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max,
261 		     int bracketed, struct cfs_range_expr **expr)
262 {
263 	struct cfs_range_expr	*re;
264 	struct cfs_lstr		tok;
265 
266 	LIBCFS_ALLOC(re, sizeof(*re));
267 	if (re == NULL)
268 		return -ENOMEM;
269 
270 	if (src->ls_len == 1 && src->ls_str[0] == '*') {
271 		re->re_lo = min;
272 		re->re_hi = max;
273 		re->re_stride = 1;
274 		goto out;
275 	}
276 
277 	if (cfs_str2num_check(src->ls_str, src->ls_len,
278 			      &re->re_lo, min, max)) {
279 		/* <number> is parsed */
280 		re->re_hi = re->re_lo;
281 		re->re_stride = 1;
282 		goto out;
283 	}
284 
285 	if (!bracketed || !cfs_gettok(src, '-', &tok))
286 		goto failed;
287 
288 	if (!cfs_str2num_check(tok.ls_str, tok.ls_len,
289 			       &re->re_lo, min, max))
290 		goto failed;
291 
292 	/* <number> - */
293 	if (cfs_str2num_check(src->ls_str, src->ls_len,
294 			      &re->re_hi, min, max)) {
295 		/* <number> - <number> is parsed */
296 		re->re_stride = 1;
297 		goto out;
298 	}
299 
300 	/* go to check <number> '-' <number> '/' <number> */
301 	if (cfs_gettok(src, '/', &tok)) {
302 		if (!cfs_str2num_check(tok.ls_str, tok.ls_len,
303 				       &re->re_hi, min, max))
304 			goto failed;
305 
306 		/* <number> - <number> / ... */
307 		if (cfs_str2num_check(src->ls_str, src->ls_len,
308 				      &re->re_stride, min, max)) {
309 			/* <number> - <number> / <number> is parsed */
310 			goto out;
311 		}
312 	}
313 
314  out:
315 	*expr = re;
316 	return 0;
317 
318  failed:
319 	LIBCFS_FREE(re, sizeof(*re));
320 	return -EINVAL;
321 }
322 
323 /**
324  * Matches value (\a value) against ranges expression list \a expr_list.
325  *
326  * \retval 1 if \a value matches
327  * \retval 0 otherwise
328  */
329 int
cfs_expr_list_match(__u32 value,struct cfs_expr_list * expr_list)330 cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list)
331 {
332 	struct cfs_range_expr	*expr;
333 
334 	list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
335 		if (value >= expr->re_lo && value <= expr->re_hi &&
336 		    ((value - expr->re_lo) % expr->re_stride) == 0)
337 			return 1;
338 	}
339 
340 	return 0;
341 }
342 
343 /**
344  * Convert express list (\a expr_list) to an array of all matched values
345  *
346  * \retval N N is total number of all matched values
347  * \retval 0 if expression list is empty
348  * \retval < 0 for failure
349  */
350 int
cfs_expr_list_values(struct cfs_expr_list * expr_list,int max,__u32 ** valpp)351 cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp)
352 {
353 	struct cfs_range_expr	*expr;
354 	__u32			*val;
355 	int			count = 0;
356 	int			i;
357 
358 	list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
359 		for (i = expr->re_lo; i <= expr->re_hi; i++) {
360 			if (((i - expr->re_lo) % expr->re_stride) == 0)
361 				count++;
362 		}
363 	}
364 
365 	if (count == 0) /* empty expression list */
366 		return 0;
367 
368 	if (count > max) {
369 		CERROR("Number of values %d exceeds max allowed %d\n",
370 		       max, count);
371 		return -EINVAL;
372 	}
373 
374 	LIBCFS_ALLOC(val, sizeof(val[0]) * count);
375 	if (val == NULL)
376 		return -ENOMEM;
377 
378 	count = 0;
379 	list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
380 		for (i = expr->re_lo; i <= expr->re_hi; i++) {
381 			if (((i - expr->re_lo) % expr->re_stride) == 0)
382 				val[count++] = i;
383 		}
384 	}
385 
386 	*valpp = val;
387 	return count;
388 }
389 EXPORT_SYMBOL(cfs_expr_list_values);
390 
391 /**
392  * Frees cfs_range_expr structures of \a expr_list.
393  *
394  * \retval none
395  */
396 void
cfs_expr_list_free(struct cfs_expr_list * expr_list)397 cfs_expr_list_free(struct cfs_expr_list *expr_list)
398 {
399 	while (!list_empty(&expr_list->el_exprs)) {
400 		struct cfs_range_expr *expr;
401 
402 		expr = list_entry(expr_list->el_exprs.next,
403 				      struct cfs_range_expr, re_link),
404 		list_del(&expr->re_link);
405 		LIBCFS_FREE(expr, sizeof(*expr));
406 	}
407 
408 	LIBCFS_FREE(expr_list, sizeof(*expr_list));
409 }
410 EXPORT_SYMBOL(cfs_expr_list_free);
411 
412 /**
413  * Parses \<cfs_expr_list\> token of the syntax.
414  *
415  * \retval 1 if \a str parses to \<number\> | \<expr_list\>
416  * \retval 0 otherwise
417  */
418 int
cfs_expr_list_parse(char * str,int len,unsigned min,unsigned max,struct cfs_expr_list ** elpp)419 cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
420 		    struct cfs_expr_list **elpp)
421 {
422 	struct cfs_expr_list	*expr_list;
423 	struct cfs_range_expr	*expr;
424 	struct cfs_lstr		src;
425 	int			rc;
426 
427 	LIBCFS_ALLOC(expr_list, sizeof(*expr_list));
428 	if (expr_list == NULL)
429 		return -ENOMEM;
430 
431 	src.ls_str = str;
432 	src.ls_len = len;
433 
434 	INIT_LIST_HEAD(&expr_list->el_exprs);
435 
436 	if (src.ls_str[0] == '[' &&
437 	    src.ls_str[src.ls_len - 1] == ']') {
438 		src.ls_str++;
439 		src.ls_len -= 2;
440 
441 		rc = -EINVAL;
442 		while (src.ls_str != NULL) {
443 			struct cfs_lstr tok;
444 
445 			if (!cfs_gettok(&src, ',', &tok)) {
446 				rc = -EINVAL;
447 				break;
448 			}
449 
450 			rc = cfs_range_expr_parse(&tok, min, max, 1, &expr);
451 			if (rc != 0)
452 				break;
453 
454 			list_add_tail(&expr->re_link,
455 					  &expr_list->el_exprs);
456 		}
457 	} else {
458 		rc = cfs_range_expr_parse(&src, min, max, 0, &expr);
459 		if (rc == 0) {
460 			list_add_tail(&expr->re_link,
461 					  &expr_list->el_exprs);
462 		}
463 	}
464 
465 	if (rc != 0)
466 		cfs_expr_list_free(expr_list);
467 	else
468 		*elpp = expr_list;
469 
470 	return rc;
471 }
472 EXPORT_SYMBOL(cfs_expr_list_parse);
473 
474 /**
475  * Frees cfs_expr_list structures of \a list.
476  *
477  * For each struct cfs_expr_list structure found on \a list it frees
478  * range_expr list attached to it and frees the cfs_expr_list itself.
479  *
480  * \retval none
481  */
482 void
cfs_expr_list_free_list(struct list_head * list)483 cfs_expr_list_free_list(struct list_head *list)
484 {
485 	struct cfs_expr_list *el;
486 
487 	while (!list_empty(list)) {
488 		el = list_entry(list->next,
489 				    struct cfs_expr_list, el_link);
490 		list_del(&el->el_link);
491 		cfs_expr_list_free(el);
492 	}
493 }
494 
495 int
cfs_ip_addr_parse(char * str,int len,struct list_head * list)496 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
497 {
498 	struct cfs_expr_list	*el;
499 	struct cfs_lstr		src;
500 	int			rc;
501 	int			i;
502 
503 	src.ls_str = str;
504 	src.ls_len = len;
505 	i = 0;
506 
507 	while (src.ls_str != NULL) {
508 		struct cfs_lstr res;
509 
510 		if (!cfs_gettok(&src, '.', &res)) {
511 			rc = -EINVAL;
512 			goto out;
513 		}
514 
515 		rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
516 		if (rc != 0)
517 			goto out;
518 
519 		list_add_tail(&el->el_link, list);
520 		i++;
521 	}
522 
523 	if (i == 4)
524 		return 0;
525 
526 	rc = -EINVAL;
527  out:
528 	cfs_expr_list_free_list(list);
529 
530 	return rc;
531 }
532 EXPORT_SYMBOL(cfs_ip_addr_parse);
533 
534 /**
535  * Matches address (\a addr) against address set encoded in \a list.
536  *
537  * \retval 1 if \a addr matches
538  * \retval 0 otherwise
539  */
540 int
cfs_ip_addr_match(__u32 addr,struct list_head * list)541 cfs_ip_addr_match(__u32 addr, struct list_head *list)
542 {
543 	struct cfs_expr_list *el;
544 	int i = 0;
545 
546 	list_for_each_entry_reverse(el, list, el_link) {
547 		if (!cfs_expr_list_match(addr & 0xff, el))
548 			return 0;
549 		addr >>= 8;
550 		i++;
551 	}
552 
553 	return i == 4;
554 }
555 EXPORT_SYMBOL(cfs_ip_addr_match);
556 
557 void
cfs_ip_addr_free(struct list_head * list)558 cfs_ip_addr_free(struct list_head *list)
559 {
560 	cfs_expr_list_free_list(list);
561 }
562 EXPORT_SYMBOL(cfs_ip_addr_free);
563