1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2d84d1cc7SJeremy Fitzhardinge /* 3d84d1cc7SJeremy Fitzhardinge * Helper function for splitting a string into an argv-like array. 4d84d1cc7SJeremy Fitzhardinge */ 5d84d1cc7SJeremy Fitzhardinge 6d84d1cc7SJeremy Fitzhardinge #include <linux/kernel.h> 7d84d1cc7SJeremy Fitzhardinge #include <linux/ctype.h> 8e7d2860bSAndré Goddard Rosa #include <linux/string.h> 95a56db1cSRobert P. J. Day #include <linux/slab.h> 108bc3bcc9SPaul Gortmaker #include <linux/export.h> 11d84d1cc7SJeremy Fitzhardinge 12d84d1cc7SJeremy Fitzhardinge static int count_argc(const char *str) 13d84d1cc7SJeremy Fitzhardinge { 14d84d1cc7SJeremy Fitzhardinge int count = 0; 15095d141bSOleg Nesterov bool was_space; 16d84d1cc7SJeremy Fitzhardinge 17095d141bSOleg Nesterov for (was_space = true; *str; str++) { 18095d141bSOleg Nesterov if (isspace(*str)) { 19095d141bSOleg Nesterov was_space = true; 20095d141bSOleg Nesterov } else if (was_space) { 21095d141bSOleg Nesterov was_space = false; 22d84d1cc7SJeremy Fitzhardinge count++; 23d84d1cc7SJeremy Fitzhardinge } 24d84d1cc7SJeremy Fitzhardinge } 25d84d1cc7SJeremy Fitzhardinge 26d84d1cc7SJeremy Fitzhardinge return count; 27d84d1cc7SJeremy Fitzhardinge } 28d84d1cc7SJeremy Fitzhardinge 29d84d1cc7SJeremy Fitzhardinge /** 30d84d1cc7SJeremy Fitzhardinge * argv_free - free an argv 31d84d1cc7SJeremy Fitzhardinge * @argv - the argument vector to be freed 32d84d1cc7SJeremy Fitzhardinge * 33d84d1cc7SJeremy Fitzhardinge * Frees an argv and the strings it points to. 34d84d1cc7SJeremy Fitzhardinge */ 35d84d1cc7SJeremy Fitzhardinge void argv_free(char **argv) 36d84d1cc7SJeremy Fitzhardinge { 37095d141bSOleg Nesterov argv--; 38095d141bSOleg Nesterov kfree(argv[0]); 39d84d1cc7SJeremy Fitzhardinge kfree(argv); 40d84d1cc7SJeremy Fitzhardinge } 41d84d1cc7SJeremy Fitzhardinge EXPORT_SYMBOL(argv_free); 42d84d1cc7SJeremy Fitzhardinge 43d84d1cc7SJeremy Fitzhardinge /** 44d84d1cc7SJeremy Fitzhardinge * argv_split - split a string at whitespace, returning an argv 45d84d1cc7SJeremy Fitzhardinge * @gfp: the GFP mask used to allocate memory 46d84d1cc7SJeremy Fitzhardinge * @str: the string to be split 47d84d1cc7SJeremy Fitzhardinge * @argcp: returned argument count 48d84d1cc7SJeremy Fitzhardinge * 49d84d1cc7SJeremy Fitzhardinge * Returns an array of pointers to strings which are split out from 50d84d1cc7SJeremy Fitzhardinge * @str. This is performed by strictly splitting on white-space; no 51d84d1cc7SJeremy Fitzhardinge * quote processing is performed. Multiple whitespace characters are 52d84d1cc7SJeremy Fitzhardinge * considered to be a single argument separator. The returned array 53d84d1cc7SJeremy Fitzhardinge * is always NULL-terminated. Returns NULL on memory allocation 54d84d1cc7SJeremy Fitzhardinge * failure. 55095d141bSOleg Nesterov * 56095d141bSOleg Nesterov * The source string at `str' may be undergoing concurrent alteration via 57095d141bSOleg Nesterov * userspace sysctl activity (at least). The argv_split() implementation 58095d141bSOleg Nesterov * attempts to handle this gracefully by taking a local copy to work on. 59d84d1cc7SJeremy Fitzhardinge */ 60d84d1cc7SJeremy Fitzhardinge char **argv_split(gfp_t gfp, const char *str, int *argcp) 61d84d1cc7SJeremy Fitzhardinge { 62095d141bSOleg Nesterov char *argv_str; 63095d141bSOleg Nesterov bool was_space; 64095d141bSOleg Nesterov char **argv, **argv_ret; 65095d141bSOleg Nesterov int argc; 66d84d1cc7SJeremy Fitzhardinge 67095d141bSOleg Nesterov argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp); 68095d141bSOleg Nesterov if (!argv_str) 69095d141bSOleg Nesterov return NULL; 70095d141bSOleg Nesterov 71095d141bSOleg Nesterov argc = count_argc(argv_str); 72095d141bSOleg Nesterov argv = kmalloc(sizeof(*argv) * (argc + 2), gfp); 73095d141bSOleg Nesterov if (!argv) { 74095d141bSOleg Nesterov kfree(argv_str); 75095d141bSOleg Nesterov return NULL; 76095d141bSOleg Nesterov } 77095d141bSOleg Nesterov 78095d141bSOleg Nesterov *argv = argv_str; 79095d141bSOleg Nesterov argv_ret = ++argv; 80095d141bSOleg Nesterov for (was_space = true; *argv_str; argv_str++) { 81095d141bSOleg Nesterov if (isspace(*argv_str)) { 82095d141bSOleg Nesterov was_space = true; 83095d141bSOleg Nesterov *argv_str = 0; 84095d141bSOleg Nesterov } else if (was_space) { 85095d141bSOleg Nesterov was_space = false; 86095d141bSOleg Nesterov *argv++ = argv_str; 87095d141bSOleg Nesterov } 88095d141bSOleg Nesterov } 89095d141bSOleg Nesterov *argv = NULL; 90d84d1cc7SJeremy Fitzhardinge 918e2b7056SNeil Horman if (argcp) 92d84d1cc7SJeremy Fitzhardinge *argcp = argc; 93095d141bSOleg Nesterov return argv_ret; 94d84d1cc7SJeremy Fitzhardinge } 95d84d1cc7SJeremy Fitzhardinge EXPORT_SYMBOL(argv_split); 96