linux/lib/argv_split.c
<<
>>
Prefs
   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);
  96