Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * Helper function for splitting a string into an argv-like array. 4 : : */ 5 : : 6 : : #include <linux/kernel.h> 7 : : #include <linux/ctype.h> 8 : : #include <linux/string.h> 9 : : #include <linux/slab.h> 10 : : #include <linux/export.h> 11 : : 12 : : static int count_argc(const char *str) 13 : : { 14 : : int count = 0; 15 : : bool was_space; 16 : : 17 : 0 : for (was_space = true; *str; str++) { 18 : 0 : if (isspace(*str)) { 19 : : was_space = true; 20 : 0 : } else if (was_space) { 21 : : was_space = false; 22 : 0 : count++; 23 : : } 24 : : } 25 : : 26 : 0 : return count; 27 : : } 28 : : 29 : : /** 30 : : * argv_free - free an argv 31 : : * @argv - the argument vector to be freed 32 : : * 33 : : * Frees an argv and the strings it points to. 34 : : */ 35 : 0 : void argv_free(char **argv) 36 : : { 37 : 0 : argv--; 38 : 0 : kfree(argv[0]); 39 : 0 : kfree(argv); 40 : 0 : } 41 : : EXPORT_SYMBOL(argv_free); 42 : : 43 : : /** 44 : : * argv_split - split a string at whitespace, returning an argv 45 : : * @gfp: the GFP mask used to allocate memory 46 : : * @str: the string to be split 47 : : * @argcp: returned argument count 48 : : * 49 : : * Returns an array of pointers to strings which are split out from 50 : : * @str. This is performed by strictly splitting on white-space; no 51 : : * quote processing is performed. Multiple whitespace characters are 52 : : * considered to be a single argument separator. The returned array 53 : : * is always NULL-terminated. Returns NULL on memory allocation 54 : : * failure. 55 : : * 56 : : * The source string at `str' may be undergoing concurrent alteration via 57 : : * userspace sysctl activity (at least). The argv_split() implementation 58 : : * attempts to handle this gracefully by taking a local copy to work on. 59 : : */ 60 : 0 : char **argv_split(gfp_t gfp, const char *str, int *argcp) 61 : : { 62 : : char *argv_str; 63 : : bool was_space; 64 : : char **argv, **argv_ret; 65 : : int argc; 66 : : 67 : 0 : argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp); 68 : 0 : if (!argv_str) 69 : : return NULL; 70 : : 71 : : argc = count_argc(argv_str); 72 : 0 : argv = kmalloc_array(argc + 2, sizeof(*argv), gfp); 73 : 0 : if (!argv) { 74 : 0 : kfree(argv_str); 75 : 0 : return NULL; 76 : : } 77 : : 78 : 0 : *argv = argv_str; 79 : 0 : argv_ret = ++argv; 80 : 0 : for (was_space = true; *argv_str; argv_str++) { 81 : 0 : if (isspace(*argv_str)) { 82 : : was_space = true; 83 : 0 : *argv_str = 0; 84 : 0 : } else if (was_space) { 85 : : was_space = false; 86 : 0 : *argv++ = argv_str; 87 : : } 88 : : } 89 : 0 : *argv = NULL; 90 : : 91 : 0 : if (argcp) 92 : 0 : *argcp = argc; 93 : 0 : return argv_ret; 94 : : } 95 : : EXPORT_SYMBOL(argv_split);