# # anaconda_optparse.py: option parsing for anaconda (CLI and boot args) # # Copyright (C) 2012 Red Hat, Inc. All rights reserved. # # 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, see . # # Authors: # Will Woods from flags import BootArgs from optparse import OptionParser, OptionConflictError class AnacondaOptionParser(OptionParser): """ Subclass of OptionParser that also examines boot arguments. If the "bootarg_prefix" keyword argument is set, it's assumed that all bootargs will start with that prefix. "require_prefix" is a bool: False: accept the argument with or without the prefix. True: ignore the argument without the prefix. (default) """ def __init__(self, *args, **kwargs): self._boot_arg = dict() self.bootarg_prefix = kwargs.pop("bootarg_prefix","") self.require_prefix = kwargs.pop("require_prefix",True) OptionParser.__init__(self, *args, **kwargs) def add_option(self, *args, **kwargs): """ Add a new option - like OptionParser.add_option. The long options will be added to the list of boot args, unless the keyword argument 'bootarg' is set to False. Positional arguments that don't start with '-' are considered extra boot args to look for. NOTE: conflict_handler is currently ignored for boot args - they will always raise OptionConflictError if they conflict. """ # TODO: add kwargs to make an option commandline-only or boot-arg-only flags = [a for a in args if a.startswith('-')] bootargs = [a for a in args if not a.startswith('-')] do_bootarg = kwargs.pop("bootarg", True) option = OptionParser.add_option(self, *flags, **kwargs) bootargs += [flag[2:] for flag in option._long_opts] if do_bootarg: for b in bootargs: if b in self._boot_arg: raise OptionConflictError( "conflicting bootopt string: %s" % b, option) else: self._boot_arg[b] = option return option def _get_bootarg_option(self, arg): """Find the correct Option for a given bootarg (if one exists)""" if self.bootarg_prefix and arg.startswith(self.bootarg_prefix): prefixed_option = True arg = arg[len(self.bootarg_prefix):] else: prefixed_option = False option = self._boot_arg.get(arg) if self.require_prefix and not prefixed_option: return None if option and self.bootarg_prefix and not prefixed_option: self.deprecated_bootargs.append(arg) return option def parse_boot_cmdline(self, cmdline, values=None): """ Parse the boot cmdline and set appropriate values according to the options set by add_option. cmdline can be given as a string (to be parsed by BootArgs), or a dict (or any object with .iteritems()) of {bootarg:value} pairs. If cmdline is None, the cmdline data will be whatever BootArgs reads by default (/proc/cmdline, /run/initramfs/etc/cmdline, /etc/cmdline). If an option requires a value but the boot arg doesn't provide one, we'll quietly not set anything. """ if cmdline is None or type(cmdline) is str: bootargs = BootArgs(cmdline) else: bootargs = cmdline self.deprecated_bootargs = [] for arg, val in bootargs.iteritems(): option = self._get_bootarg_option(arg) if option is None: continue if option.takes_value() and val is None: continue # TODO: emit a warning or something there? if option.action == "store_true" and val in ("0", "no", "off"): # special case: "mpath=0" would otherwise set mpath to True setattr(values, option.dest, False) continue option.process(arg, val, values, self) return values def parse_args(self, args=None, values=None, cmdline=None): """ Like OptionParser.parse_args(), but also parses the boot cmdline. (see parse_boot_cmdline for details on that process.) Commandline arguments will override boot arguments. """ if values is None: values = self.get_default_values() v = self.parse_boot_cmdline(cmdline, values) return OptionParser.parse_args(self, args, v)