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