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/args.h>
35 #include <linux/array_size.h>
36 #include <linux/types.h>
37 #include <linux/gfp.h>
38 #include <linux/slab.h>
39 #include <linux/uaccess.h>
40 #include <linux/err.h>
41 #include <linux/bitops.h> /* for BITS_PER_LONG */
42 #include <linux/overflow.h>
43 #include <linux/stdarg.h>
44
45 #include <sys/libkern.h>
46
47 #define strnicmp(...) strncasecmp(__VA_ARGS__)
48
49 static inline int
match_string(const char * const * table,int n,const char * key)50 match_string(const char *const *table, int n, const char *key)
51 {
52 int i;
53
54 for (i = 0; i != n && table[i] != NULL; i++) {
55 if (strcmp(table[i], key) == 0)
56 return (i);
57 }
58 return (-EINVAL);
59 }
60
61 static inline void *
memdup_user(const void * ptr,size_t len)62 memdup_user(const void *ptr, size_t len)
63 {
64 void *retval;
65 int error;
66
67 retval = malloc(len, M_KMALLOC, M_WAITOK);
68 error = linux_copyin(ptr, retval, len);
69 if (error != 0) {
70 free(retval, M_KMALLOC);
71 return (ERR_PTR(error));
72 }
73 return (retval);
74 }
75
76 static inline void *
vmemdup_user(const void * ptr,size_t len)77 vmemdup_user(const void *ptr, size_t len)
78 {
79 void *retval;
80 int error;
81
82 retval = malloc(len, M_KMALLOC, M_WAITOK);
83 error = linux_copyin(ptr, retval, len);
84 if (error != 0) {
85 free(retval, M_KMALLOC);
86 return (ERR_PTR(error));
87 }
88 return (retval);
89 }
90
91 static inline void *
memdup_user_nul(const void * ptr,size_t len)92 memdup_user_nul(const void *ptr, size_t len)
93 {
94 char *retval;
95 int error;
96
97 retval = malloc(len + 1, M_KMALLOC, M_WAITOK);
98 error = linux_copyin(ptr, retval, len);
99 if (error != 0) {
100 free(retval, M_KMALLOC);
101 return (ERR_PTR(error));
102 }
103 retval[len] = '\0';
104 return (retval);
105 }
106
107 static inline void *
memdup_array_user(const void * src,size_t n,size_t size)108 memdup_array_user(const void *src, size_t n, size_t size)
109 {
110 size_t len;
111
112 if (check_mul_overflow(n, size, &len))
113 return (ERR_PTR(-EOVERFLOW));
114
115 return (memdup_user(src, len));
116 }
117
118 static inline void *
vmemdup_array_user(const void * src,size_t n,size_t size)119 vmemdup_array_user(const void *src, size_t n, size_t size)
120 {
121 size_t len;
122
123 if (check_mul_overflow(n, size, &len))
124 return (ERR_PTR(-EOVERFLOW));
125
126 return (vmemdup_user(src, len));
127 }
128
129 static inline void *
kmemdup(const void * src,size_t len,gfp_t gfp)130 kmemdup(const void *src, size_t len, gfp_t gfp)
131 {
132 void *dst;
133
134 dst = kmalloc(len, gfp);
135 if (dst != NULL)
136 memcpy(dst, src, len);
137 return (dst);
138 }
139
140 static inline void *
kmemdup_array(const void * src,size_t count,size_t element_size,gfp_t gfp)141 kmemdup_array(const void *src, size_t count, size_t element_size, gfp_t gfp)
142 {
143 return (kmemdup(src, size_mul(count, element_size), gfp));
144 }
145
146 /* See slab.h for kvmalloc/kvfree(). */
147 static inline void *
kvmemdup(const void * src,size_t len,gfp_t gfp)148 kvmemdup(const void *src, size_t len, gfp_t gfp)
149 {
150 void *dst;
151
152 dst = kvmalloc(len, gfp);
153 if (dst != NULL)
154 memcpy(dst, src, len);
155 return (dst);
156 }
157
158 static inline char *
strndup_user(const char __user * ustr,long n)159 strndup_user(const char __user *ustr, long n)
160 {
161 if (n < 1)
162 return (ERR_PTR(-EINVAL));
163
164 return (memdup_user_nul(ustr, n - 1));
165 }
166
167 static inline char *
kstrdup(const char * string,gfp_t gfp)168 kstrdup(const char *string, gfp_t gfp)
169 {
170 char *retval;
171 size_t len;
172
173 if (string == NULL)
174 return (NULL);
175 len = strlen(string) + 1;
176 retval = kmalloc(len, gfp);
177 if (retval != NULL)
178 memcpy(retval, string, len);
179 return (retval);
180 }
181
182 static inline char *
kstrndup(const char * string,size_t len,gfp_t gfp)183 kstrndup(const char *string, size_t len, gfp_t gfp)
184 {
185 char *retval;
186
187 if (string == NULL)
188 return (NULL);
189 retval = kmalloc(len + 1, gfp);
190 if (retval != NULL)
191 strncpy(retval, string, len);
192 return (retval);
193 }
194
195 static inline const char *
kstrdup_const(const char * src,gfp_t gfp)196 kstrdup_const(const char *src, gfp_t gfp)
197 {
198 return (kmemdup(src, strlen(src) + 1, gfp));
199 }
200
201 static inline char *
skip_spaces(const char * str)202 skip_spaces(const char *str)
203 {
204 while (isspace(*str))
205 ++str;
206 return (__DECONST(char *, str));
207 }
208
209 /*
210 * This function trims whitespaces at the end of a string and returns a pointer
211 * to the first non-whitespace character.
212 */
213 static inline char *
strim(char * str)214 strim(char *str)
215 {
216 char *end;
217
218 end = str + strlen(str);
219 while (end >= str && (*end == '\0' || isspace(*end))) {
220 *end = '\0';
221 end--;
222 }
223
224 return (skip_spaces(str));
225 }
226
227 static inline void *
memchr_inv(const void * start,int c,size_t length)228 memchr_inv(const void *start, int c, size_t length)
229 {
230 const u8 *ptr;
231 const u8 *end;
232 u8 ch;
233
234 ch = c;
235 ptr = start;
236 end = ptr + length;
237
238 while (ptr != end) {
239 if (*ptr != ch)
240 return (__DECONST(void *, ptr));
241 ptr++;
242 }
243 return (NULL);
244 }
245
246 static inline bool
mem_is_zero(const void * start,size_t length)247 mem_is_zero(const void *start, size_t length)
248 {
249 return (memchr_inv(start, 0, length) == NULL);
250 }
251
252 static inline size_t
str_has_prefix(const char * str,const char * prefix)253 str_has_prefix(const char *str, const char *prefix)
254 {
255 size_t len;
256
257 len = strlen(prefix);
258 return (strncmp(str, prefix, len) == 0 ? len : 0);
259 }
260
261 static inline char *
strreplace(char * str,char old,char new)262 strreplace(char *str, char old, char new)
263 {
264 char *p;
265
266 p = strchrnul(str, old);
267 while (p != NULL && *p != '\0') {
268 *p = new;
269 p = strchrnul(str, old);
270 }
271 return (p);
272 }
273
274 static inline ssize_t
sized_strscpy(char * dst,const char * src,size_t len)275 sized_strscpy(char* dst, const char* src, size_t len)
276 {
277 size_t i;
278
279 if (len <= INT_MAX) {
280 for (i = 0; i < len; i++)
281 if ('\0' == (dst[i] = src[i]))
282 return ((ssize_t)i);
283 if (i != 0)
284 dst[--i] = '\0';
285 }
286
287 return (-E2BIG);
288 }
289
290 #define __strscpy0(dst, src, ...) sized_strscpy(dst, src, sizeof(dst))
291 #define __strscpy1(dst, src, len) sized_strscpy(dst, src, len)
292 #define strscpy(dst, src, ...) \
293 CONCATENATE(__strscpy, COUNT_ARGS(__VA_ARGS__))(dst, src, __VA_ARGS__)
294
295 static inline ssize_t
sized_strscpy_pad(char * dst,const char * src,size_t len)296 sized_strscpy_pad(char* dst, const char* src, size_t len)
297 {
298
299 bzero(dst, len);
300
301 return (strscpy(dst, src, len));
302 }
303
304 #define __strscpy_pad0(dst, src, ...) sized_strscpy_pad(dst, src, sizeof(dst))
305 #define __strscpy_pad1(dst, src, len) sized_strscpy_pad(dst, src, len)
306 #define strscpy_pad(dst, src, ...) \
307 CONCATENATE(__strscpy_pad, COUNT_ARGS(__VA_ARGS__))(dst, src, __VA_ARGS__)
308
309 static inline char *
strnchr(const char * cp,size_t n,int ch)310 strnchr(const char *cp, size_t n, int ch)
311 {
312 char *p;
313
314 for (p = __DECONST(char *, cp); n--; ++p) {
315 if (*p == ch)
316 return (p);
317 if (*p == '\0')
318 break;
319 }
320
321 return (NULL);
322 }
323
324 static inline void *
memset32(uint32_t * b,uint32_t c,size_t len)325 memset32(uint32_t *b, uint32_t c, size_t len)
326 {
327 uint32_t *dst = b;
328
329 while (len--)
330 *dst++ = c;
331 return (b);
332 }
333
334 static inline void *
memset64(uint64_t * b,uint64_t c,size_t len)335 memset64(uint64_t *b, uint64_t c, size_t len)
336 {
337 uint64_t *dst = b;
338
339 while (len--)
340 *dst++ = c;
341 return (b);
342 }
343
344 static inline void *
memset_p(void ** p,void * v,size_t n)345 memset_p(void **p, void *v, size_t n)
346 {
347
348 if (BITS_PER_LONG == 32)
349 return (memset32((uint32_t *)p, (uintptr_t)v, n));
350 else
351 return (memset64((uint64_t *)p, (uintptr_t)v, n));
352 }
353
354 static inline void
memcpy_and_pad(void * dst,size_t dstlen,const void * src,size_t len,int ch)355 memcpy_and_pad(void *dst, size_t dstlen, const void *src, size_t len, int ch)
356 {
357
358 if (len >= dstlen) {
359 memcpy(dst, src, dstlen);
360 } else {
361 memcpy(dst, src, len);
362 /* Pad with given padding character. */
363 memset((char *)dst + len, ch, dstlen - len);
364 }
365 }
366
367 #define strtomem(dst, src) do { \
368 size_t dstlen = ARRAY_SIZE(dst); \
369 size_t srclen = __builtin_object_size(src, 1); \
370 srclen = MIN(srclen, dstlen); \
371 srclen = strnlen(src, srclen); \
372 memcpy(dst, src, srclen); \
373 } while (0)
374
375 #define strtomem_pad(dst, src, pad) do { \
376 size_t dstlen = ARRAY_SIZE(dst); \
377 size_t srclen = __builtin_object_size(src, 1); \
378 srclen = MIN(srclen, dstlen); \
379 srclen = strnlen(src, srclen); \
380 memcpy_and_pad(dst, dstlen, src, srclen, pad); \
381 } while (0)
382
383 #define memset_startat(ptr, bytepat, smember) \
384 ({ \
385 uint8_t *_ptr = (uint8_t *)(ptr); \
386 int _c = (int)(bytepat); \
387 size_t _o = offsetof(typeof(*(ptr)), smember); \
388 memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
389 })
390
391 #define memset_after(ptr, bytepat, smember) \
392 ({ \
393 uint8_t *_ptr = (uint8_t *)(ptr); \
394 int _c = (int)(bytepat); \
395 size_t _o = offsetofend(typeof(*(ptr)), smember); \
396 memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
397 })
398
399 static inline void
memzero_explicit(void * p,size_t s)400 memzero_explicit(void *p, size_t s)
401 {
402 memset(p, 0, s);
403 __asm__ __volatile__("": :"r"(p) :"memory");
404 }
405
406 #endif /* _LINUXKPI_LINUX_STRING_H_ */
407