Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / libcfs / libcfs / libcfs_string.c
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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * String manipulation functions.
32  *
33  * libcfs/libcfs/libcfs_string.c
34  *
35  * Author: Nathan Rutman <nathan.rutman@sun.com>
36  */
37
38 #include <linux/ctype.h>
39 #include <libcfs/libcfs.h>
40 #include <libcfs/libcfs_string.h>
41
42 /* Convert a text string to a bitmask */
43 int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
44                  int *oldmask, int minmask, int allmask, int defmask)
45 {
46         const char *debugstr;
47         char op = 0;
48         int newmask = minmask, i, len, found = 0;
49
50         ENTRY;
51         /* <str> must be a list of tokens separated by whitespace or comma,
52          * and optionally an operator ('+' or '-').  If an operator
53          * appears first in <str>, '*oldmask' is used as the starting point
54          * (relative), otherwise minmask is used (absolute).  An operator
55          * applies to all following tokens up to the next operator.
56          */
57         while (*str != 0) {
58                 while (isspace(*str) || *str == ',')
59                         str++;
60                 if (*str == 0)
61                         break;
62                 if (*str == '+' || *str == '-') {
63                         op = *str++;
64                         if (!found)
65                                 /* only if first token is relative */
66                                 newmask = *oldmask;
67                         while (isspace(*str))
68                                 str++;
69                         if (*str == 0)          /* trailing op */
70                                 return -EINVAL;
71                 }
72
73                 /* find token length */
74                 for (len = 0; str[len] != 0 && !isspace(str[len]) &&
75                         str[len] != '+' && str[len] != '-' && str[len] != ',';
76                      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 &= ~BIT(i);
87                                 else
88                                         newmask |= BIT(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 && strcasecmp(str, "DEFAULT") == 0) {
102                         if (op == '-')
103                                 newmask = (newmask & ~defmask) | minmask;
104                         else if (op == '+')
105                                 newmask |= defmask;
106                         else
107                                 newmask = defmask;
108                         found = 1;
109                 }
110                 if (!found) {
111                         CWARN("unknown mask '%.*s'.\n"
112                               "mask usage: [+|-]<all|type> ...\n", len, str);
113                         return -EINVAL;
114                 }
115                 str += len;
116         }
117
118         *oldmask = newmask;
119         return 0;
120 }
121 EXPORT_SYMBOL(cfs_str2mask);