On Mon, 4 Aug 2025 17:17:43 +0200
Daniel Kiper <dki...@net-space.pl> wrote:

> On Sun, Aug 03, 2025 at 10:57:03AM -0500, Aaron Rainbolt wrote:
> > On Fri, 1 Aug 2025 14:55:36 +0200 Daniel Kiper
> > <dki...@net-space.pl> wrote:  
> > > On Fri, Jul 25, 2025 at 03:31:12PM -0500, Aaron Rainbolt wrote:  
> > > > Xen traditionally allows customizing guest behavior by passing
> > > > arguments to the VM kernel via the kernel command line. This is
> > > > no longer possible when using GRUB with Xen, as the kernel
> > > > command line is decided by the GRUB configuration file within
> > > > the guest, not data passed to the guest by Xen.
> > > >
> > > > To work around this limitation, enable GRUB to parse a command
> > > > line passed to it by Xen, and expose data from the command line
> > > > to the GRUB configuration as environment variables. These
> > > > variables can be used in the GRUB configuration for any desired
> > > > purpose, such as extending the kernel command line passed to
> > > > the guest. The command line format is inspired by the Linux
> > > > kernel's command line format.
> > > >
> > > > To reduce the risk of misuse, abuse, or accidents in
> > > > production, the command line will only be parsed if it consists
> > > > entirely of 7-bit ASCII characters, only alphabetical
> > > > characters and underscores are permitted in variable names, and
> > > > all variable names must start with the string "xen_grub_env_".
> > > > This also allows room for expanding the command line arguments
> > > > accepted by GRUB in the future, should other arguments end up
> > > > becoming desirable in the future.
> > > >
> > > > Signed-off-by: Aaron Rainbolt <arraybo...@gmail.com>
> > > > ---
> > > >  docs/grub.texi                |  50 +++++
> > > >  grub-core/Makefile.core.def   |   2 +
> > > >  grub-core/kern/i386/xen/pvh.c |  14 ++
> > > >  grub-core/kern/main.c         |  12 ++
> > > >  grub-core/kern/xen/cmdline.c  | 343
> > > > ++++++++++++++++++++++++++++++++++ include/grub/xen.h
> > > >  | 2 + 6 files changed, 423 insertions(+)
> > > >  create mode 100644 grub-core/kern/xen/cmdline.c
> > > >
> > > > diff --git a/docs/grub.texi b/docs/grub.texi
> > > > index 34b3484..ce82483 100644
> > > > --- a/docs/grub.texi
> > > > +++ b/docs/grub.texi
> > > > @@ -3271,6 +3271,7 @@ GRUB.  Others may be used freely in GRUB
> > > > configuration files. @menu
> > > >  * Special environment variables::
> > > >  * Environment block::
> > > > +* Passing environment variables through Xen::
> > > >  @end menu
> > > >
> > > >
> > > > @@ -3871,6 +3872,55 @@ using BIOS or EFI functions (no ATA, USB
> > > > or IEEE1275). @command{grub-mkconfig} uses this facility to
> > > > implement @samp{GRUB_SAVEDEFAULT} (@pxref{Simple
> > > > configuration}).
> > > >
> > > > +@node Passing environment variables through Xen
> > > > +@section Passing environment variables through Xen
> > > > +
> > > > +If you are using a GRUB image as the kernel for a PV or PVH Xen
> > > > virtual +machine, you can pass environment variables from Xen's
> > > > dom0 to the VM through +the Xen-provided kernel command line.
> > > > When combined with a properly configured +guest, this can be
> > > > used to customize the guest's behavior on bootup via the +VM's
> > > > Xen configuration file. +
> > > > +GRUB will parse the kernel command line passed to it by Xen
> > > > during bootup. +The command line will be split into
> > > > space-delimited words. Single and +double quotes may be used to
> > > > quote words or portions of words that contain +spaces.
> > > > Arbitrary characters may be backslash-escaped to make them a
> > > > literal +component of a word rather than being parsed as quotes
> > > > or word separators. The +command line must consist entirely of
> > > > printable 7-bit ASCII characters and +spaces. If a non-printing
> > > > ASCII character is found anywhere in the command +line, the
> > > > entire command line will be ignored by GRUB. + +Each word
> > > > should be a variable assignment in the format ``variable'' or
> > > > +``variable=value''. Variable names must contain only the
> > > > characters A-Z, a-z, +and underscore (``_''). Variable names
> > > > must begin with the string +``xen_grub_env_''. Variable values
> > > > can contain arbitrary printable 7-bit +ASCII characters and
> > > > space. If any variable contains an illegal name, that +variable
> > > > will be ignored. + +If a variable name and value are both
> > > > specified, the variable will be set to +the specified value. If
> > > > only a variable name is specified, the variable's +value will
> > > > be set to ``1''. +
> > > > +The following is a simple example of how to use this
> > > > functionality to append +arbitrary variables to a guest's
> > > > kernel command line: +
> > > > +@example
> > > > +# In the Xen configuration file for the guest
> > > > +name = "linux_vm"
> > > > +type = "pvh"
> > > > +kernel = "/path/to/grub-i386-xen_pvh.bin"
> > > > +extra = "xen_grub_env_kernelappend='loglevel=3'"  
> > >
> > > s/kernelappend/kernel_append/
> > >
> > > or maybe even
> > >
> > > s/kernelappend/linux_append/
> > >
> > > to make it clear it is appended to the "linux" command line...  
> >
> > Will do.
> >  
> > > > +memory = 1024
> > > > +disk = [ "file:/srv/vms/linux_vm.img,sda,w" ]
> > > > +
> > > > +# In the guest's GRUB configuration file
> > > > +menuentry "Linux VM with dom0-specified kernel parameters" @{
> > > > +    search --set=root --label linux_vm --hint hd0,msdos1
> > > > +    linux /boot/vmlinuz root=LABEL=linux_vm
> > > > $@{xen_grub_env_kernelappend@}  
> > >
> > > Ditto...  
> >
> > Will do.
> >  
> > > > +    initrd /boot/initrd.img
> > > > +@}
> > > > +@end example
> > > > +
> > > >  @node Modules
> > > >  @chapter Modules
> > > >
> > > > diff --git a/grub-core/Makefile.core.def
> > > > b/grub-core/Makefile.core.def index b3f7119..df0f266 100644
> > > > --- a/grub-core/Makefile.core.def
> > > > +++ b/grub-core/Makefile.core.def
> > > > @@ -248,6 +248,7 @@ kernel = {
> > > >    xen = term/xen/console.c;
> > > >    xen = disk/xen/xendisk.c;
> > > >    xen = commands/boot.c;
> > > > +  xen = kern/xen/cmdline.c;
> > > >
> > > >    i386_xen_pvh = commands/boot.c;
> > > >    i386_xen_pvh = disk/xen/xendisk.c;
> > > > @@ -255,6 +256,7 @@ kernel = {
> > > >    i386_xen_pvh = kern/i386/xen/tsc.c;
> > > >    i386_xen_pvh = kern/i386/xen/pvh.c;
> > > >    i386_xen_pvh = kern/xen/init.c;
> > > > +  i386_xen_pvh = kern/xen/cmdline.c;
> > > >    i386_xen_pvh = term/xen/console.c;
> > > >
> > > >    ia64_efi = kern/ia64/efi/startup.S;
> > > > diff --git a/grub-core/kern/i386/xen/pvh.c
> > > > b/grub-core/kern/i386/xen/pvh.c index 91fbca8..12df2d8 100644
> > > > --- a/grub-core/kern/i386/xen/pvh.c
> > > > +++ b/grub-core/kern/i386/xen/pvh.c
> > > > @@ -321,6 +321,8 @@ void
> > > >  grub_xen_setup_pvh (void)
> > > >  {
> > > >    grub_addr_t par;
> > > > +  const char *xen_cmdline;
> > > > +  int i;
> > > >
> > > >    grub_xen_cpuid_base ();
> > > >    grub_xen_setup_hypercall_page ();
> > > > @@ -352,6 +354,18 @@ grub_xen_setup_pvh (void)
> > > >    grub_xen_mm_init_regions ();
> > > >
> > > >    grub_rsdp_addr = pvh_start_info->rsdp_paddr;
> > > > +
> > > > +  xen_cmdline = (const char *) pvh_start_info->cmdline_paddr;
> > > > +  for (i = 0; i < MAX_GUEST_CMDLINE; i++)  
> > >
> > > Oh, MAX_GUEST_CMDLINE is a too generic. May I ask you to rename
> > > it to GRUB_XEN_MAX_GUEST_CMDLINE? This should be done in separate
> > > patch preceding this one.  
> >
> > Sure.
> >  
> > > > +    {
> > > > +      if (xen_cmdline[i] == '\0')  
> > >
> > > I cannot see much sense in this check. Please look below...
> > >  
> > > > +        {
> > > > +          grub_strncpy ((char *)
> > > > grub_xen_start_page_addr->cmd_line,
> > > > +                       (char *)
> > > > pvh_start_info->cmdline_paddr,  
> > >
> > > s/char */const char */
> > >
> > > Is it always guaranteed that pvh_start_info->cmdline_paddr have
> > > MAX_GUEST_CMDLINE size? If yes then...  
> >
> > It is not guaranteed. I tested this under Qubes OS, and it is
> > unfortunately very possible to pass a guest command line longer than
> > MAX_GUEST_CMDLINE via pvh_start_info->cmdline_paddr. I do not know
> > of any documentation specifying what the "real" maximum length is
> > in this instance (if any), but in any event the string ultimately
> > has to be crammed into an array that is only MAX_GUEST_CMDLINE
> > long. Originally I wrote this to truncate the command line in this
> > situation, but later decided that discarding the command line would
> > be safer than truncation.  
> 
> I think you are confusing source, grub_xen_start_page_addr->cmd_line,
> and destination, pvh_start_info->cmdline_paddr. I am asking about the
> destination...

The destination is grub_xen_start_page_addr->cmd_line.
pvh_start_info->cmdline_paddr is the *source*, not the destination.
grub_xen_start_page_addr->cmd_line is a MAX_GUEST_CMDLINE-long int8_t
array, so yes, the destination is guaranteed to always have
MAX_GUEST_CMDLINE size.

> > (When booting a VM in PV mode, Xen does guarantee the command line
> > will not be longer than MAX_GUEST_CMDLINE and will simply return a
> > truncated command line. There is no way to detect this condition to
> > my awareness, so in PV mode, we simply live with the truncation
> > since we aren't given another option.)  
> 
> OK...
> 
> > > grub_memset ((void *) pvh_start_info->cmdline_paddr, 0,
> > > MAX_GUEST_CMDLINE); grub_strncpy ((char *)
> > > grub_xen_start_page_addr->cmd_line, (const char *)
> > > pvh_start_info->cmdline_paddr, MAX_GUEST_CMDLINE - 1);
> > >
> > > ... and you are done...  
> >
> > This would truncate the command line rather than discarding it. If
> > the goal is consistency with Xen's PV mode, then I can switch to
> > this, but I don't like the idea of booting a guest with corrupted
> > data inserted randomly into the grub.cfg file. (Like mentioned
> > above, there isn't any other option when using PV mode, but just
> > because PV mode does things dangerously doesn't mean we have to
> > when running in PVH mode.)  
> 
> OK, but please remember you have to ensure the string is
> NUL-terminated after grub_strncpy(). Potentially you could also use
> grub_strlen() to make a check and add NUL in proper place...

The code does ensure the string is NUL-terminated I believe, unless
grub_strncpy doesn't behave like POSIX strncpy. If a '\0' is found
anywhere in pvh_start_info->cmdline_paddr (the source), then we
grub_strncpy the string to grub_xen_start_page_addr->cmd_line,
specifying the size of the destination buffer as MAX_GUEST_CMDLINE.
strncpy pads the rest of the buffer with NUL bytes. In the worst case
scenario, the source is exactly MAX_GUEST_CMDLINE-1 bytes long plus a
NUL at the end, in which case strncpy will copy MAX_GUEST_CMDLINE-1
bytes and then add one byte of NUL padding. If the sources consists of
MAX_GUEST_CMDLINE non-NUL bytes, the copy won't happen at all because a
NUL will never be found in the first MAX_GUEST_CMDLINE bytes of the
source.

Using grub_strlen as a sanity check sounds good. If after the copy,
`grub_strlen((char *) grub_xen_start_page_addr->cmd_line) != (i - 1)`,
then we know something is wrong and can halt the system.

> > > > +                       MAX_GUEST_CMDLINE);
> > > > +          break;
> > > > +        }
> > > > +    }
> > > >  }
> > > >
> > > >  grub_err_t
> > > > diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
> > > > index 143a232..b4377d3 100644
> > > > --- a/grub-core/kern/main.c
> > > > +++ b/grub-core/kern/main.c
> > > > @@ -37,6 +37,10 @@
> > > >  #include <grub/machine/memory.h>
> > > >  #endif
> > > >
> > > > +#if defined (GRUB_MACHINE_XEN) || defined
> > > > (GRUB_MACHINE_XEN_PVH) +#include <grub/xen.h>
> > > > +#endif
> > > > +
> > > >  static bool cli_disabled = false;
> > > >  static bool cli_need_auth = false;
> > > >
> > > > @@ -351,6 +355,14 @@ grub_main (void)
> > > >    grub_env_export ("root");
> > > >    grub_env_export ("prefix");
> > > >
> > > > +  /*
> > > > +   * Parse command line parameters from Xen and export them as
> > > > environment
> > > > +   * variables
> > > > +   */
> > > > +#if defined (GRUB_MACHINE_XEN) || defined
> > > > (GRUB_MACHINE_XEN_PVH)
> > > > +  grub_parse_xen_cmdline ();  
> > >
> > > Please move this call to the
> > > grub-core/kern/xen/init.c:grub_machine_init().  
> >
> > Will do.
> >  
> > > > +#endif
> > > > +
> > > >    /* Reclaim space used for modules.  */
> > > >    reclaim_module_space ();
> > > >
> > > > diff --git a/grub-core/kern/xen/cmdline.c
> > > > b/grub-core/kern/xen/cmdline.c new file mode 100644
> > > > index 0000000..03dd88f
> > > > --- /dev/null
> > > > +++ b/grub-core/kern/xen/cmdline.c
> > > > @@ -0,0 +1,343 @@
> > > > +/*
> > > > + *  GRUB  --  GRand Unified Bootloader
> > > > + *  Copyright (C) 2025  Free Software Foundation, Inc.
> > > > + *
> > > > + *  GRUB 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 3 of the
> > > > License, or
> > > > + *  (at your option) any later version.
> > > > + *
> > > > + *  GRUB 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 GRUB.  If not, see
> > > > <http://www.gnu.org/licenses/>.
> > > > + */
> > > > +
> > > > +#include <grub/env.h>
> > > > +#include <grub/misc.h>
> > > > +#include <grub/mm.h>
> > > > +#include <grub/xen.h>
> > > > +
> > > > +enum parse_flags
> > > > +{
> > > > +  PARSER_HIT_BACKSLASH = 0x1,
> > > > +  PARSER_IN_SINGLE_QUOTES = 0x2,
> > > > +  PARSER_IN_DOUBLE_QUOTES = 0x4,
> > > > +};  
> > > typedef parse_flags parse_flags_t;
> > >
> > > ... and use parse_flags_t instead below...  
> >
> > Will do.
> >  
> > > And probably this should be a local variable...  
> >
> > See below for comments on globals in the parser.
> >  
> > > > +
> > > > +#define PARSER_BASE_WORD_LEN 16  
> > >
> > > This constant begs for a few words of comment...  
> >
> > Will add. This is just the initial length of the dynamically
> > allocated buffer for storing each "word" of the command line, but
> > it is confusing as written. Perhaps it should be renamed to
> > PARSER_WORD_BUF_START_LEN or similar, to make it clear this isn't a
> > string length, but a buffer length?  
> 
> s/length/size/ then... However, then why 16 not, e.g., 32?

My original iteration of the patch didn't require `xen_grub_env_` at
the beginning of every variable name, so 16 was a reasonable estimate
of how long most "words" would end up, and I wanted to use the smallest
reasonable value here. That being said, `xen_grub_env_` is required
now, which is already 13 bytes long, so maybe 32 is a more reasonable
value. (Or, depending on where GRUB's allocator aligns things, maybe
this should be a large number like MAX_GUEST_CMDLINE, so that we don't
ever have to reallocate?)

> > > > +static grub_size_t word_list_len;
> > > > +static char **word_list;
> > > > +static grub_size_t current_word_len;
> > > > +static grub_size_t current_word_pos;
> > > > +static char *current_word;
> > > > +static char current_char;  
> > >
> > > I have a feeling that most if not all of this variables should be
> > > local in a given function...  
> >
> > I made them globals because making them local would have required an
> > awful lot of parameter "shuttling" that I believed made the code
> > less readable. For instance, the `append_word_to_list` function
> > right now has no parameters and can be called very simply by the
> > parser whenever it is needed. If all variables used were local, the
> > function would have to have a signature akin to:
> >
> >   static bool append_word_to_list(grub_size_t *current_word_pos_ref,
> >     grub_size_t *current_word_len_ref, char *current_word,
> >     grub_size_t *word_list_len_ref, char **word_list)
> >
> > IMO this is difficult to read and frustrating to call (possibly even
> > error-prone). Ultimately the variables are "local" to the parser,
> > and the functions are just there to split up the parser's algorithm
> > to avoid repetition. They all ultimately operate on the same state,
> > so having the state variables static but global within the file
> > fits the current parser design well.  
> 
> First of all, think about the design. If you are sure it is optimal
> then please use struct and a pointer to pass as many argument as you
> need...

Will do.

> > > > +static bool
> > > > +append_char_to_word (bool allow_null)
> > > > +{
> > > > +  /*
> > > > +   * Fail if the current char is outside of the range 0x20 to
> > > > 0x7E. If
> > > > +   * allow_null is true, make an exception for 0x00. This is a
> > > > safeguard  
> > >
> > > Could you elaborate here when allow_null == true is useful?  
> >
> > Usually when appending characters to a word, you aren't going to be
> > appending null characters, thus `append_char_to_word` usually
> > rejects  
> 
> s/null/NUL/...

Will switch terminology from now on.

> > those so as to make it harder to mess things up. However, the string
> > does need to be null-terminated, and thus once a command line word
> > is  
> 
> Ditto... In general, even it is correct, I prefer to use NUL instead
> of null/NULL to avoid confusion...
> 
> > fully loaded into current_word, it is necessary to add the null
> > terminator on the end. In this instance the parser sets
> > `current_char` to '\0' and then calls the `append_char_to_word`
> > function with `allow_null` set to true, so that the function knows
> > that the addition of a null is intentional here.
> >
> > (In retrospect, if allow_null is set to true, the only thing
> > `append_char_to_word` should append is a null character, it should
> > reject anything else in that instance. Otherwise someone could
> > accidentally append something other than a null when they meant to
> > append a null.)  
> 
> Is not it simpler to open code this instead of complicating this
> function?

Due to the possibility of having to reallocate the buffer, I don't
think so. If however we switch to using a buffer than doesn't need
reallocation, then it would be simpler to do that. I'll experiment with
it before sending the next patch version.

> > > > +   * against likely-invalid data.
> > > > +   */
> > > > +  if ( (!(current_char >= 0x20) || !(current_char <= 0x7E) )  
> > >
> > > grub_isprint()?  
> >
> > That would work, I wasn't aware that existed. Maybe a mention of
> > some valuable GRUB internal API functions that are likely to remain
> > stable could be added to the GRUB development manual? (Or just a
> > reference to header files where useful things like this are
> > defined.)  
> 
> Certainly it is a good idea. In general you can assume the GRUB has a
> lot of POSIX compatible functions which names are prefixed with
> "grub_".

Nice, good to know.

> > > > +      && (current_char != '\0' || allow_null == false))  
> > >
> > > I would drop redundant spaces between "(" and ")" and move "&&"
> > > to the end of first line of "if".  
> >
> > Will do, though I'm likely to rewrite this conditional anyway so
> > that anything other than '\0' will be rejected when `allow_null ==
> > true`. 
> > > > +    return false;
> > > > +
> > > > +  if (current_word_pos == current_word_len)
> > > > +    {
> > > > +      current_word_len *= 2;  
> > >
> > > You can do this in the argument of the function below...  
> >
> > I mean, yes, technically I can, but that's a lot less readable to
> > me. I can't find anywhere else in GRUB that uses that style (using
> > `grep -ri '\*='` to search), and can find a few spots that use a
> > style similar to the one I've used here:
> >
> > * `util/grub-install.c` in function `device_map_check_duplicates`
> > * `grub-core/osdep/windows/platform.c` in function
> > `get_efi_variable`
> > * `grub-core/osdep/unix/platform.c` in function `get_ofpathname`
> >  
> > > > +      current_word = grub_realloc (current_word,
> > > > current_word_len);
> > > > +      if (current_word == NULL)
> > > > +        {
> > > > +          current_word_len /= 2;
> > > > +          return false;
> > > > +        }
> > > > +    }
> > > > +
> > > > +  current_word[current_word_pos] = current_char;
> > > > +  current_word_pos++;  
> > >
> > > Again, you can do this operation in the "[]" above...  
> >
> > Will do. (This does seem to be a much more common way to write
> > things in GRUB than what I've done.)
> >  
> > > > +  return true;
> > > > +}
> > > > +
> > > > +static bool
> > > > +append_word_to_list (void)
> > > > +{
> > > > +  /* No-op on empty words. */
> > > > +  if (current_word_pos == 0)  
> > >
> > > This should be probably an argument for the function...  
> >
> > See above for parser state and global variables rationale.
> >  
> > > > +    return true;
> > > > +
> > > > +  current_char = '\0';
> > > > +  if (append_char_to_word (true) == false)
> > > > +    {
> > > > +      grub_error (GRUB_ERR_BUG,
> > > > +                 "couldn't append null terminator to word
> > > > during Xen cmdline parsing");
> > > > +      grub_print_error ();
> > > > +      grub_exit ();
> > > > +    }
> > > > +
> > > > +  current_word_len = grub_strlen (current_word) + 1;
> > > > +  current_word = grub_realloc (current_word, current_word_len);
> > > > +  if (current_word == NULL)
> > > > +    return false;
> > > > +  word_list_len++;  
> > >
> > > Again this, OK ++word_list_len to be precise, can be done in a
> > > function argument below...  
> >
> > `grep -ri 'alloc.*++'` doesn't show me any instance of this style
> > anywhere else in the GRUB codebase, and I find it much more
> > difficult to read since now I have to think about incrementing
> > `word_list_len`'s value and returning it and multiplying the
> > returned value all at the same time.
> > `grub-core/osdep/unix/platform.c` uses the style I've used here.
> >  
> > > > +  word_list = grub_realloc (word_list, word_list_len * sizeof
> > > > (char *));  
> 
> word_list = grub_realloc (word_list, ++word_list_len * sizeof (char
> *a));
> 
> Is it really difficult to read? I do not think so...

I find it harder to read personally, but I'm fine with switching to it
if you'd prefer.

> [...]
> 
> > > > +void
> > > > +grub_parse_xen_cmdline (void)
> > > > +{
> > > > +  const char *cmdline = (const char *)
> > > > grub_xen_start_page_addr->cmd_line;
> > > > +  grub_size_t cmdline_len;
> > > > +  bool cmdline_valid = false;
> > > > +  char **param_keys = NULL;
> > > > +  char **param_vals = NULL;
> > > > +  grub_size_t param_dict_len = 0;
> > > > +  grub_size_t param_dict_pos = 0;
> > > > +  enum parse_flags parse_flags = 0;
> > > > +  grub_size_t i = 0;
> > > > +
> > > > +  /*
> > > > +   * The following algorithm is used to parse the Xen command
> > > > line:
> > > > +   *
> > > > +   * - The command line is split into space-separated words.
> > > > +   *   - Single and double quotes may be used to suppress the
> > > > splitting
> > > > +   *     behavior of spaces.
> > > > +   *   - Double quotes are appended to the current word
> > > > verbatim if they
> > > > +   *     appear within a single-quoted string portion, and vice
> > > > versa.
> > > > +   *   - Backslashes may be used to cause the next character
> > > > to be
> > > > +   *     appended to the current word verbatim. This is only
> > > > useful when
> > > > +   *     used to escape quotes, spaces, and backslashes, but
> > > > for simplicity
> > > > +   *     we allow backslash-escaping anything.
> > > > +   * - After splitting the command line into words, each word
> > > > is checked to
> > > > +   *   see if it contains an equals sign.
> > > > +   *   - If it does, it is split on the equals sign into a
> > > > key-value pair. The
> > > > +   *     key is then treated as an variable name, and the
> > > > value is treated as
> > > > +   *     the variable's value.
> > > > +   *   - If it does not, the entire word is treated as a
> > > > variable name. The
> > > > +   *     variable's value is implicitly considered to be `1`.
> > > > +   * - All variables detected on the command line are checked
> > > > to see if their
> > > > +   *   names begin with the string `xen_grub_env_`. Variables
> > > > that do not pass
> > > > +   *   this check are discarded, variables that do pass this
> > > > check are
> > > > +   *   exported so they are available to the GRUB
> > > > configuration.  
> > >
> > > I think not all from this valuable comment landed in the
> > > documentation. Please fix it...  
> >
> > Comparing the two side-by-side:
> >
> > +----------------------------------+----------------------------------+
> > | Documentation                    | Comment
> >   |
> > +==================================+==================================+
> > | The command line will be split   | The command line is split into
> >   | | into space-delimited words.      | space-separated words.
> > Single    | | Single and double quotes may be  | and double quotes
> > may be used to | | used to quote words or portions  | suppress the
> > splitting behavior  | | of words that contain spaces.    | of
> > spaces.                       |
> > +----------------------------------+----------------------------------+
> > | (Self-evident, any other         | Double quotes are appended to
> >   | | behavior involving quotes would  | the current word verbatim
> > if     | | be extremely unexpected.)        | they appear within a
> > single-     | |                                  | quoted string,
> > and vice versa.   |
> > +----------------------------------+----------------------------------+
> > | Arbitrary characters may be      | Backslashes may be used to
> > cause | | backslash-escaped to make them a | the next character to
> > be         | | literal component of a word      | appended to the
> > current word     | | rather than being parsed as      | verbatim.
> > This is only useful    | | quotes or word separators.       | when
> > used to escape quotes,      | |                                  |
> > spaces, and backslashes, but for | |
> >   | simplicity we allow backslash-   | |
> >       | escaping anything.               |
> > +----------------------------------+----------------------------------+
> > | Each word should be a variable   | After splitting the command
> > line | | assignment in the format         | into words, each word
> > is checked | | ``variable'' or                  | to see if it
> > contains an equals  | | ``variable=value''.              | sign.
> >                         |
> > +----------------------------------+----------------------------------+
> > | If a variable name and value are | If it does, it is split on the
> >   | | both specified, the variable     | equals sign into a
> > key-value     | | will be set to the specified     | pair. The key
> > is then treated as | | value.                           | a
> > variable name, and the value   | |
> > | treated as the variable's value. |
> > +----------------------------------+----------------------------------+
> > | If only a variable name is       | If it does not, the entire
> > word  | | specified, the variable's value  | is treated as a
> > variable name.   | | will be set to ``1''.            | The
> > variable's value is          | |                                  |
> > implicitly considered to be '1'. |
> > +----------------------------------+----------------------------------+
> > | Variable names must begin with   | All variables detected on the
> >   | | the string ``xen_grub_env_''...  | command line are checked
> > to see  | | If any variable contains an      | if their names begin
> > with the    | | illegal name, that variable will | string
> > `xen_grub_env_`.          | | be ignored.                      |
> > Variables that do not pass this  | |
> >   | check are discarded,             |
> > +----------------------------------+----------------------------------+
> > | ...you can pass environment      | variables that do pass this
> >   | | variables from Xen's dom0 to the | check are exported so they
> > are   | | VM through the Xen-provided      | available to the GRUB
> >           | | kernel command line.             | configuration.
> >               |
> > +----------------------------------+----------------------------------+
> >
> > The only missing detail I see is that single quotes are legal in
> > double-quoted strings and vice versa, though I guess I can make it
> > more explicit that the variables passed on the command line are
> > exported before getting to the example that shows this. Is there
> > anything else you see that's missing?  
> 
> Exactly, I was thing about single/double quotes here. If other stuff
> is in the documentation then OK...

Will add.

--
Aaron

> > > > +   */
> > > > +
> > > > +  current_word_len = PARSER_BASE_WORD_LEN;
> > > > +  current_word = grub_malloc (current_word_len);
> > > > +  if (current_word == NULL)
> > > > +    goto cleanup;
> > > > +
> > > > +  for (i = 0; i < MAX_GUEST_CMDLINE; i++)
> > > > +    {
> > > > +      if (cmdline[i] == '\0')
> > > > +        {
> > > > +          cmdline_valid = true;
> > > > +          break;
> > > > +        }
> > > > +    }
> > > > +
> > > > +  if (cmdline_valid == false)
> > > > +    {
> > > > +      grub_error (GRUB_ERR_BAD_ARGUMENT,
> > > > +                 "Command line from Xen is not
> > > > NUL-terminated");  
> > >
> > > GRUB errors usually start with lowercase...  
> >
> > Will fix.
> >  
> > > > +      grub_print_error ();
> > > > +      goto cleanup;
> > > > +    }
> > > > +
> > > > +  cmdline_len = grub_strlen (cmdline);
> > > > +  for (i = 0; i < cmdline_len; i++)
> > > > +    {
> > > > +      current_char = cmdline[i];
> > > > +
> > > > +      /*
> > > > +       * If the previous character was a backslash, append the
> > > > current
> > > > +       * character to the word verbatim
> > > > +       */
> > > > +      if (parse_flags & PARSER_HIT_BACKSLASH)  
> > >
> > > s/parse_flags/parser_state/  
> >
> > Hmm, I don't like 'parser_state' as a name because the parser's
> > "state" is the global variables in `grub-core/kern/xen/cmdline.`.
> > Maybe 'splitter_state' instead, since this is just the bit of state
> > that the word splitter is concerned with?  
> 
> I am OK with both...
>
> Daniel

Attachment: pgp8mnvORoPa9.pgp
Description: OpenPGP digital signature

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to