Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Helper function for splitting a string into an argv-like array.
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/ctype.h>
0008 #include <linux/string.h>
0009 #include <linux/slab.h>
0010 #include <linux/export.h>
0011 
0012 static int count_argc(const char *str)
0013 {
0014     int count = 0;
0015     bool was_space;
0016 
0017     for (was_space = true; *str; str++) {
0018         if (isspace(*str)) {
0019             was_space = true;
0020         } else if (was_space) {
0021             was_space = false;
0022             count++;
0023         }
0024     }
0025 
0026     return count;
0027 }
0028 
0029 /**
0030  * argv_free - free an argv
0031  * @argv - the argument vector to be freed
0032  *
0033  * Frees an argv and the strings it points to.
0034  */
0035 void argv_free(char **argv)
0036 {
0037     argv--;
0038     kfree(argv[0]);
0039     kfree(argv);
0040 }
0041 EXPORT_SYMBOL(argv_free);
0042 
0043 /**
0044  * argv_split - split a string at whitespace, returning an argv
0045  * @gfp: the GFP mask used to allocate memory
0046  * @str: the string to be split
0047  * @argcp: returned argument count
0048  *
0049  * Returns an array of pointers to strings which are split out from
0050  * @str.  This is performed by strictly splitting on white-space; no
0051  * quote processing is performed.  Multiple whitespace characters are
0052  * considered to be a single argument separator.  The returned array
0053  * is always NULL-terminated.  Returns NULL on memory allocation
0054  * failure.
0055  *
0056  * The source string at `str' may be undergoing concurrent alteration via
0057  * userspace sysctl activity (at least).  The argv_split() implementation
0058  * attempts to handle this gracefully by taking a local copy to work on.
0059  */
0060 char **argv_split(gfp_t gfp, const char *str, int *argcp)
0061 {
0062     char *argv_str;
0063     bool was_space;
0064     char **argv, **argv_ret;
0065     int argc;
0066 
0067     argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp);
0068     if (!argv_str)
0069         return NULL;
0070 
0071     argc = count_argc(argv_str);
0072     argv = kmalloc_array(argc + 2, sizeof(*argv), gfp);
0073     if (!argv) {
0074         kfree(argv_str);
0075         return NULL;
0076     }
0077 
0078     *argv = argv_str;
0079     argv_ret = ++argv;
0080     for (was_space = true; *argv_str; argv_str++) {
0081         if (isspace(*argv_str)) {
0082             was_space = true;
0083             *argv_str = 0;
0084         } else if (was_space) {
0085             was_space = false;
0086             *argv++ = argv_str;
0087         }
0088     }
0089     *argv = NULL;
0090 
0091     if (argcp)
0092         *argcp = argc;
0093     return argv_ret;
0094 }
0095 EXPORT_SYMBOL(argv_split);