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