Message ID | 1319063459-4804-2-git-send-email-dianders@chromium.org |
---|---|
State | Rejected |
Headers | show |
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
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
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
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
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
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
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
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
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
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
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
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 --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_ */
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