[RFC PATCH] kexec-tools: Fix option/argument parsing
Matt Evans
matt at ozlabs.org
Thu May 13 19:22:12 EDT 2010
Simon Horman wrote:
> On Thu, May 13, 2010 at 06:14:32PM +1000, Matt Evans wrote:
>> Hi,
>>
>>
>> In playing with kexec-tools I've noticed various problems with the argument
>> passing, meaning one has to be careful to use certain forms of arguments
>> and present them in a certain order.
>>
>> The arguments end up being parsed three times, each getting more specific
>> than the last. main() looks for general args, arch_process_options() looks
>> for options common to all loaders for the arch, and then finally many
>> file_type load() methods check for options specific to that filetype.
>>
>> As GNU getopt works, it re-orders the argv[] pushing any args it doesn't
>> recognise to the end. This includes arguments to valid options which
>> are simply not recognised the first time around.
>>
>> For example, this does not work:
>> # ./kexec -l --append "init=/bin/foo" /boot/vmlinux
>> Cannot open `init=/bin/foo': No such file or directory
>>
>> but this does:
>> # ./kexec -l --append="init=/bin/foo" /boot/vmlinux
>> <joy>
>>
>> Using the --opt<space>arg variant results in the first non-option argument
>> in main() being "init=/bin/foo" which is then used as the kernel filename,
>> failing. Also, the order affects things in unintuitive ways:
>>
>> # ./kexec -l /boot/vmlinux --append "init=/bin/foo"
>> <appears to load correctly, but command line appended with "/boot/vmlinux"!>
>>
>> This behaviour is avoided by using the --opt= forms, but getopt does allow
>> both and hence the user can have a fairly frustrating experience. (Doing
>> something unexpected (ex. 3) is more annoying than an error exit (ex. 1)
>> in many cases.)
>>
>> The fix presented here is to create a new #define to encapsulate all possible
>> options for an architecture build. The intention is that this set includes
>> all possible loaders' all possible options.
>>
>> main() walks through the options and silently ignores any non-general
>> options (BUT respects that "--arg foo" should remain together, as
>> getopt_long() does now recognise it). arch_process_options() walks through
>> them again and responds to any arch-specific options, again ignoring but
>> respecting any non-arch options. Finally the loader may look for its
>> options, and find them in-order and present. Any outside of this combined
>> set are complained-about as usual.
>>
>> So, comments please. Is this a reasonable way to do it or is there an
>> obvious better way I've missed? :-) So far I have been able to test on
>> x86(32,64) and ppc(32,64) but none of the others. :(
>
> This seems reasonable to me.
>
> I've compiled tested the code on all architectures except cris (I don't
> have my build environment at the moment). I found a minor problem on arm
> which I have noted below.
That's superb, thanks very much for compiling them! And thanks also for catching the cut-n-paste-no-brain-involved ARM build problem below. I'll repost.
Cheers,
Matt
>
> [snip]
>
>> diff --git a/kexec/arch/arm/include/arch/options.h b/kexec/arch/arm/include/arch/options.h
>> index 248230b..a76539e 100644
>> --- a/kexec/arch/arm/include/arch/options.h
>> +++ b/kexec/arch/arm/include/arch/options.h
>> @@ -3,9 +3,38 @@
>>
>> #define OPT_ARCH_MAX (OPT_MAX+0)
>>
>> +#define OPT_APPEND 'a'
>> +#define OPT_RAMDISK 'r'
>> +
>> +/* Options relevant to the architecture (excluding loader-specific ones),
>> + * in this case none:
>> + */
>> #define KEXEC_ARCH_OPTIONS \
>> KEXEC_OPTIONS \
>>
>> #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
>>
>> +/* The following two #defines list ALL of the options added by all of the
>> + * architecture's loaders.
>> + * o main() uses this complete list to scan for its options, ignoring
>> + * arch-specific/loader-specific ones.
>> + * o Then, arch_process_options() uses this complete list to scan for its
>> + * options, ignoring general/loader-specific ones.
>> + * o Then, the file_type[n].load re-scans for options, using
>> + * KEXEC_ARCH_OPTIONS plus its loader-specific options subset.
>> + * Any unrecognised options cause an error here.
>> + *
>> + * This is done so that main()'s/arch_process_options()'s getopt_long() calls
>> + * don't choose a kernel filename from random arguments to options they don't
>> + * recognise -- as they now recognise (if not act upon) all possible options.
>> + */
>> +#define KEXEC_ALL_OPTIONS \
>> + KEXEC_ARCH_OPTIONS
>> + { "command-line", 1, 0, OPT_APPEND },
>> + { "append", 1, 0, OPT_APPEND },
>> + { "initrd", 1, 0, OPT_RAMDISK },
>
> The above 4 lines seem to be missing a trailing '\'
>
>> + { "ramdisk", 1, 0, OPT_RAMDISK },
>> +
>> +#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR "a:r:"
>> +
>> #endif /* KEXEC_ARCH_ARM_OPTIONS_H */
>
> [snip]
More information about the kexec
mailing list