xref: /freebsd/sys/compat/linuxkpi/common/include/linux/string.h (revision 0b9434d707c71de7b1b62e400e6e780224f0384d)
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
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
196 kstrdup_const(const char *src, gfp_t gfp)
197 {
198 	return (kmemdup(src, strlen(src) + 1, gfp));
199 }
200 
201 static inline char *
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 *
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 *
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
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
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 *
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
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
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 *
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 *
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 *
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 *
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
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
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