2N/A# The contents of this file are subject to the terms of the 2N/A# Common Development and Distribution License (the "License"). 2N/A# You may not use this file except in compliance with the License. 2N/A# See the License for the specific language governing permissions 2N/A# and limitations under the License. 2N/A# When distributing Covered Code, include this CDDL HEADER in each 2N/A# If applicable, add the following below this CDDL HEADER, with the 2N/A# fields enclosed by brackets "[]" replaced with your own identifying 2N/A# information: Portions Copyright [yyyy] [name of copyright owner] 2N/A# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 2N/AGRUB2 boot loader backend for pybootmgmt 2N/A# pylint: disable=C0302 2N/A """Returns a timestamp string with all significant digits 2N/A############################################################################# 2N/A############################################################################# 2N/A# pylint: disable=R0903 2N/A """MenuConfigEntry represents one menu entry (section) from a 2N/A MenuConfigParser. Each entry is linked with the MenuConfigParser that 2N/A created it so that when it is modified, it can inform the parent 2N/A that state has been modified. 2N/A """Initialize the MenuConfigEntry 2N/A # section is the section name tuple: 2N/A # (<class type>, <0-based index>) 2N/A # options is a dictionary of all options in the section 2N/A """Update the options dict in this instance with the newdict passed in. 2N/A Detects if there are changes, and if there are, marks the parent 2N/A MenuConfigParser as dirty. 2N/A """Returns a dict with the options passed in, stringified. 2N/A """Return a copy to the options dict so no one can modify it. 2N/A Ideally, it would be an immutable dict. 2N/A """Returns a floating point timestamp of the last modified time, or 0 2N/A if no timestamp exists. 2N/A """Return a string that represents the section name 2N/A """Match the section using the string passed. 2N/A """Returns the string representation of this menu configuration entry 2N/A # pylint: disable=W0212 2N/A """Compare two MenuConfigEntry instances based on their section names. 2N/A # Compare the section tuples directly (the integer comparison 2N/A # for the third tuple element happens automatically): 2N/A """Compares two MenuConfigEntry instances. the entry with the 2N/A most-recent modified timestamp wins, otherwise, the entry with the 2N/A lexically-largest section tuple wins. 2N/A pass # Can't compare using the modified timestamps, so revert 2N/A # to testing the section names 2N/A # pylint: enable=W0212 2N/A# pylint: enable=R0903 2N/A# pylint: disable=R0902 2N/A """The MenuConfigParser class provides an interface to the menu.conf 2N/A file. The menu.conf file contains a set of sections, each (except for two) 2N/A of which describes a single Solaris boot entry in the 2N/A automatically-generated boot-loader menu. The syntax of the menu.conf is 2N/A that accepted by the ConfigParser class. The sections and properties 2N/A order = <comma-separated list of section names> 2N/A <Boot Loader Properties> 2N/A [<classname>:<index>] 2N/A title=<Menu entry title> [Required] 2N/A default={True|False} # If this is the default boot entry 2N/A transient={True|False} # If this is a transient entry 2N/A Other properties, depending on the <classname>: 2N/A bootfs=<bootfs value> [SolarisDiskBootInstance] [required] 2N/A kargs=<kernel arguments> [SolarisBootInstance] [optional] 2N/A kernel=<path to kernel file> [SolarisBootInstance] [optional] 2N/A boot_archive=<path to boot archive> [SolarisBootInstance] [optional] 2N/A '# DO NOT EDIT THIS FILE DIRECTLY. CHANGES MAY NOT ' 2N/A '# Changes to this file can be made indirectly via ' 2N/A 'bootadm(1M) subcommands.\n#\n')
2N/A """Creates or loads the menu configuration from the specified file. 2N/A If the file does not exist, an empty menu configuration is created, 2N/A but is not written to disk (see the write() method). If new_conf 2N/A is True, the file's contents are not loaded; instead, an empty menu 2N/A configuration is created (but not written yet). 2N/A The following Exceptions may be generated: 2N/A BootmgmtConfigReadError -- If there's a problem reading config file. 2N/A """Attempt to load the file specified. If it does not exist, 2N/A proceed with an empty SafeConfigParser. 2N/A The following Exceptions may be generated: 2N/A BootmgmtConfigReadError -- If there's a problem reading config file. 2N/A """Creates MenuConfigEntry objects from the ConfigParser's section 2N/A list and adds them to the entry list. Also loads the meta and 2N/A global sections, if found. 2N/A # Now create an MenuConfigEntry object for each section 2N/A # Parse the section name into a tuple: 2N/A # Handle 'normal' menu entries 2N/A elif sect ==
'meta':
# Handle [meta] section 2N/A elif sect ==
'global':
# Handle [global] section 2N/A # Globals are sanity-checked by MenuConfigParser consumers 2N/A # pylint: disable=E0102,E0202,E1101 2N/A """Returns the state of the internal dirty variable. 2N/A """Sets the state of the internal dirty variable. Emits a debug 2N/A message if the state of the internal dirty variable changed. 2N/A # pylint: enable=E0102,E0202,E1101 2N/A """Returns the filename of the menu.conf that this object was created 2N/A # pylint: disable=R0913 2N/A """Add an entry to the menu configuration file. 2N/A The section_name parameter is used to derive the section 2N/A If the propdict is not None, it contains 2N/A the properties used to initialize the new menu entry. 2N/A # pylint: enable=R0913 2N/A """Delete an entry by matching the object address to one in the list. 2N/A """Deletes one or more menu configuration entries. Entries are found 2N/A based by either matching the section_name argument (if cmp_fn is None) 2N/A or by invoking cmp_fn for each entry in the entry list. If cmp_fn 2N/A returns True, that entry is deleted. cmp_fn takes 1 argument-- 2N/A the entry instance to consider for deletion). 2N/A If match_all is True, then all entries that match are deleted; 2N/A otherwise, only the first match is deleted. 2N/A Returns a count of the number of deleted entries. 2N/A """CDS = comma-delimited string 2N/A """Set the propname property to a comma-separated string composed 2N/A of strings from stringlist. 2N/A """Get a list of section headers that specify the order of menu 2N/A entries, if one exists. 2N/A """Set the list of section headers that specifies the order of menu 2N/A """Delete the order property from the meta section and mark this 2N/A """Generates a new section title based on the existing sections and 2N/A the name passed in. Note that until the section is a part of a 2N/A MenuConfigEntry object and that object is added to this 2N/A MenuConfigParser's entry list, it's possible for this function to 2N/A generate multiple identical section names. 2N/A # Now find the largest used index for the section_name 2N/A else:
# Search for and return a tuple with a free index 2N/A """Generate a new ConfigParser using the data from the MenuConfigEntry 2N/A """Writes the menu configuration data to the menu configuration file. 2N/A If no changes have been made since the configuration was loaded, 2N/A write() will return without writing the file (unless force is True). 2N/A If alt_file is not None, the menu configuration will be written there. 2N/A Exceptions that may be generated: 2N/A BootmgmtConfigWriteError -- If the menu config file cannot be created 2N/A or if there's a problem writing to it. 2N/A # First synch the MenuConfigParser state to a new ConfigParser: 2N/A # Use the alternate file, if specified; otherwise use the cached 2N/A # filename supplied to the constructor 2N/A # We cannot proceed without a filename 2N/A# pylint: enable=R0902 2N/A """Implementation of the BootLoader interface for the GRUB2 boot 2N/A # These prefixes MUST NOT start with '/', or os.path.join() will not 2N/A # behave as we want below. 2N/A 'uefi64':
'x86_64-efi'}
2N/A # List of modules that should be baked into the GRUB 2 image (i.e. 2N/A # available in rescue mode). Each key in PRELOADED_MODULES *must* be 2N/A # a list of strings (module names). 2N/A # These may look like duplicates of the BOOT_SUBDIRS, but they're separate 2N/A # because they're actualy arguments to the grub-mkimage command. 2N/A 'uefi64':
'x86_64-efi'}
2N/A 'uefi64':
'efi_gop'}
2N/A "640x480x15;640x480x32" 2N/A # This exit code is returned by grub-install and grub-mkimage if it is 2N/A # incompatible with the GRUB2 modules on which it was asked to operate. 2N/A # In the case of ODDBootConfig, this is a fatal error. For DiskBootConfig, 2N/A # we log this fact and then proceed with deferred boot loader activation. 2N/A # GRUB_OTHERS stores lists of 3-tuples (source, destination, perms) 2N/A # (source is relative to the data root (i.e. the root directory of a boot 2N/A # instance) and destination is relative to the config data root (i.e. the 2N/A # zfs top level dataset for a root pool). The destination is relative to 2N/A # the grub configuration directory (boot/grub) and perms is a 3-tuple of 2N/A # (user, group, mode). If perms is None, GRUB_OTHERS_PERM_DEFAULTS is used. 2N/A 'unicode.pf2',
None),
2N/A 'splash.jpg',
None)]
2N/A # Paths are relative to the zfs top level dataset: 2N/A # Due to a limitation in Solaris's mkfs -F pcfs, we cannot make a 2N/A # fat filesystem with nofdisk of size < 4M. 2N/A """Probe for GRUB2 on a system. 2N/A """This GRUB2 probe function searches the ODD's root, looking for 2N/A the GRUB2 core modules""" 2N/A """This GRUB2 probe function searches the net install image root, 2N/A looking for the GRUB2 NBP programs""" 2N/A """This GRUB2 probe function invokes probe_artifacts to look for 2N/A the menu.conf file at the ZFS top-level dataset (if this is a ZFS-based 2N/A DiskBootConfig), as well as the GRUB2 kernel and utilities. 2N/A """Generic probe function for GRUB2. 2N/A # Both the data root location must be specified 2N/A """Looks for the menu.conf and the NBPs. There are no "tools" 2N/A needed for NetBootConfig. The images are preassembled. 2N/A # This is the OS image's root; we need to look for the config 2N/A # files in the net_data_root. 2N/A """Probe for artifacts found when used with a DiskBootConfig 2N/A # probe_artifacts can either be called at BootLoader factory.get 2N/A # time or at runtime. If it's the latter, we need to get the 2N/A # most-recent data root in which to look for the artifacts. 2N/A # pylint: disable=W0212 2N/A # pylint: enable=W0212 2N/A # List of essential data files need to pass the disk probe: 2N/A # In addition to the loader files themselves, we need to ensure 2N/A # that we have access to the grub-install program (and its dependent 2N/A # executables) in the currently-running system (otherwise, we'll 2N/A # have no way to install GRUB2). 2N/A """Returns a list of artifacts for this BootLoader, given a 2N/A bootconfig to use for directory information. 2N/A # Only supported for disk-based BootConfigs. 2N/A # The config files are written to the root of the data dir. 2N/A """Constructor for GRUB2 BootLoader 2N/A """Uninitialized all theme attributes (resets to default theme) 2N/A """Reset configuration information by starting with a new menu.conf. 2N/A """Loads the configuration, based on the type of BootConfig. 2N/A """Returns the directory where configuration files are stored. 2N/A """Load the menu configuration file and read bootloader properties 2N/A and boot instances from it. Autogenerate boot instances from the BEs 2N/A on the system. Returns True if boot instances were autogenerated (and 2N/A therefore the MenuConfigParser was updated). 2N/A # merge in properties from the config file: 2N/A # Add the boot instances to the BootConfig instance: 2N/A """Part of upgrade support: Correct splash image extension if 2N/A # BootLoader install() hooks 2N/A # (or temporary equivalent for non-Disk BootConfigs) file (from the global 2N/A # properties) and the rest of the menu.conf is used by the GRUB2 2N/A """Generates the grub.cfg file(s) for GRUB2. Different approaches are 2N/A taken depending on the type of BootConfig this BootLoader is associated 2N/A with. For DiskBootConfig, we update the 2N/A exec()ing grub-mkconfig to do the actual file generation. For 2N/A ODDBootConfig and NetBootConfig, we create the grub.cfg by hand (since 2N/A the autogeneration scripts put system-specific GRUB2 commands into the 2N/A generated configuration file.) 2N/A msg = (
'Cannot _write_config(%s) - _boot_config is None' %
2N/A # Determine the type of boot configuration we're dealing with, then 2N/A # call the tailored _write_config_<bootconfig_type> method. 2N/A """Returns a list of firmware targets that this BootLoader must 2N/A handle at install()-time. 2N/A """To generate the grub.cfg file, we invoke the grub-mkconfig 2N/A command. Before doing that, we need to create the grub2_defs.$FW 2N/A file, which consists of a number of environment variables whose 2N/A values are derived from the BootLoader properties. Once that file is 2N/A created, we must store the menu organizer's state (the menu.conf) 2N/A then we can invoke grub-mkconfig (since the Solaris autogenerator 2N/A # assemble_other_grub_files must be done before the grub.cfg is 2N/A # generated, as grub-mkconfig looks for specific files that 2N/A # assemble_other_grub_files copies. 2N/A """Write the menu.conf file to the system location if basepath is None. 2N/A Creates directories as needed. 2N/A May raise BootmgmtConfigWriteError if there was a problem creating 2N/A # We need to return 2 tuples -- one for the menu.conf and one 2N/A # If final_path is None, do not generate a tuple for menu.conf 2N/A '%s for BootConfig class %s' %
2N/A # pylint: disable=R0913 2N/A """Generates a stub file that sources the parent dir's file of the 2N/A same name. This is suitable ONLY for DiskBootConfig and ODDBootConfig. 2N/A Returns a tuple if basepath is not None. 2N/A # pylint: enable=R0913 2N/A """Generate the GRUB2 script code for the video driver load 2N/A """Generates the stub config files for the platform-specific config 2N/A 'set multiboot=%s\n' 2N/A 'if [ -s %s ]; then\n' 2N/A """Create and populate the grub.cfg file""" 2N/A # Before we can invoke grub-mkconfig, we need to transform 2N/A # the boot loader properties into a grub defaults file, 2N/A # then set the BOOTMGMT_GRUB2_DEFAULTS environment 2N/A # variable to its path. (The grub-mkconfig program will source 2N/A # file if the environment variable is set.) 2N/A # The resulting grub.cfg from _internal_mkconfig is designed 2N/A # to work on all targets 2N/A # pylint: disable=R0912 2N/A """Writes the grub.cfg file to the appropriate location. If 2N/A defs_dict is not None, internal grub-mkconfig is used. 2N/A # pylint: enable=R0912 2N/A """Returns the token to use when constructing tuples returned from 2N/A """Moves the temporary grub.cfg.new to grub.cfg. 2N/A # Move was successful, so now set the owner and mode properly: 2N/A # pylint: disable=R0912 2N/A """Invokes grub-mkconfig and directs its output to the outfile. 2N/A 'Generating %s boot loader configuration files' %
target,
2N/A # pylint: enable=R0912 2N/A # pylint: disable=R0914 2N/A """Generate the GRUB2 defaults file either in the specified 2N/A path or in the system location. Returns the path to the defaults 2N/A file. This is suitable only for DiskBootConfig. 2N/A May raise BootmgmtConfigWriteError if there was a problem creating the 2N/A defaults file (or its parent directory). 2N/A # pylint: enable=R0914 2N/A """Generate a dict with gfxterm defaults. 2N/A # If splash is None, the property does not exist, so use a 2N/A # We have to get the basename of the splashimage because 2N/A # we know it will be copied into the config_dir. 2N/A # If fore is None, the property does not exist, so use a default 2N/A # If back is None, the property does not exist, so use a default 2N/A # The background color must have a 0 alpha so the 2N/A # splash image comes through. 2N/A # If a theme is to be used, it was previously copied into the 2N/A # proper place in _assemble_other_grub_files(). If theme_grub_path 2N/A # is non-None, use it to set the GRUB_THEME_DIRECT property; if 2N/A # theme_os_path is set, use it to set the GRUB_THEME property. 2N/A """Generate a dictionary with grub defaults pertaining to the console. 2N/A # Regardless of the type of the GRUB2 console, always set the video 2N/A # backend; Solaris uses a framebuffer console by default and GRUB2 2N/A # may be called upon to set the graphics mode. 2N/A # The gfxpayload modelist should be set regardless of the GRUB2 2N/A # console type also, since we may have Solaris instances that use 2N/A # framebuffer console that need this variable set in a specific 2N/A # part of the menu entry 2N/A # 'console' is the default GRUB2 input terminal type. gfxterm 2N/A # is the default output terminal type if none are specified. 2N/A """Generate a dictionary of grub default keys and their values. 2N/A defdict[
'GRUB_HIDDEN_TIMEOUT'] =
'true' # Must be lower case 2N/A # Set the default entry based on the list of default boot instances 2N/A """Convert a string of hex digits into a GRUB2 color specification. 2N/A """Convert the serial parameters property tuple into a GRUB2 serial 2N/A command. If params is None, the default serial command is used. 2N/A The form of the serial_params property is: 2N/A serial_params | A tuple containing (<portspec>,<speed>,<d>, 2N/A | <portspec> is currently defined to be a 2N/A | number (valid values depend on the platform, 2N/A | but '0' is ttya (com1) and '1' is ttyb (com2)). 2N/A | Serial console parameters (<d>=data bits, 2N/A | <p>=parity ('N','E','O'),<s>=stop bits ('0','1'), 2N/A | <f>=flow control ('H','S',None) for hardware, 2N/A | software, or none). The default is: 2N/A | ('0',None,None,None,None,None). 2N/A # If the port number is larger than 0xFF, assume it's an 2N/A # IO port number and use --port instead of --unit: 2N/A """Copy all files associated with the theme whose theme 2N/A file is specified into the proper location. Returns a 3-tuple of 2N/A (1) tuples (if basepath is set) (or None if not), and (2) 2N/A the *GRUB path* to the theme_file (the GRUB path will be used 2N/A directly in the grub.cfg file) and (3) The OS path to the 2N/A self.
_debug(
'THEME: src=%s, theme=%s, theme_bn=%s, grub_path=%s ',
2N/A "dirnm is the source theme's directory" 2N/A 'root',
'bin',
0644)
2N/A # We're doing a directory copy of an entire theme. If the 2N/A # destination exists, blow it away first, or the copytree will fail: 2N/A # Iterate through the source directory, using collect_tuples to 2N/A # collect the list of file tuples returned to the caller. 2N/A # The OS path to the theme file is the destination path 2N/A return None,
None,
None 2N/A # If the source directory does not exist, but the destination DOES, 2N/A # check to see if the theme file exists, and if it does, just use the 2N/A # existing theme in the destination. This covers the case where 2N/A # pybootmgmt is used in conjunction with a data source that does not 2N/A # include the specified theme. 2N/A # The OS path to the theme file is the destination path 2N/A # We're doing a directory copy of an entire theme. If the 2N/A # destination exists, blow it away first, or the copytree will fail: 2N/A return None,
None,
None 2N/A """Copy other needed GRUB2 files into the proper location. 2N/A Return the appropriate tuples (if basepath is set). 2N/A # Assemble the theme files, if necessary 2N/A # theme name alphanumeric validation was done in BootLoader 2N/A else:
# No theme property, so default to enable themeing with 2N/A # the default theme. 2N/A # If this is the default theme and we hit an error, quietly 2N/A # revert to non-themed graphical menus. 2N/A """Using the list of 3-tuples passed in file_tuples, copy those files 2N/A to proper destination with the proper modes. This is suitable for 2N/A DiskBootConfig and ODDBootConfig only. 2N/A # If perms is None in the 3-tuple 2N/A """A stripped-down barebones implementation of a GRUB2 menu generator. 2N/A First, a set of header script code is emitted (its contents depends on 2N/A the values in the defs_dict (a dict representation of the 2N/A correspond to the boot configuration's boot_instances list. 2N/A """Returns the list of lines in the script preamble stored in 2N/A the definitions dictionary passed in. 2N/A # pylint: disable=R0912 2N/A """Output the grub.cfg header for this target based on the defs_dict. 2N/A # If there is a preamble specified in the defs_dict, add that first: 2N/A # First, output the script for initializing the console device(s): 2N/A # load_video_$target is defined in the stub grub.cfg files (or the 2N/A # grub.cfg directly for NetBootConfig). 2N/A # NOTE: We always load video drivers because Solaris may need it 2N/A # for framebuffer console. 2N/A # Initting gfxterm must be done after all other console devices 2N/A # are initted because the terminal_output statement is embedded 2N/A # in the gfxterm init script block. 2N/A # Now add the timeout and quiet script: 2N/A # finally, the default: 2N/A """Return a list of lines that init the specified terminal device 2N/A # The caller knows that gfxterm must be the last console device 2N/A # processed (due to the use of terminal_output statements) 2N/A # We have several potential properties to handle here: 2N/A # GRUB_VIDEO_BACKEND, GRUB_BACKGROUND, GRUB_FORECOLOR, and 2N/A # Add GRUB theme dependencies here: 2N/A # Emit module load lines for all required modules: 2N/A # If loading the default font fails, it's not fatal 2N/A # Add the font-load conditional statement: 2N/A # XXX - Revisit the hard-coded font path here? 2N/A # fore/back color must be set BEFORE the background image 2N/A # Loading the background image requires us to first load 2N/A # modules needed to access the filesystem on which it's stored 2N/A # Close the conditional 2N/A if need_fi:
# If we need a fi (if theme code was emitted above) 2N/A # pylint: enable=R0912 2N/A """To generate the grub.cfg file for an ODDBootConfig, we create the 2N/A menu by hand (we do NOT use the grub-mkconfig program). 2N/A # It doesn't matter which target's defs_dict we use here 2N/A # because _generate_grub_cfg is guaranteed to generate a 2N/A # config file without direct target-specific code (there may 2N/A # be references to things defined in the target-specific stubs 2N/A # The stub files are the small script files that do target-specific 2N/A # things, then source the main config file 2N/A """To generate the grub.cfg file for a NetBootConfig, we create the 2N/A menu by hand (we do NOT use the grub-mkconfig program). Since we will 2N/A not use a graphical console while network booting, we do not need 2N/A to assemble other files (i.e. GRUB2 font files and splash screen image). 2N/Aregexp ".*/(.*)" $prefix -s 1:target 2N/Atr -s target - _ "$target" 2N/Aif [ -z "$target" -o "$target" = "%(bios)s" ]; then 2N/A set multiboot=multiboot 2N/Aelif [ "$target" = "%(uefi64)s" ]; then 2N/A set multiboot=multiboot2 2N/A # Generate the target def dictionaries and the video driver load 2N/A # code so we can use them in the loop below. 2N/A # It doesn't matter which target's defs_dict we use here 2N/A # because _generate_grub_cfg is guaranteed to generate a 2N/A # config file without direct target-specific code. 2N/A # Elide the final stanza that searches for the custom.cfg -- 2N/A # we have no use for it in a network boot scenario. 2N/A # Add the script preamble, which establishes the platform 2N/A # on which the script is executing and sets some key variables 2N/A # that the generated grub configuration file uses. 2N/A # The grub_cfg tuples must be marked specially, so that 2N/A # the consumer knows that they can be placed in the 2N/A # tftp boot loader search path 2N/A # Override install so we can update the UEFI boot variables with the 2N/A # device list passed in. Failure to set the boot variables is NOT a 2N/A # fatal error; it will, however, be logged to syslog. 2N/A # No need to go further if we have tuples to return (no install 2N/A # was done to an actual device) or if location is empty 2N/A # If this is not a disk-based boot configuration, or if there were 2N/A # tuples returned from the main install() method (which implies we 2N/A # did not install onto actual physical devices) or if the system 2N/A # firmware is not UEFI, just return the tuple_list, if any. 2N/A 'device to %s. Manual intervention may be required ' 2N/A """Write the GRUB2 boot loader to disk. We support 4 scenarios: 2N/A (1) BIOS systems, installation onto a DOS-partitioned disk with 2N/A a Solaris partition -- boot loader is embedded in the Solaris 2N/A boot slice (usually slice 8, but really it's any slice that 2N/A includes cylinder 0). The devname passed in can be directly 2N/A passed to grub-install, as grub-setup has been modified to write 2N/A the loader to the appropriate place in the Solaris partition; 2N/A (2) BIOS systems, installation onto a GPT-partitioned disk. A 2N/A BIOS Boot Partition (BBP) is required. The devname passed in 2N/A refers to the partition that includes the ZFS, not the BBP, so 2N/A we need to figure out if we're on a GPT-partitioned disk, and 2N/A pass the whole-disk node (p0) to grub-install so *IT* can 2N/A locate the BBP and install GRUB2 there; 2N/A (3) UEFI systems, installation onto a DOS-partitioned disk. The 2N/A device node refers to a VTOC slice, so we need to get the device 2N/A node for the EFI System Partition, mount it (if it's not already 2N/A mounted), and invoke grub-install, telling it to install the EFI 2N/A (4) UEFI systems, installation onto a GPT-partitioned disk. 2N/A # The prefixdir MUST exist, otherwise grub-install will fail: 2N/A # We need to derive the EFI System Partition from the device 2N/A # passed in, mount it (if it's not already mounted), and pass 2N/A # the mountpoint as the instdev 2N/A # If there was a problem trying to determine if the ESP is 2N/A # already mounted, proceed anyway -- we'll fail during the 2N/A # mount if it was already mounted. 2N/A 'a temporary dir for mounting the ESP',
ioerr)
2N/A ' is not supported')
2N/A 'Boot loader installation')
2N/A # If we're not able to install the bootloader due to 2N/A # incompatibility between the GRUB2 utilities and the modules 2N/A # from the data directory, begin the deferred boot loader 2N/A # activation process by creating the required file in the 2N/A # root directory of the data_root. 2N/A 'GRUB2 boot loader and unable to create required ' 2N/A 'GRUB2 could not be installed at this time. The GRUB2 ' 2N/A 'utilities on the root filesystem are older than (and ' 2N/A 'incompatible with) the GRUB2 modules in %s. ' 2N/A 'The new version of GRUB2 will be installed automatically ' 2N/A 'when booting the Solaris instance in which the new GRUB2 ' 2N/A 'default boot location -- ignoring')
2N/A # Final sanity check 2N/A """Copies GRUB2 modules (and config files) to a directory under 2N/A basepath. Returns a list of tuples, each of which describes one of the 2N/A files copied. This is suitable for DiskBootConfig and ODDBootConfig 2N/A # No additional modules for netboot images -- everything is baked 2N/A # Iterate through all files in the modpath directory, excluding ones 2N/A # that are in the exclusion_list: 2N/A # We're only interested in *.img, *.mod, *.lst and efiemu* 2N/A 'root',
'root',
0644))
2N/A """Construct the bootable grub2 image for the specified target. The 2N/A boot image is BootConfig-specific (BootLoaders associated with 2N/A ODDBootConfig instances get BIOS-targeted El Torito images and UEFI64- 2N/A targeted FAT filesystem images with embedded UEFI64-targeted boot 2N/A applications (suitable for direct inclusion in an ODD image); 2N/A NetBootConfig boot loaders get BIOS PXE images and UEFI64 net boot 2N/A application images). 2N/A # microconfigs are needed even on BIOS targets, since the resulting 2N/A # image is used to build a USB image, where we will need to search. 2N/A """Create an El Torito image by invoking grub-mkimage with the proper 2N/A parameters, then prepending the result with cdboot.img. 2N/A # Write the image to 'core.img', as that's where we'll look for it 2N/A # if we want to repurpose the ISO to make other bootable media 2N/A modlist = [
'biosdisk',
'iso9660',
'part_msdos',
'part_sunpc',
2N/A # Finally, create the final file with cdboot.img prepended to the 2N/A # image we just created. 2N/A None,
None,
None,
None,
None),
2N/A 'root',
'root',
0644)]
2N/A """Create a GRUB2 boot image for the specified target, named imagename, 2N/A with modlist modules embedded and preloaded. If microconfig is not 2N/A # Now we can remove the temporary memdisk image file: 2N/A """Create a "tarfs" (tar file) with the microconfig specified. The 2N/A microconfig specified is the parent directory -- there must be a 2N/A # Change into the directory that includes microconfig. This is 2N/A # required so that we can generate the tarfile that includes it. 2N/A # We change back to the original directory in the finally clause, 2N/A # pylint: disable=R0912,R0913,R0914,R0915 2N/A # Set up the stderr/out pipes to be non-blocking so we can read 2N/A # from both without blocking. 2N/A '%s returned error code %d. stderr was:\n%s' %
2N/A # pylint: enable=R0913 2N/A """Create a FAT filesystem image that contains a GRUB2 boot application 2N/A (constructed by grub-mkimage) suitable for 64-bit UEFI systems. If a 2N/A microconfig file is specified, it is embedded into the image via the 2N/A -c argument to grub-mkimage. 2N/A """Perform a cleanup of activities in LIFO order 2N/A # pylint: disable=W0702 2N/A # pylint: enable=W0702 2N/A # Make a temporary directory that will be used to hold the image: 2N/A # gzio must be in the list before normal because normal attempts 2N/A # to grub_dl_load(gzio) very early in GRUB startup (before $prefix 2N/A # is set) so the net result would be an error message from 2N/A # grub_dl_load() that $prefix is not set. We use gzio for the 2N/A # Solaris boot archive, so we might as well load it now anyway. 2N/A modlist = [
'iso9660',
'part_msdos',
'part_sunpc',
'part_gpt',
'ufs1']
2N/A # Create the image with a size that will fit the boot image and 2N/A # filesystem metadata 2N/A # Associate the image with the lofi device 2N/A # Create a pcfs filesystem on the lofi device 2N/A # Create a temp dir to use as a mountpoint 2N/A # Mount the pcfs filesystem just created 2N/A # Create the EFI/BOOT directory that will hold the boot image 2N/A # Copy the image onto the mounted pcfs filesystem 2N/A # Unmount the pcfs filesystem 2N/A self.
_debug(
'Removing temp mount dir for uefi64 image failed: %s',
2N/A # Remove the lofi association 2N/A # Remove the boot image temporary file and temp dir 2N/A None,
None,
None,
None,
None)]
2N/A # pylint: enable=R0912,R0914,R0915 2N/A """Copies the NBP program for the specified target to the specified 2N/A path. Raises BootmgmtConfigWriteError if the copy failed. 2N/A # pylint: disable=W0613 2N/A """Create a GRUB2 image bootable via the PXE on systems with BIOS 2N/A # For now, do not create the image-- just use the one delivered 2N/A # into the installation image. 2N/A """Create a GRUB2 UEFI boot application image bootable via the native 2N/A UEFI network boot mechanism. 2N/A # For now, do not create the image-- just use the one delivered 2N/A # into the installation image. 2N/A # pylint: enable=W0613 2N/A """Create a small configuration file whose purpose is one: 2N/A (a) to locate the REAL root device (since the microconfig file will 2N/A be loaded from a memdisk baked inside the GRUB2 image), or (b) to 2N/A source the REAL configuration file (i.e. when booting from the network, 2N/A the microconfig contains the GRUB2 script that searches the tftp 2N/A hierarchy, in accordance with the Solaris-defined search order for 2N/A the GRUB2 configuration file.) 2N/A # Future enhancement: Generate the GRUB2 NetBootConfig microconfig 2N/A # here by using the script delivered to the install image, making 2N/A # sure to set prefix to a directory whose last component is the 2N/A # platform name (that means that _grub2_mkimage_generic must be 2N/A # modified also to parameterize the --prefix argument given to 2N/A 'not supported for class %s' %
2N/A # The microconfig file must be stored in a temp dir, under 2N/A # boot/grub, since that's where the image construction commands 2N/A # will be told to find it (prefix will be set to 2N/A # Return the parent dir holding the config file 2N/A """Create directories for dirname(basepath). 2N/A May raise BootmgmtConfigWriteError if there was a problem creating the 2N/A """Create directories for path. 2N/A May raise BootmgmtConfigWriteError if there was a problem creating the 2N/A """GRUB2MenuOrganizer includes shared code between the GRUB2 pybootmgmt 2N/A Methods are provided to get an ordered list of boot instances from the 2N/A system (via the autogen backend (which gets the list of BEs and 2N/A generates a boot instance for each BE) if none exist in the menu.conf) and 2N/A the rest from the menu.conf, which has sections for each customized boot 2N/A instance (and, therefore, menu entry)) and to synch a list of boot 2N/A """Constructor for GRUB2MenuOrganizer 2N/A """Pseudoproperty returns True of the underlying MenuConfigParser is 2N/A """Start over with a new (empty) menu configuration 2N/A """Returns a dictionary of properties from the global section of the 2N/A """Load the menu.conf file and processes the sections, generating 2N/A BootInstance objects and returning the list to the caller. 2N/A # The total number of boot instances added to the BootConfig instance 2N/A # stored in self._boot_config is equal to the number of BE sections 2N/A # in the menu.conf file (including the transient entry, if it exists). 2N/A # If there are no BE sections, the autogenerator is used to populate 2N/A # If an explicit ordering is specified in the menu configuration 2N/A # file, rearrange inst_list and return it. 2N/A # If no instances are present, generate instances for the BEs 2N/A # Now inst_list has the full set of boot instances 2N/A """Given a list of boot instances and a boot loader properties dict, 2N/A synchronize the underlying MenuConfigParser in preparation for writing 2N/A # First update the properties in the [global] section 2N/A # Loop through all boot instances, keeping track of the order 2N/A # for the order property, and synchronizing the menu entry with the 2N/A # Filter out Solaris boot instances that refer to deleted BEs 2N/A # (this is only possible if the boot instance has a bootfs 2N/A # Synch boot instance to custom entry: 2N/A # Check if this class has a corresponding emitter in 2N/A # the GRUB2MenuEntryEmitter class. If it does not, 2N/A # Remove sections in the menu.conf file that correspond to deleted boot 2N/A # instances (i.e. all those not in the order_list) 2N/A """Loads the menu configuration file. 2N/A # This will succeeds either if the menu.conf is loaded successfully, 2N/A # or if the menu.conf is not present. In the latter case, an empty 2N/A """Save the menu configuration to stable storage. 2N/A """Convert boot instance to a dictionary suitable for serialization 2N/A in the menu.conf file. The bulk of the work is performed by methods 2N/A tailored for each type of BootInstance. 2N/A """Convert a propdict from a menu.conf section into a boot instance. 2N/A The type of BootInstance is given by the string section_type. 2N/A # Make a copy of the properties from the section and remove the 2N/A # 'modified' attribute, since it has nothing to do with creation 2N/A # of a boot instance: 2N/A # The default property must be a bool, else we get an exception 2N/A # at BootInstance construction time. 2N/A # Add the platform value from the associated BootConfig so that 2N/A # the BootInstance is properly initialized. 2N/A # BootInstance instantiation takes a path as the first parameter 2N/A # and **kwargs for all others. 2N/A # pylint: disable=W0142 2N/A # pylint: enable=W0142 2N/A """Copy properties from the boot instance to the MenuConfigEntry 2N/A """Rearranges the boot instance list passed in to match the order 2N/A specified. The boot_instances list is modified in place. 2N/A # The explicit_order list contains strings that are of the forms: 2N/A # '<classtype>|<index>'. Note that if the explicit order list is 2N/A # incomplete, order is undefined for other entries. If a boot 2N/A # instance is referenced in the explicit order list, but it doesn't 2N/A # exist on the system, that order entry is ignored 2N/A if inst is None:
# Skip instance slots marked with None 2N/A # Each instance in the instance list is guaranteed to have 2N/A # a _menu_conf_entry, so there is no need to use getattr here. 2N/A # pylint: disable=W0212 2N/A # Found a match -- add the instance to the temp list 2N/A # and mark the slot in boot_insts so we don't duplicate 2N/A # pylint: enable=W0212 2N/A if not found:
# the order property is out of date! 2N/A # Now update boot_instances with the ordered_list first: 2N/A # Then any leftover instances that were not specified explicitly. 2N/A # Note that the relative order of these unmatched instances is 2N/A """Builds a list of boot instances, each of which corresponds to a 2N/A # Ignore entries with sections whos names are tuples with <> 2 2N/A # Store the menu.conf entry this boot instance was created from 2N/A # for later use (i.e. sorting, etc.) 2N/A """Escape a menuentry title. In addition to the regular escapes, 2N/A '>' must be escaped (replaced with '>>'). 2N/A """Escape a string so it evaluates to its raw value in grub.cfg. 2N/A # Quotation marks must be escaped, as must backslashes 2N/A """Emits GRUB menuentry blocks for the grub.cfg file. 2N/A """If fileobj is None, STDOUT is used. vardict is the dictionary 2N/A that holds variables that may be used by the menu entry 2N/A generators. If it's None, os.environ is used. If force_grub2 is 2N/A True, we instantiate the BootConfigs with a loaderclass keyword arg 2N/A to ensure we get the BootInstances from GRUB2 and not a different 2N/A (perhaps higher-ranked) BootLoader, whose BootInstances may be in 2N/A the BootConfig's boot_instances list. 2N/A """Caches zpool properties used by the menu generator methods. 2N/A # The GRUB2 guid for a zfs pool is a straight hex conversion-- 2N/A # there are NO dashes, but there ARE leading zeroes! 2N/A """Emit entries to the fileobj specified in __init__. This should only 2N/A be invoked when this class is instantiated by the GRUB2 autogen script. 2N/A # Filter out entries that managed to exist despite 2N/A # referring to a nonexistant BE: 2N/A # Emit code to check for the presence and nonzero size of 2N/A # a GRUB Legacy configuration file. If it exists, extract 2N/A # the entries into a submenu. 2N/A '\t\t\textract_legacy_entries_source "$2"\n')
2N/A """Call the BootInstance-specific function to emit a menuentry block 2N/A # If the boot instance is target-specific, emit code that causes 2N/A # GRUB2 to only process the menu entry when running on that target. 2N/A self.
_debug(
'Not emitting entry for instance type %s (title=%s)',
2N/A """Returns a string containing the search command to use for the 2N/A # pylint: disable=C0103 2N/A """Emits a menuentry for a Solaris network boot instance. 2N/A # If the parent boot configuration isn't a NetBootConfig, we'll need an 2N/A # explicit load of the network driver. 2N/A # Net boot instances frequently have $ strings embedded in the 2N/A # kernel arguments. If any are found, escape them from the grub2 2N/A # pylint: disable=W0613 2N/A """Emits a menuentry for a ODD-based Solaris instance. 2N/A # If the parent boot configuration isn't on an ODD, we'll need an 2N/A # explicit load of iso9660. 2N/A # pylint: disable=W0212 2N/A """Custom emitter for a SolarisDiskBootInstance 2N/A # Cover all bases by loading part_msdos, part_sunpc, and part_gpt 2N/A # If the BootConfig that this boot instance is a member of is a 2N/A # disk boot config (i.e. we invoked grub-mkconfig to generate the 2N/A # grub.cfg file) AND the console type of this BootConfig is NOT 2N/A # graphical, then we need to manually add a call to load_video 2N/A # (the body of which is emitted by the 00_header script). This is 2N/A # essential so that GRUB can find and set graphics modes for Solaris 2N/A # instances that use framebuffer console. 2N/A # Common code for the remainder of the entry: 2N/A # pylint: enable=W0613 2N/A """Returns a search command string that includes the identifying file 2N/A from either the bootinst (tried first) or boot_loader. 2N/A # If the boot instance specifies a identifying file, use it to 2N/A # Fall back on the boot loader's identifying file to find $root 2N/A """Generic code for finishing a Solaris boot instance's menuentry 2N/A # Only 64-bit is supported, so replace the format-string here: 2N/A # If the kernel specified has another path prepended, ensure 2N/A # that the second parameter to multiboot[2] is the boot-archive- 2N/A # relative kernel path. 2N/A """Checks if the specified dataset (or implied dataset) has encryption 2N/A enabled, and if so, emits the proper commands to prompt for and set 2N/A the zfs key. Returns True if the dataset is encrypted. 2N/A """Handle the ZFS-specific part of menuentry generation. Returns the 2N/A kargs to use in the entry. 2N/A else:
# No bootfs -- check for rpool 2N/A # If this is an encrypted dataset, prompt user for the password 2N/A # pylint: disable=W0613 2N/A """Custom emitter for a ChainDiskBootInstance 2N/A # GRUB2 uses 1-based partition indices 2N/A # Special case -- use of letters: GRUB2 does not 2N/A # support using letters to access VTOC-labelled drives 2N/A # so convert the letter into a numerical index 2N/A # GRUB2 uses 1-based partition indices 2N/A # pylint: enable=C0103,W0212,W0613 2N/A """Returns a list of boot loader classes, consumed by the boot loader