diff mbox

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

Message ID 1319063459-4804-2-git-send-email-dianders@chromium.org
State Rejected
Headers show

Commit Message

Doug Anderson Oct. 19, 2011, 10:30 p.m. UTC
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@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

Comments

Mike Frysinger Oct. 19, 2011, 10:46 p.m. UTC | #1
On Wednesday 19 October 2011 18:30:56 Doug Anderson wrote:
> --- /dev/null
> +++ b/common/cmdline.c
>
> +/*
> + * To run unit tests in this file:
> + *   gcc -DRUN_UNITTESTS -Wall -Werror common/cmdline.c -o cmdline &&
> ./cmdline
> + */
> +#ifdef RUN_UNITTESTS

i'm not sure this part should be merged ... better to keep on the back burner 
while Simon sorts out testing framework with new sandbox arch.

> +void add_cmdline_param(char *cmdline, const char *toappend, int bufsize)

bufsize should be size_t

> +{
> +	int cmdline_len = strlen(cmdline);

cmdline_len should be size_t

> +	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);
> +	}

hmm, i feel like this should be simpler and not need that branch

	if (cmdline_len)
		cmdline[cmdline_len++] = ' ';
	if (bufsize <= cmdline_len)
		return;
	memcpy(&cmdline[cmdline_len], toappend, bufsize - cmdline_len - 1);
	cmdline[bufsize] = '\0';
-mike
Mike Frysinger Oct. 19, 2011, 10:52 p.m. UTC | #2
On Wednesday 19 October 2011 18:30:56 Doug Anderson wrote:
> --- /dev/null
> +++ b/include/cmdline.h
>
> +int remove_cmdline_param(char *cmdline, const char *param_name);
> +void add_cmdline_param(char *cmdline, const char *toappend, int bufsize);

i'm not particularly enamored with this naming style.  i find the style of 
"<section>_<operation>" to be easier on the eyes rather than this RPN.

i.e. cmdline_param_remove() and cmdline_param_add()
-mike
Doug Anderson Oct. 20, 2011, 1:07 a.m. UTC | #3
On Wed, Oct 19, 2011 at 3:52 PM, Mike Frysinger <vapier@gentoo.org> wrote:

> i'm not particularly enamored with this naming style.  i find the style of
> "<section>_<operation>" to be easier on the eyes rather than this RPN.
>
> i.e. cmdline_param_remove() and cmdline_param_add()
>

I'm happy to name it whatever you'd like.  My next patch will use your
naming suggestion unless someone says otherwise.

I will note, however, that the "verb_noun" style of naming appears to be
favored by the Linux kernel.  In the section of "Naming" in <
http://www.kernel.org/doc/Documentation/CodingStyle>, a suggested name is
"count_active_users()", not "active_users_count()".

-Doug
Doug Anderson Oct. 20, 2011, 1:23 a.m. UTC | #4
On Wed, Oct 19, 2011 at 3:46 PM, Mike Frysinger <vapier@gentoo.org> wrote:

> On Wednesday 19 October 2011 18:30:56 Doug Anderson wrote:
> > --- /dev/null
> > +++ b/common/cmdline.c
> >
> > +/*
> > + * To run unit tests in this file:
> > + *   gcc -DRUN_UNITTESTS -Wall -Werror common/cmdline.c -o cmdline &&
> > ./cmdline
> > + */
> > +#ifdef RUN_UNITTESTS
>
> i'm not sure this part should be merged ... better to keep on the back
> burner
> while Simon sorts out testing framework with new sandbox arch.


Fair enough.  I will take out for the next version.


> bufsize should be size_t
> cmdline_len should be size_t
>

Will do in all cases.  Thanks for catching!


> hmm, i feel like this should be simpler and not need that branch
>
>        if (cmdline_len)
>                cmdline[cmdline_len++] = ' ';
>        if (bufsize <= cmdline_len)
>                return;
>        memcpy(&cmdline[cmdline_len], toappend, bufsize - cmdline_len - 1);
>        cmdline[bufsize] = '\0';
>

There is one case that this doesn't catch I think: where cmdline_len was
exactly the same size as the original string (so we shouldn't append
anything).

...but then, as I look at this, I realize that I somehow sent you 1 rev back
of my patch.  Aack!  I will resend a new one tomorrow morning.


Thanks!

