cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

argv_split.c (2154B)


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