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 0 : static int count_argc(const char *str) 13 : { 14 0 : int count = 0; 15 0 : 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 0 : 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 0 : char *argv_str; 63 0 : bool was_space; 64 0 : char **argv, **argv_ret; 65 0 : int argc; 66 : 67 0 : argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp); 68 0 : if (!argv_str) 69 : return NULL; 70 : 71 0 : 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 0 : was_space = true; 83 0 : *argv_str = 0; 84 0 : } else if (was_space) { 85 0 : was_space = false; 86 0 : *argv++ = argv_str; 87 : } 88 : } 89 0 : *argv = NULL; 90 : 91 0 : if (argcp) 92 0 : *argcp = argc; 93 : return argv_ret; 94 : } 95 : EXPORT_SYMBOL(argv_split);