summaryrefslogtreecommitdiffstats
path: root/lib/argv_split.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-09-05 11:59:05 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-09-05 11:59:05 -0700
commit9f0346dcbea363787186c94ef94dd01aaa215afa (patch)
treeb81c168f4d0dbe4c7f4750f4598d48a6deb72094 /lib/argv_split.c
downloadlinux-stable-9f0346dcbea363787186c94ef94dd01aaa215afa.tar.gz
linux-stable-9f0346dcbea363787186c94ef94dd01aaa215afa.zip
Merge tag 'driver-core-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-coregrafted
Pull driver core fixes from Danilo Krummrich: - Fix kernfs listxattr() not returning security xattr names (e.g. SELinux labels) when the kernfs node has no allocated kernfs_iattrs - Fix silent truncation of IRQ vector indices in the Rust PCI abstractions - Don't select OF from DRIVER_PE_KUNIT_TEST; skip the test when OF is disabled instead of silently enabling extra kernel functionality - Russ Weight is retiring from kernel development; update the Firmware Loader sysfs contact to the driver-core mailing list, add a CREDITS entry for Firmware Upload, and update MAINTAINERS accordingly * tag 'driver-core-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: MAINTAINERS: Remove Russ Weight from Firmware Loader CREDITS: Add CREDITS entry for Firmware Upload firmware_loader: Change contact for sysfs nodes rust: pci: reject IRQ vector indices that do not fit in u32 kernfs: preserve security xattrs without allocating iattrs drivers: base: test: DRIVER_PE_KUNIT_TEST should not select OF
Diffstat (limited to 'lib/argv_split.c')
-rw-r--r--lib/argv_split.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/lib/argv_split.c b/lib/argv_split.c
new file mode 100644
index 000000000..e28db8e3b
--- /dev/null
+++ b/lib/argv_split.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Helper function for splitting a string into an argv-like array.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+static int count_argc(const char *str)
+{
+ int count = 0;
+ bool was_space;
+
+ for (was_space = true; *str; str++) {
+ if (isspace(*str)) {
+ was_space = true;
+ } else if (was_space) {
+ was_space = false;
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv: the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+ argv--;
+ kfree(argv[0]);
+ kfree(argv);
+}
+EXPORT_SYMBOL(argv_free);
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @gfp: the GFP mask used to allocate memory
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns: an array of pointers to strings which are split out from
+ * @str. This is performed by strictly splitting on white-space; no
+ * quote processing is performed. Multiple whitespace characters are
+ * considered to be a single argument separator. The returned array
+ * is always NULL-terminated. Returns NULL on memory allocation
+ * failure.
+ *
+ * The source string at `str' may be undergoing concurrent alteration via
+ * userspace sysctl activity (at least). The argv_split() implementation
+ * attempts to handle this gracefully by taking a local copy to work on.
+ */
+char **argv_split(gfp_t gfp, const char *str, int *argcp)
+{
+ char *argv_str;
+ bool was_space;
+ char **argv, **argv_ret;
+ int argc;
+
+ argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp);
+ if (!argv_str)
+ return NULL;
+
+ argc = count_argc(argv_str);
+ argv = kmalloc_array(argc + 2, sizeof(*argv), gfp);
+ if (!argv) {
+ kfree(argv_str);
+ return NULL;
+ }
+
+ *argv = argv_str;
+ argv_ret = ++argv;
+ for (was_space = true; *argv_str; argv_str++) {
+ if (isspace(*argv_str)) {
+ was_space = true;
+ *argv_str = 0;
+ } else if (was_space) {
+ was_space = false;
+ *argv++ = argv_str;
+ }
+ }
+ *argv = NULL;
+
+ if (argcp)
+ *argcp = argc;
+ return argv_ret;
+}
+EXPORT_SYMBOL(argv_split);