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