1 /*-
2 * Copyright (c) 2010 Isilon Systems, Inc.
3 * Copyright (c) 2010 iX Systems, Inc.
4 * Copyright (c) 2010 Panasas, Inc.
5 * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice unmodified, this list of conditions, and the following
13 * disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef _LINUXKPI_LINUX_STRING_H_
30 #define _LINUXKPI_LINUX_STRING_H_
31
32 #include <sys/ctype.h>
33
34 #include <linux/array_size.h>
35 #include <linux/types.h>
36 #include <linux/gfp.h>
37 #include <linux/slab.h>
38 #include <linux/uaccess.h>
39 #include <linux/err.h>
40 #include <linux/bitops.h> /* for BITS_PER_LONG */
41 #include <linux/overflow.h>
42 #include <linux/stdarg.h>
43
44 #include <sys/libkern.h>
45
46 #define strnicmp(...) strncasecmp(__VA_ARGS__)
47
48 static inline int
match_string(const char * const * table,int n,const char * key)49 match_string(const char *const *table, int n, const char *key)
50 {
51 int i;
52
53 for (i = 0; i != n && table[i] != NULL; i++) {
54 if (strcmp(table[i], key) == 0)
55 return (i);
56 }
57 return (-EINVAL);
58 }
59
60 static inline void *
memdup_user(const void * ptr,size_t len)61 memdup_user(const void *ptr, size_t len)
62 {
63 void *retval;
64 int error;
65
66 retval = malloc(len, M_KMALLOC, M_WAITOK);
67 error = linux_copyin(ptr, retval, len);
68 if (error != 0) {
69 free(retval, M_KMALLOC);
70 return (ERR_PTR(error));
71 }
72 return (retval);
73 }
74
75 static inline void *
memdup_user_nul(const void * ptr,size_t len)76 memdup_user_nul(const void *ptr, size_t len)
77 {
78 char *retval;
79 int error;
80
81 retval = malloc(len + 1, M_KMALLOC, M_WAITOK);
82 error = linux_copyin(ptr, retval, len);
83 if (error != 0) {
84 free(retval, M_KMALLOC);
85 return (ERR_PTR(error));
86 }
87 retval[len] = '\0';
88 return (retval);
89 }
90
91 static inline void *
memdup_array_user(const void * src,size_t n,size_t size)92 memdup_array_user(const void *src, size_t n, size_t size)
93 {
94 size_t len;
95
96 if (check_mul_overflow(n, size, &len))
97 return (ERR_PTR(-EOVERFLOW));
98
99 return (memdup_user(src, len));
100 }
101
102 static inline void *
kmemdup(const void * src,size_t len,gfp_t gfp)103 kmemdup(const void *src, size_t len, gfp_t gfp)
104 {
105 void *dst;
106
107 dst = kmalloc(len, gfp);
108 if (dst != NULL)
109 memcpy(dst, src, len);
110 return (dst);
111 }
112
113 static inline void *
kmemdup_array(const void * src,size_t count,size_t element_size,gfp_t gfp)114 kmemdup_array(const void *src, size_t count, size_t element_size, gfp_t gfp)
115 {
116 return (kmemdup(src, size_mul(count, element_size), gfp));
117 }
118
119 /* See slab.h for kvmalloc/kvfree(). */
120 static inline void *
kvmemdup(const void * src,size_t len,gfp_t gfp)121 kvmemdup(const void *src, size_t len, gfp_t gfp)
122 {
123 void *dst;
124
125 dst = kvmalloc(len, gfp);
126 if (dst != NULL)
127 memcpy(dst, src, len);
128 return (dst);
129 }
130
131 static inline char *
strndup_user(const char __user * ustr,long n)132 strndup_user(const char __user *ustr, long n)
133 {
134 if (n < 1)
135 return (ERR_PTR(-EINVAL));
136
137 return (memdup_user_nul(ustr, n - 1));
138 }
139
140 static inline char *
kstrdup(const char * string,gfp_t gfp)141 kstrdup(const char *string, gfp_t gfp)
142 {
143 char *retval;
144 size_t len;
145
146 if (string == NULL)
147 return (NULL);
148 len = strlen(string) + 1;
149 retval = kmalloc(len, gfp);
150 if (retval != NULL)
151 memcpy(retval, string, len);
152 return (retval);
153 }
154
155 static inline char *
kstrndup(const char * string,size_t len,gfp_t gfp)156 kstrndup(const char *string, size_t len, gfp_t gfp)
157 {
158 char *retval;
159
160 if (string == NULL)
161 return (NULL);
162 retval = kmalloc(len + 1, gfp);
163 if (retval != NULL)
164 strncpy(retval, string, len);
165 return (retval);
166 }
167
168 static inline const char *
kstrdup_const(const char * src,gfp_t gfp)169 kstrdup_const(const char *src, gfp_t gfp)
170 {
171 return (kmemdup(src, strlen(src) + 1, gfp));
172 }
173
174 static inline char *
skip_spaces(const char * str)175 skip_spaces(const char *str)
176 {
177 while (isspace(*str))
178 ++str;
179 return (__DECONST(char *, str));
180 }
181
182 /*
183 * This function trims whitespaces at the end of a string and returns a pointer
184 * to the first non-whitespace character.
185 */
186 static inline char *
strim(char * str)187 strim(char *str)
188 {
189 char *end;
190
191 end = str + strlen(str);
192 while (end >= str && (*end == '\0' || isspace(*end))) {
193 *end = '\0';
194 end--;
195 }
196
197 return (skip_spaces(str));
198 }
199
200 static inline void *
memchr_inv(const void * start,int c,size_t length)201 memchr_inv(const void *start, int c, size_t length)
202 {
203 const u8 *ptr;
204 const u8 *end;
205 u8 ch;
206
207 ch = c;
208 ptr = start;
209 end = ptr + length;
210
211 while (ptr != end) {
212 if (*ptr != ch)
213 return (__DECONST(void *, ptr));
214 ptr++;
215 }
216 return (NULL);
217 }
218
219 static inline bool
mem_is_zero(const void * start,size_t length)220 mem_is_zero(const void *start, size_t length)
221 {
222 return (memchr_inv(start, 0, length) == NULL);
223 }
224
225 static inline size_t
str_has_prefix(const char * str,const char * prefix)226 str_has_prefix(const char *str, const char *prefix)
227 {
228 size_t len;
229
230 len = strlen(prefix);
231 return (strncmp(str, prefix, len) == 0 ? len : 0);
232 }
233
234 static inline char *
strreplace(char * str,char old,char new)235 strreplace(char *str, char old, char new)
236 {
237 char *p;
238
239 p = strchrnul(str, old);
240 while (p != NULL && *p != '\0') {
241 *p = new;
242 p = strchrnul(str, old);
243 }
244 return (p);
245 }
246
247 static inline ssize_t
strscpy(char * dst,const char * src,size_t len)248 strscpy(char* dst, const char* src, size_t len)
249 {
250 size_t i;
251
252 if (len <= INT_MAX) {
253 for (i = 0; i < len; i++)
254 if ('\0' == (dst[i] = src[i]))
255 return ((ssize_t)i);
256 if (i != 0)
257 dst[--i] = '\0';
258 }
259
260 return (-E2BIG);
261 }
262
263 static inline ssize_t
strscpy_pad(char * dst,const char * src,size_t len)264 strscpy_pad(char* dst, const char* src, size_t len)
265 {
266
267 bzero(dst, len);
268
269 return (strscpy(dst, src, len));
270 }
271
272 static inline char *
strnchr(const char * cp,size_t n,int ch)273 strnchr(const char *cp, size_t n, int ch)
274 {
275 char *p;
276
277 for (p = __DECONST(char *, cp); n--; ++p) {
278 if (*p == ch)
279 return (p);
280 if (*p == '\0')
281 break;
282 }
283
284 return (NULL);
285 }
286
287 static inline void *
memset32(uint32_t * b,uint32_t c,size_t len)288 memset32(uint32_t *b, uint32_t c, size_t len)
289 {
290 uint32_t *dst = b;
291
292 while (len--)
293 *dst++ = c;
294 return (b);
295 }
296
297 static inline void *
memset64(uint64_t * b,uint64_t c,size_t len)298 memset64(uint64_t *b, uint64_t c, size_t len)
299 {
300 uint64_t *dst = b;
301
302 while (len--)
303 *dst++ = c;
304 return (b);
305 }
306
307 static inline void *
memset_p(void ** p,void * v,size_t n)308 memset_p(void **p, void *v, size_t n)
309 {
310
311 if (BITS_PER_LONG == 32)
312 return (memset32((uint32_t *)p, (uintptr_t)v, n));
313 else
314 return (memset64((uint64_t *)p, (uintptr_t)v, n));
315 }
316
317 static inline void
memcpy_and_pad(void * dst,size_t dstlen,const void * src,size_t len,int ch)318 memcpy_and_pad(void *dst, size_t dstlen, const void *src, size_t len, int ch)
319 {
320
321 if (len >= dstlen) {
322 memcpy(dst, src, dstlen);
323 } else {
324 memcpy(dst, src, len);
325 /* Pad with given padding character. */
326 memset((char *)dst + len, ch, dstlen - len);
327 }
328 }
329
330 #define strtomem(dst, src) do { \
331 size_t dstlen = ARRAY_SIZE(dst); \
332 size_t srclen = __builtin_object_size(src, 1); \
333 srclen = MIN(srclen, dstlen); \
334 srclen = strnlen(src, srclen); \
335 memcpy(dst, src, srclen); \
336 } while (0)
337
338 #define strtomem_pad(dst, src, pad) do { \
339 size_t dstlen = ARRAY_SIZE(dst); \
340 size_t srclen = __builtin_object_size(src, 1); \
341 srclen = MIN(srclen, dstlen); \
342 srclen = strnlen(src, srclen); \
343 memcpy_and_pad(dst, dstlen, src, srclen, pad); \
344 } while (0)
345
346 #define memset_startat(ptr, bytepat, smember) \
347 ({ \
348 uint8_t *_ptr = (uint8_t *)(ptr); \
349 int _c = (int)(bytepat); \
350 size_t _o = offsetof(typeof(*(ptr)), smember); \
351 memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
352 })
353
354 #define memset_after(ptr, bytepat, smember) \
355 ({ \
356 uint8_t *_ptr = (uint8_t *)(ptr); \
357 int _c = (int)(bytepat); \
358 size_t _o = offsetofend(typeof(*(ptr)), smember); \
359 memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
360 })
361
362 static inline void
memzero_explicit(void * p,size_t s)363 memzero_explicit(void *p, size_t s)
364 {
365 memset(p, 0, s);
366 __asm__ __volatile__("": :"r"(p) :"memory");
367 }
368
369 #endif /* _LINUXKPI_LINUX_STRING_H_ */
370