Whamcloud - gitweb
LU-13791 mdt: allow using symbolic capability names
[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
43 /* convert a binary mask to a string of bit names */
44 int cfs_mask2str(char *str, int size, u64 mask, const char *(*bit2str)(int bit),
45                  char sep)
46 {
47         int len = 0;
48         const char *token;
49         int i;
50
51         if (mask == 0) {                        /* "0" */
52                 if (size > 0)
53                         str[0] = '0';
54                 len = 1;
55         } else {                                /* space-separated tokens */
56                 for (i = 0; i < 64; i++) {
57                         if ((mask & BIT(i)) == 0)
58                                 continue;
59
60                         token = bit2str(i);
61                         if (!token)             /* unused bit */
62                                 continue;
63
64                         if (len > 0) {          /* separator? */
65                                 if (len < size)
66                                         str[len] = sep;
67                                 len++;
68                         }
69
70                         while (*token != 0) {
71                                 if (len < size)
72                                         str[len] = *token;
73                                 token++;
74                                 len++;
75                         }
76                 }
77         }
78
79         /* terminate 'str' */
80         if (len < size)
81                 str[len++] = '\n';
82         if (len < size)
83                 str[len] = '\0';
84         else
85                 str[size - 1] = '\0';
86
87         return len;
88 }
89 EXPORT_SYMBOL(cfs_mask2str);
90
91 /* Convert a text string to a bitmask */
92 int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
93                  u64 *oldmask, u64 minmask, u64 allmask, u64 defmask)
94 {
95         const char *debugstr;
96         u64 newmask = minmask, found = 0;
97
98         ENTRY;
99         /* <str> must be a list of tokens separated by whitespace or comma,
100          * and optionally an operator ('+' or '-').  If an operator
101          * appears first in <str>, '*oldmask' is used as the starting point
102          * (relative), otherwise minmask is used (absolute).  An operator
103          * applies to all following tokens up to the next operator.
104          */
105         while (*str != 0) {
106                 int i, len;
107                 char op = 0;
108
109                 while (isspace(*str) || *str == ',')
110                         str++;
111                 if (*str == 0)
112                         break;
113                 if (*str == '+' || *str == '-') {
114                         op = *str++;
115                         if (!found)
116                                 /* only if first token is relative */
117                                 newmask = *oldmask;
118                         while (isspace(*str))
119                                 str++;
120                         if (*str == 0)          /* trailing op */
121                                 return -EINVAL;
122                 }
123
124                 /* find token length */
125                 for (len = 0; str[len] != 0 && !isspace(str[len]) &&
126                         str[len] != '+' && str[len] != '-' && str[len] != ',';
127                      len++);
128
129                 /* match token */
130                 found = 0;
131                 for (i = 0; i < 32; i++) {
132                         debugstr = bit2str(i);
133                         if (debugstr != NULL &&
134                             strlen(debugstr) == len &&
135                             strncasecmp(str, debugstr, len) == 0) {
136                                 if (op == '-')
137                                         newmask &= ~BIT(i);
138                                 else
139                                         newmask |= BIT(i);
140                                 found = 1;
141                                 break;
142                         }
143                 }
144                 if (!found && len == 3 &&
145                     (strncasecmp(str, "ALL", len) == 0)) {
146                         if (op == '-')
147                                 newmask = minmask;
148                         else
149                                 newmask = allmask;
150                         found = 1;
151                 }
152                 if (!found && strcasecmp(str, "DEFAULT") == 0) {
153                         if (op == '-')
154                                 newmask = (newmask & ~defmask) | minmask;
155                         else if (op == '+')
156                                 newmask |= defmask;
157                         else
158                                 newmask = defmask;
159                         found = 1;
160                 }
161                 if (!found) {
162                         CWARN("unknown mask '%.*s'.\n"
163                               "mask usage: [+|-]<all|type> ...\n", len, str);
164                         return -EINVAL;
165                 }
166                 str += len;
167         }
168
169         *oldmask = newmask;
170         return 0;
171 }
172 EXPORT_SYMBOL(cfs_str2mask);