-Doug
Mike Frysinger Oct. 20, 2011, 1:37 a.m. UTC | #5
On Wednesday 19 October 2011 21:07:11 Doug Anderson wrote:
> On Wed, Oct 19, 2011 at 3:52 PM, Mike Frysinger <vapier@gentoo.org> wrote:
> > i'm not particularly enamored with this naming style.  i find the style
> > of "<section>_<operation>" to be easier on the eyes rather than this
> > RPN.
> > 
> > i.e. cmdline_param_remove() and cmdline_param_add()
> 
> I'm happy to name it whatever you'd like.  My next patch will use your
> naming suggestion unless someone says otherwise.
> 
> I will note, however, that the "verb_noun" style of naming appears to be
> favored by the Linux kernel.  In the section of "Naming" in <
> http://www.kernel.org/doc/Documentation/CodingStyle>, a suggested name is
> "count_active_users()", not "active_users_count()".

to be fair, that file says:
	... you should call that "count_active_users()" or similar, you should
	_not_ call it "cntusr()".
it doesn't seem to take a position on the "verb_noun" vs "noun_verb" style. 

in my experience, the common string tends to be more used at the start rather 
than the end (spinlocks, mutexes, interrupts, gpios, spi, i2c).  but i've 
certainly not done a comprehensive survey to back up my position :).
-mike
Wolfgang Denk Oct. 20, 2011, 2:36 p.m. UTC | #6
Dear Doug Anderson,

In message <1319063459-4804-2-git-send-email-dianders@chromium.org> you wrote:
> 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@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

Sorry, but could you please explain why anybody would need this?

Instead of adding tons of code to process one environment variable
that happens to be passed to Linux, but otherwise is not different
form any of the other variables, you can as well just use plain simple
shell scripting capabilities to build your Linux command line from
pieces.  This is way more flexible and much less resource consuming.

Unless you have a really good explanation why such coude is needed I
tend to NAK it.

Best regards,

Wolfgang Denk
Doug Anderson Oct. 20, 2011, 5:06 p.m. UTC | #7
Wolfgang,

On Thu, Oct 20, 2011 at 7:36 AM, Wolfgang Denk <wd@denx.de> wrote:

> Sorry, but could you please explain why anybody would need this?
>

I'm happy to explain.  :)  In our setup, the Linux command line is
constructed (in part) by reading from the disk.  When we load the kernel, we
also load the kernel command line.  It is convenient for us if this kernel
command line on disk continues to have things like "console=/dev/ttyS0" and
"earlyprintk" in it so that we can swap between release (no console) and
development (with console) by just tweaking a settings in u-boot.

Certainly we could change our setup, but the prior existence
of fixup_silent_linux() indicated that this might be a common way to do
things.

In the case of Chromium OS, we also do some additional programmatic munging
of the command line for verified boot purposes, but since that is not
upstream it's not really a good argument for making the more general
function.

In any case, I already have the more direct (and less generalized) version
of fixup_silent_linux() written and will send out a patch with just that
shortly.

Based on your comments, I'll assume that you're not interested in the more
general command line munging tools and will abandon them for now until there
is a clear need for them.

Thanks for your review!

-Doug
Mike Frysinger Oct. 20, 2011, 5:15 p.m. UTC | #8
On Thursday 20 October 2011 13:06:23 Doug Anderson wrote:
> Based on your comments, I'll assume that you're not interested in the more
> general command line munging tools and will abandon them for now until
> there is a clear need for them.

what is the difference in compiled sizes ?  if the abstracted funcs add 
negligible overhead, i think merging these locally in the bootm code might 
make sense in a pure clean up sense ...
-mike
Doug Anderson Oct. 20, 2011, 6:23 p.m. UTC | #9
Mike,

On Thu, Oct 20, 2011 at 10:15 AM, Mike Frysinger <vapier@gentoo.org> wrote:

> what is the difference in compiled sizes ?  if the abstracted funcs add
> negligible overhead, i think merging these locally in the bootm code might
> make sense in a pure clean up sense ...
>

Compared to the simple version I just posted and my latest attempt to
address your review comments (and pulling in the newest version of my
patches):

Simple version: 168820 bytes
With munging functions abstracted: 169184 bytes

...so 364 bytes.  It might be smaller if I actually inlined my functions
into bootm.


How about this for a plan?

Wolfgang can see if he wants to apply my "simple" fix to use malloc().  If
so, great!  ...at least the bug will be fixed.  :)

