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 */ 46int 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 for (len = 0; str[len] != 0 && !isspace(str[len]) && 76 str[len] != '+' && str[len] != '-'; len++); 77 78 /* match token */ 79 found = 0; 80 for (i = 0; i < 32; i++) { 81 debugstr = bit2str(i); 82 if (debugstr != NULL && 83 strlen(debugstr) == len && 84 strncasecmp(str, debugstr, len) == 0) { 85 if (op == '-') 86 newmask &= ~(1 << i); 87 else 88 newmask |= (1 << i); 89 found = 1; 90 break; 91 } 92 } 93 if (!found && len == 3 && 94 (strncasecmp(str, "ALL", len) == 0)) { 95 if (op == '-') 96 newmask = minmask; 97 else 98 newmask = allmask; 99 found = 1; 100 } 101 if (!found) { 102 CWARN("unknown mask '%.*s'.\n" 103 "mask usage: [+|-]<all|type> ...\n", len, str); 104 return -EINVAL; 105 } 106 str += len; 107 } 108 109 *oldmask = newmask; 110 return 0; 111} 112 113/* get the first string out of @str */ 114char *cfs_firststr(char *str, size_t size) 115{ 116 size_t i = 0; 117 char *end; 118 119 /* trim leading spaces */ 120 while (i < size && *str && isspace(*str)) { 121 ++i; 122 ++str; 123 } 124 125 /* string with all spaces */ 126 if (*str == '\0') 127 goto out; 128 129 end = str; 130 while (i < size && *end != '\0' && !isspace(*end)) { 131 ++i; 132 ++end; 133 } 134 135 *end= '\0'; 136out: 137 return str; 138} 139EXPORT_SYMBOL(cfs_firststr); 140 141char * 142cfs_trimwhite(char *str) 143{ 144 char *end; 145 146 while (isspace(*str)) 147 str++; 148 149 end = str + strlen(str); 150 while (end > str) { 151 if (!isspace(end[-1])) 152 break; 153 end--; 154 } 155 156 *end = 0; 157 return str; 158} 159EXPORT_SYMBOL(cfs_trimwhite); 160 161/** 162 * Extracts tokens from strings. 163 * 164 * Looks for \a delim in string \a next, sets \a res to point to 165 * substring before the delimiter, sets \a next right after the found 166 * delimiter. 167 * 168 * \retval 1 if \a res points to a string of non-whitespace characters 169 * \retval 0 otherwise 170 */ 171int 172cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res) 173{ 174 char *end; 175 176 if (next->ls_str == NULL) 177 return 0; 178 179 /* skip leading white spaces */ 180 while (next->ls_len) { 181 if (!isspace(*next->ls_str)) 182 break; 183 next->ls_str++; 184 next->ls_len--; 185 } 186 187 if (next->ls_len == 0) /* whitespaces only */ 188 return 0; 189 190 if (*next->ls_str == delim) { 191 /* first non-writespace is the delimiter */ 192 return 0; 193 } 194 195 res->ls_str = next->ls_str; 196 end = memchr(next->ls_str, delim, next->ls_len); 197 if (end == NULL) { 198 /* there is no the delimeter in the string */ 199 end = next->ls_str + next->ls_len; 200 next->ls_str = NULL; 201 } else { 202 next->ls_str = end + 1; 203 next->ls_len -= (end - res->ls_str + 1); 204 } 205 206 /* skip ending whitespaces */ 207 while (--end != res->ls_str) { 208 if (!isspace(*end)) 209 break; 210 } 211 212 res->ls_len = end - res->ls_str + 1; 213 return 1; 214} 215 216/** 217 * Converts string to integer. 218 * 219 * Accepts decimal and hexadecimal number recordings. 220 * 221 * \retval 1 if first \a nob chars of \a str convert to decimal or 222 * hexadecimal integer in the range [\a min, \a max] 223 * \retval 0 otherwise 224 */ 225int 226cfs_str2num_check(char *str, int nob, unsigned *num, 227 unsigned min, unsigned max) 228{ 229 char *endp; 230 231 str = cfs_trimwhite(str); 232 *num = strtoul(str, &endp, 0); 233 if (endp == str) 234 return 0; 235 236 for (; endp < str + nob; endp++) { 237 if (!isspace(*endp)) 238 return 0; 239 } 240 241 return (*num >= min && *num <= max); 242} 243 244/** 245 * Parses \<range_expr\> token of the syntax. If \a bracketed is false, 246 * \a src should only have a single token which can be \<number\> or \* 247 * 248 * \retval pointer to allocated range_expr and initialized 249 * range_expr::re_lo, range_expr::re_hi and range_expr:re_stride if \a 250 `* src parses to 251 * \<number\> | 252 * \<number\> '-' \<number\> | 253 * \<number\> '-' \<number\> '/' \<number\> 254 * \retval 0 will be returned if it can be parsed, otherwise -EINVAL or 255 * -ENOMEM will be returned. 256 */ 257static int 258cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max, 259 int bracketed, struct cfs_range_expr **expr) 260{ 261 struct cfs_range_expr *re; 262 struct cfs_lstr tok; 263 264 LIBCFS_ALLOC(re, sizeof(*re)); 265 if (re == NULL) 266 return -ENOMEM; 267 268 if (src->ls_len == 1 && src->ls_str[0] == '*') { 269 re->re_lo = min; 270 re->re_hi = max; 271 re->re_stride = 1; 272 goto out; 273 } 274 275 if (cfs_str2num_check(src->ls_str, src->ls_len, 276 &re->re_lo, min, max)) { 277 /* <number> is parsed */ 278 re->re_hi = re->re_lo; 279 re->re_stride = 1; 280 goto out; 281 } 282 283 if (!bracketed || !cfs_gettok(src, '-', &tok)) 284 goto failed; 285 286 if (!cfs_str2num_check(tok.ls_str, tok.ls_len, 287 &re->re_lo, min, max)) 288 goto failed; 289 290 /* <number> - */ 291 if (cfs_str2num_check(src->ls_str, src->ls_len, 292 &re->re_hi, min, max)) { 293 /* <number> - <number> is parsed */ 294 re->re_stride = 1; 295 goto out; 296 } 297 298 /* go to check <number> '-' <number> '/' <number> */ 299 if (cfs_gettok(src, '/', &tok)) { 300 if (!cfs_str2num_check(tok.ls_str, tok.ls_len, 301 &re->re_hi, min, max)) 302 goto failed; 303 304 /* <number> - <number> / ... */ 305 if (cfs_str2num_check(src->ls_str, src->ls_len, 306 &re->re_stride, min, max)) { 307 /* <number> - <number> / <number> is parsed */ 308 goto out; 309 } 310 } 311 312 out: 313 *expr = re; 314 return 0; 315 316 failed: 317 LIBCFS_FREE(re, sizeof(*re)); 318 return -EINVAL; 319} 320 321/** 322 * Matches value (\a value) against ranges expression list \a expr_list. 323 * 324 * \retval 1 if \a value matches 325 * \retval 0 otherwise 326 */ 327int 328cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list) 329{ 330 struct cfs_range_expr *expr; 331 332 list_for_each_entry(expr, &expr_list->el_exprs, re_link) { 333 if (value >= expr->re_lo && value <= expr->re_hi && 334 ((value - expr->re_lo) % expr->re_stride) == 0) 335 return 1; 336 } 337 338 return 0; 339} 340 341/** 342 * Convert express list (\a expr_list) to an array of all matched values 343 * 344 * \retval N N is total number of all matched values 345 * \retval 0 if expression list is empty 346 * \retval < 0 for failure 347 */ 348int 349cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp) 350{ 351 struct cfs_range_expr *expr; 352 __u32 *val; 353 int count = 0; 354 int i; 355 356 list_for_each_entry(expr, &expr_list->el_exprs, re_link) { 357 for (i = expr->re_lo; i <= expr->re_hi; i++) { 358 if (((i - expr->re_lo) % expr->re_stride) == 0) 359 count++; 360 } 361 } 362 363 if (count == 0) /* empty expression list */ 364 return 0; 365 366 if (count > max) { 367 CERROR("Number of values %d exceeds max allowed %d\n", 368 max, count); 369 return -EINVAL; 370 } 371 372 LIBCFS_ALLOC(val, sizeof(val[0]) * count); 373 if (val == NULL) 374 return -ENOMEM; 375 376 count = 0; 377 list_for_each_entry(expr, &expr_list->el_exprs, re_link) { 378 for (i = expr->re_lo; i <= expr->re_hi; i++) { 379 if (((i - expr->re_lo) % expr->re_stride) == 0) 380 val[count++] = i; 381 } 382 } 383 384 *valpp = val; 385 return count; 386} 387EXPORT_SYMBOL(cfs_expr_list_values); 388 389/** 390 * Frees cfs_range_expr structures of \a expr_list. 391 * 392 * \retval none 393 */ 394void 395cfs_expr_list_free(struct cfs_expr_list *expr_list) 396{ 397 while (!list_empty(&expr_list->el_exprs)) { 398 struct cfs_range_expr *expr; 399 400 expr = list_entry(expr_list->el_exprs.next, 401 struct cfs_range_expr, re_link), 402 list_del(&expr->re_link); 403 LIBCFS_FREE(expr, sizeof(*expr)); 404 } 405 406 LIBCFS_FREE(expr_list, sizeof(*expr_list)); 407} 408EXPORT_SYMBOL(cfs_expr_list_free); 409 410/** 411 * Parses \<cfs_expr_list\> token of the syntax. 412 * 413 * \retval 1 if \a str parses to \<number\> | \<expr_list\> 414 * \retval 0 otherwise 415 */ 416int 417cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max, 418 struct cfs_expr_list **elpp) 419{ 420 struct cfs_expr_list *expr_list; 421 struct cfs_range_expr *expr; 422 struct cfs_lstr src; 423 int rc; 424 425 LIBCFS_ALLOC(expr_list, sizeof(*expr_list)); 426 if (expr_list == NULL) 427 return -ENOMEM; 428 429 src.ls_str = str; 430 src.ls_len = len; 431 432 INIT_LIST_HEAD(&expr_list->el_exprs); 433 434 if (src.ls_str[0] == '[' && 435 src.ls_str[src.ls_len - 1] == ']') { 436 src.ls_str++; 437 src.ls_len -= 2; 438 439 rc = -EINVAL; 440 while (src.ls_str != NULL) { 441 struct cfs_lstr tok; 442 443 if (!cfs_gettok(&src, ',', &tok)) { 444 rc = -EINVAL; 445 break; 446 } 447 448 rc = cfs_range_expr_parse(&tok, min, max, 1, &expr); 449 if (rc != 0) 450 break; 451 452 list_add_tail(&expr->re_link, 453 &expr_list->el_exprs); 454 } 455 } else { 456 rc = cfs_range_expr_parse(&src, min, max, 0, &expr); 457 if (rc == 0) { 458 list_add_tail(&expr->re_link, 459 &expr_list->el_exprs); 460 } 461 } 462 463 if (rc != 0) 464 cfs_expr_list_free(expr_list); 465 else 466 *elpp = expr_list; 467 468 return rc; 469} 470EXPORT_SYMBOL(cfs_expr_list_parse); 471 472/** 473 * Frees cfs_expr_list structures of \a list. 474 * 475 * For each struct cfs_expr_list structure found on \a list it frees 476 * range_expr list attached to it and frees the cfs_expr_list itself. 477 * 478 * \retval none 479 */ 480void 481cfs_expr_list_free_list(struct list_head *list) 482{ 483 struct cfs_expr_list *el; 484 485 while (!list_empty(list)) { 486 el = list_entry(list->next, 487 struct cfs_expr_list, el_link); 488 list_del(&el->el_link); 489 cfs_expr_list_free(el); 490 } 491} 492 493int 494cfs_ip_addr_parse(char *str, int len, struct list_head *list) 495{ 496 struct cfs_expr_list *el; 497 struct cfs_lstr src; 498 int rc; 499 int i; 500 501 src.ls_str = str; 502 src.ls_len = len; 503 i = 0; 504 505 while (src.ls_str != NULL) { 506 struct cfs_lstr res; 507 508 if (!cfs_gettok(&src, '.', &res)) { 509 rc = -EINVAL; 510 goto out; 511 } 512 513 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el); 514 if (rc != 0) 515 goto out; 516 517 list_add_tail(&el->el_link, list); 518 i++; 519 } 520 521 if (i == 4) 522 return 0; 523 524 rc = -EINVAL; 525 out: 526 cfs_expr_list_free_list(list); 527 528 return rc; 529} 530EXPORT_SYMBOL(cfs_ip_addr_parse); 531 532/** 533 * Matches address (\a addr) against address set encoded in \a list. 534 * 535 * \retval 1 if \a addr matches 536 * \retval 0 otherwise 537 */ 538int 539cfs_ip_addr_match(__u32 addr, struct list_head *list) 540{ 541 struct cfs_expr_list *el; 542 int i = 0; 543 544 list_for_each_entry_reverse(el, list, el_link) { 545 if (!cfs_expr_list_match(addr & 0xff, el)) 546 return 0; 547 addr >>= 8; 548 i++; 549 } 550 551 return i == 4; 552} 553EXPORT_SYMBOL(cfs_ip_addr_match); 554 555void 556cfs_ip_addr_free(struct list_head *list) 557{ 558 cfs_expr_list_free_list(list); 559} 560EXPORT_SYMBOL(cfs_ip_addr_free); 561