[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