...then, we can decide if we want to add the abstract munging tools and
where to add them (either a separate lib/cmdline.c file or direct into
bootm).  If you want them, I'll submit a patch with all of your review
feedback addressed and a second patch to change fixup_silent_linux() to use
them (with a better description).

...we can think about the earlyprintk and looping questions after the above
have been addressed.

-Doug
Wolfgang Denk Oct. 20, 2011, 7:03 p.m. UTC | #10
Dear Doug Anderson,

In message <CAD=FV=WEk1To=hyOTLBC+htq=7hxrTqtyckajJyLByqs3DBFYA@mail.gmail.com> you wrote:
>
> I'm happy to explain.  :)  In our setup, the Linux command line is
> constructed (in part) by reading from the disk.  When we load the kernel, we
> also load the kernel command line.  It is convenient for us if this kernel
> command line on disk continues to have things like "console=/dev/ttyS0" and
> "earlyprintk" in it so that we can swap between release (no console) and
> development (with console) by just tweaking a settings in u-boot.
> 
> Certainly we could change our setup, but the prior existence
> of fixup_silent_linux() indicated that this might be a common way to do
> things.

Please check where this is actually used, and how. It serves a very
special purpose, and by todays level of reviews I seriously doubt such
code would be accepted any more.

Yes, please change your setup.  Just because you are doing things your
(highly unefficient) way does not mean I'm going to accept such code
for mainline.

> In the case of Chromium OS, we also do some additional programmatic munging
> of the command line for verified boot purposes, but since that is not
> upstream it's not really a good argument for making the more general
> function.

May I ask why you don;t use the powerful capabilities of incrementally
building the command line from environment variable settings?

[These can also be read from disk.]

> In any case, I already have the more direct (and less generalized) version
> of fixup_silent_linux() written and will send out a patch with just that
> shortly.

Please consider it NAKed.

> Based on your comments, I'll assume that you're not interested in the more
> general command line munging tools and will abandon them for now until there
> is a clear need for them.

"Not interested" is an understatement.  I consider them a highly
unefficient and conceptually broken approach.

Best regards,

Wolfgang Denk
Wolfgang Denk Oct. 20, 2011, 7:33 p.m. UTC | #11
Dear Doug Anderson,

In message <CAD=FV=Vki9xXZG0uoHnMgR9=XXv5p=XCbbwhr-xAu9A0WoxdkA@mail.gmail.com> you wrote:
> 
> ...then, we can decide if we want to add the abstract munging tools and
> where to add them (either a separate lib/cmdline.c file or direct into
> bootm).  If you want them, I'll submit a patch with all of your review
> feedback addressed and a second patch to change fixup_silent_linux() to use
> them (with a better description).

As I wrote before: if such a feature should be added, then please in a
generally useful and usable way, not special-cased for specific
operations on a single special variable only.

Best regards,

Wolfgang Denk
Doug Anderson Oct. 21, 2011, 5:09 a.m. UTC | #12
Wolfgang,

On Thu, Oct 20, 2011 at 12:03 PM, Wolfgang Denk <wd@denx.de> wrote:

> > In any case, I already have the more direct (and less generalized)
> version
> > of fixup_silent_linux() written and will send out a patch with just that
> > shortly.
>
> Please consider it NAKed.


One side effect of not committing any patch for fixup_silent_linux() is that
it means that anyone who defines CONFIG_SILENT_CONSOLE and is booting Linux
with "bootm" is subject to the current buffer overrun (regardless of whether
they have a "console=" clause in their Linux command line).

I understand your concerns and will plan to change the way our boot scripts
work so that fixup_silent_linux() isn't needed in our case.  However, since
we still want to define CONFIG_SILENT_CONSOLE we will need something to keep
the buffer overrun away.

If you will not accept a patch to fix the buffer overrun, will you accept a
patch that adds a new config option like CONFIG_DONT_FIXUP_SILENT_LINUX that
prevents fixup_silent_linux() from being called?  That way, any existing
code that relies on the current behavior will continue to work as it does
today, but anyone who wants to avoid the buffer overrun can.

...or, an alternate would be to add CONFIG_FIXUP_SILENT_LINUX to all
existing configs with CONFIG_SILENT_CONSOLE and use that.


Thanks!

-Doug
diff mbox

Patch

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_ */