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