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 <diand...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to