xref: /freebsd/sys/compat/linuxkpi/common/include/linux/string.h (revision c27779e0a9546e8b2bfde74b5c9cbf08bbed000e)
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 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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
170 kstrdup_const(const char *src, gfp_t gfp)
171 {
172 	return (kmemdup(src, strlen(src) + 1, gfp));
173 }
174 
175 static inline char *
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 *
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 *
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
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
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 *
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
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
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 *
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 *
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 *
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 *
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
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
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