[U-Boot] [PATCH 1/4] cmdline: Add linux command line munging tools

Doug Anderson dianders at chromium.org
Thu Oct 20 00:30:56 CEST 2011


It appears that there are a handful of places in u-boot that we want
to munge the linux command line.  This adds some helper functions that
make that easier.

Signed-off-by: Doug Anderson <dianders at chromium.org>
---
 common/Makefile   |    1 +
 common/cmdline.c  |  318 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/cmdline.h |   30 +++++
 3 files changed, 349 insertions(+), 0 deletions(-)
 create mode 100644 common/cmdline.c
 create mode 100644 include/cmdline.h

diff --git a/common/Makefile b/common/Makefile
index ae795e0..90d2ff0 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -186,6 +186,7 @@ COBJS-$(CONFIG_UPDATE_TFTP) += update.o
 COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
 endif
 
+COBJS-y += cmdline.o
 COBJS-y += console.o
 COBJS-y += memsize.o
 COBJS-y += stdio.o
diff --git a/common/cmdline.c b/common/cmdline.c
new file mode 100644
index 0000000..0862838
--- /dev/null
+++ b/common/cmdline.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Functions for munging the Linux command line */
+
+/*
+ * To run unit tests in this file:
+ *   gcc -DRUN_UNITTESTS -Wall -Werror common/cmdline.c -o cmdline && ./cmdline
+ */
+#ifdef RUN_UNITTESTS
+
+#define CONFIG_SILENT_CONSOLE
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#else
+
+#include <common.h>
+#include <malloc.h>
+
+#include <cmdline.h>
+
+#include <linux/ctype.h>
+
+#endif
+
+
+/**
+ * Modify the command line to remove a parameter.
+ *
+ * This can either remove standalone parameters or ones with arguments.  For
+ * instance you can remove the param "console=/dev/ttyS0" by passing in
+ * "console" and you can remove the param "earlyprintk" by passing in
+ * "earlyprintk".
+ *
+ * WARNING:
+ * - The current code doesn't handle removing parameters with spaces in
+ *   them.  Specifically, you can't use it to remove xyz if you have
+ *   something like xyz="abc def".
+ *
+ * Notes:
+ * - It is _not_ considered an error to remove a parameter that doesn't exist.
+ * - If the parameter exists more than once, this just removes the first.
+ *   You can loop to get them all.
+ * - The parameter must match exactly.  AKA "onsole" doesn't match "console".
+ *
+ * @param cmdline	The command line to modify.
+ * @param param_name	The name of the parameter to remove.
+ * @return 1 if the param was removed; 0 otherwise.
+ */
+int remove_cmdline_param(char *cmdline, const char *param_name)
+{
+	char *start;
+	char *end;
+	int param_name_len = strlen(param_name);
+
+	assert(param_name_len != 0);
+
+	/*
+	 * Try to find the param; if we find it, start will point to the
+	 * beginning of the param and end to the character after the param
+	 * (could be '\0', '=', or ' ').  If we fail, we return 0 in the loop.
+	 */
+	start = cmdline;
+	while (1) {
+		start = strstr(start, param_name);
+		if (!start)
+			return 0;
+		end = start + param_name_len;
+
+		/*
+		 * Loop break condition is space (or nothing) before param and
+		 * space or equals (or nothing) after param.
+		 */
+		if (((start == cmdline) || isspace(start[-1])) &&
+		    ((*end == '\0') || (*end == '=') || isspace(*end)))
+			break;
+
+		start = end;
+	}
+
+	/*
+	 * Skip so end points to the start of the next param; note that we don't
+	 * handle quoting here (!), so we'll get confused with abc="def ghi"
+	 */
+	while ((*end != '\0') && !isspace(*end))
+		end++;
+	while (isspace(*end))
+		end++;
+
+	/*
+	 * Move start backwards to clean up any extra spaces.  After this runs,
+	 * start will point to the place to move end onto.
+	 */
+	if (start != cmdline) {
+		start--;
+		while ((start != cmdline) && isspace(*start))
+			start--;
+
+		/*
+		 * Two cases:
+		 * - nothing at end: move fwd one char so we don't clobber the
+		 *   last char of the previous cmd.
+		 * - more stuff at end: add exactly one ' ' to separate the
+		 *   chunks.
+		 */
+		start++;
+		if (*end != '\0') {
+			*start = ' ';
+			start++;
+		}
+	}
+
+	/* Kill the parameter */
+	memmove(start, end, strlen(end)+1);
+
+	return 1;
+}
+
+/**
+ * Add a parameter to the command line.
+ *
+ * This is much like a glorified strncat(), but handles adding a space between
+ * the old cmdline and the new one if needed and takes the whole bufsize
+ * instead of the number of characters to copy.
+ *
+ * @param cmdline	The command line to modify.
+ * @param toappend	The parameter to append, like "console=/dev/ttyS0".
+ * @param bufsize	The number of bytes that were allocated to cmdline, so
+ *			we know not to overrun.
+ */
+void add_cmdline_param(char *cmdline, const char *toappend, int bufsize)
+{
+	int cmdline_len = strlen(cmdline);
+
+	if (cmdline_len == 0)
+		strncat(cmdline, toappend, bufsize-1);
+	else {
+		int bytes_avail = bufsize - cmdline_len;
+
+		if (bytes_avail <= 0) {
+			assert(bytes_avail == 0);
+			return;
+		}
+		cmdline[bufsize-1] = '\0';
+		cmdline[cmdline_len] = ' ';
+		strncpy(&cmdline[cmdline_len+1], toappend,
+			bytes_avail-2);
+	}
+}
+
+
+#ifdef RUN_UNITTESTS
+
+/**
+ * Unit tests for remove_cmdline_param().
+ */
+void remove_cmdline_param_unittest(void)
+{
+	char *original_str;
+	char *expected_str;
+	char *result;
+	int retval;
+
+	/* Try removing each bit of a reasonable sample */
+	original_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "console");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	original_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "console=ttyS0,115200n8 rootwait ro";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "root");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	original_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 ro";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "rootwait");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	original_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "ro");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	/* Remove something that's not there */
+	original_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "console=ttyS0,115200n8 root=/dev/mmcblk0p3 rootwait ro";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "oogabooga");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 0);
+	free(result);
+
+	/* Remove from a NULL string */
+	original_str = "";
+	expected_str = "";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "oogabooga");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 0);
+	free(result);
+
+	/* Remove with an '=' based param at the end */
+	original_str = "root=/dev/mmcblk0p3 rootwait ro console=ttyS0,115200n8";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "console");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	/* Remove with a non-'=' based param at the beginning */
+	original_str = "ro root=/dev/mmcblk0p3 rootwait console=ttyS0,115200n8";
+	expected_str = "root=/dev/mmcblk0p3 rootwait console=ttyS0,115200n8";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "ro");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	/* Add a few extra spaces and see how it deals with it */
+	original_str = "console=ttyS0,115200n8\t  root=/dev/mmcblk0p3 \tro";
+	expected_str = "console=ttyS0,115200n8 ro";
+	result = strdup(original_str);
+	retval = remove_cmdline_param(result, "root");
+	assert(strcmp(result, expected_str) == 0);
+	assert(retval == 1);
+	free(result);
+
+	printf("remove_cmdline_param_unittest: pass\n");
+}
+
+/**
+ * Unit tests for add_cmdline_param().
+ */
+void add_cmdline_param_unittest(void)
+{
+	char *original_str;
+	char *expected_str;
+	char *result;
+	int extra_chars = strlen(" console=");
+	int bufsize;
+
+	/* Simple case first; try adding "console=" */
+	original_str = "root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro console=";
+	bufsize = strlen(original_str) + 1 + extra_chars;
+	result = malloc(bufsize);
+	strcpy(result, original_str);
+	add_cmdline_param(result, "console=", bufsize);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	/* Add to an empty string; should see no ' ' before... */
+	original_str = "";
+	expected_str = "console=";
+	bufsize = strlen(original_str) + 1 + extra_chars - 1;
+	result = malloc(bufsize);
+	strcpy(result, original_str);
+	add_cmdline_param(result, "console=", bufsize);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	/* Shrink down bufsize and see loss of = */
+	original_str = "root=/dev/mmcblk0p3 rootwait ro";
+	expected_str = "root=/dev/mmcblk0p3 rootwait ro console";
+	bufsize = strlen(original_str) + 1 + extra_chars - 1;
+	result = malloc(bufsize);
+	strcpy(result, original_str);
+	add_cmdline_param(result, "console=", bufsize);
+	assert(strcmp(result, expected_str) == 0);
+	free(result);
+
+	printf("add_cmdline_param_unittest: pass\n");
+}
+
+int main(int argc, char **argv)
+{
+	remove_cmdline_param_unittest();
+	add_cmdline_param_unittest();
+	return 0;
+}
+#endif
diff --git a/include/cmdline.h b/include/cmdline.h
new file mode 100644
index 0000000..65b415c
--- /dev/null
+++ b/include/cmdline.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Functions for munging the Linux command line */
+
+#ifndef _CMDLINE_H_
+#define _CMDLINE_H_
+
+int remove_cmdline_param(char *cmdline, const char *param_name);
+void add_cmdline_param(char *cmdline, const char *toappend, int bufsize);
+
+#endif /*_CMDLINE_H_ */
-- 
1.7.3.1



More information about the U-Boot mailing list