// SPDX-License-Identifier: GPL-2.01/*2* Helper function for splitting a string into an argv-like array.3*/45#include <linux/kernel.h>6#include <linux/ctype.h>7#include <linux/string.h>8#include <linux/slab.h>9#include <linux/export.h>1011static int count_argc(const char *str)12{13int count = 0;14bool was_space;1516for (was_space = true; *str; str++) {17if (isspace(*str)) {18was_space = true;19} else if (was_space) {20was_space = false;21count++;22}23}2425return count;26}2728/**29* argv_free - free an argv30* @argv: the argument vector to be freed31*32* Frees an argv and the strings it points to.33*/34void argv_free(char **argv)35{36argv--;37kfree(argv[0]);38kfree(argv);39}40EXPORT_SYMBOL(argv_free);4142/**43* argv_split - split a string at whitespace, returning an argv44* @gfp: the GFP mask used to allocate memory45* @str: the string to be split46* @argcp: returned argument count47*48* Returns: an array of pointers to strings which are split out from49* @str. This is performed by strictly splitting on white-space; no50* quote processing is performed. Multiple whitespace characters are51* considered to be a single argument separator. The returned array52* is always NULL-terminated. Returns NULL on memory allocation53* failure.54*55* The source string at `str' may be undergoing concurrent alteration via56* userspace sysctl activity (at least). The argv_split() implementation57* attempts to handle this gracefully by taking a local copy to work on.58*/59char **argv_split(gfp_t gfp, const char *str, int *argcp)60{61char *argv_str;62bool was_space;63char **argv, **argv_ret;64int argc;6566argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp);67if (!argv_str)68return NULL;6970argc = count_argc(argv_str);71argv = kmalloc_array(argc + 2, sizeof(*argv), gfp);72if (!argv) {73kfree(argv_str);74return NULL;75}7677*argv = argv_str;78argv_ret = ++argv;79for (was_space = true; *argv_str; argv_str++) {80if (isspace(*argv_str)) {81was_space = true;82*argv_str = 0;83} else if (was_space) {84was_space = false;85*argv++ = argv_str;86}87}88*argv = NULL;8990if (argcp)91*argcp = argc;92return argv_ret;93}94EXPORT_SYMBOL(argv_split);959697