Line data Source code
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 0 : for (was_space = true; *str; str++) {
17 0 : if (isspace(*str)) {
18 : was_space = true;
19 0 : } else if (was_space) {
20 : was_space = false;
21 0 : 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 0 : void argv_free(char **argv)
35 : {
36 0 : argv--;
37 0 : kfree(argv[0]);
38 0 : kfree(argv);
39 0 : }
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 0 : 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 0 : argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp);
67 0 : if (!argv_str)
68 : return NULL;
69 :
70 : argc = count_argc(argv_str);
71 0 : argv = kmalloc(sizeof(*argv) * (argc + 2), gfp);
72 0 : if (!argv) {
73 0 : kfree(argv_str);
74 0 : return NULL;
75 : }
76 :
77 0 : *argv = argv_str;
78 0 : argv_ret = ++argv;
79 0 : for (was_space = true; *argv_str; argv_str++) {
80 0 : if (isspace(*argv_str)) {
81 : was_space = true;
82 0 : *argv_str = 0;
83 0 : } else if (was_space) {
84 : was_space = false;
85 0 : *argv++ = argv_str;
86 : }
87 : }
88 0 : *argv = NULL;
89 :
90 0 : if (argcp)
91 0 : *argcp = argc;
92 0 : return argv_ret;
93 : }
94 : EXPORT_SYMBOL(argv_split);
|