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