iVc@s^dZddlZddlZddlZddlZddlZddlZddlZddlZddl j Z ddl Z ddl Z ddlZddlZddlZddlZddlZddlmZmZmZmZmZmZmZmZmZddlmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'ddl(m)Z)m*Z*ddl+m,Z,m-Z-m.Z.m/Z/m0Z0ddl1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:ddl;m<Z<dd l=m>Z>dd l?m@Z@mAZAd ZBd ZCd e)fdYZDde3fdYZEde3fdYZFdZGdS(s* GRUB2 boot loader backend for pybootmgmt iN( t BootmgmtErrortBootmgmtArgumentErrortBootmgmtConfigReadErrortBootmgmtConfigWriteErrortBootmgmtNotSupportedErrort!BootmgmtUnsupportedOperationErrort BootmgmtUnsupportedPropertyErrort BootmgmtUnsupportedPlatformErrortBootmgmtInterfaceCodingError( t libzfs_initt libzfs_finit zpool_opent zpool_closetzpool_get_proptZPOOL_PROP_GUIDt is_gpt_diskt mnttab_opent getmntanyt mnttab_close(t BootLoadertBootLoaderInstallError(t BootConfigtDiskBootConfigt ODDBootConfigt NetBootConfigtSolarisDiskBootInstance( tget_current_arch_stringt LoggerMixint bootfs_splitt parse_booltfind_efi_system_partitiontget_zpool_default_bootfstis_zfs_encrypted_datasettwrite_temp_filetget_bootfs_list_from_libbe(tSystemFirmware(tAuthConfigParser(tMenuConfigEntrytMenuConfigParseris$C12A7328-F81F-11D2-BA4B-00A0C93EC93BtGRUB2BootLoaderc BsleZdZdZidzd6Zejejejej ej ej ej ej ejg Zidd6dd6Zidd6dd6Ziejjedd edd6ejjedd edd6Ziedjd d d6edjd d d6Zd d gZied6ed6Zidd6dd6Zidd6dd6ZdZdZdZdZdZ dZ!dZ"d{Z#dZ$dZ%e$de%Z&dZ'ejjeddZ(e(e'Z)idd6dd6d d 6d!d!6Z*d"gZ+ejjedd#d$d|fd}gZ-id'd6d(d6Z.d)Z/d*Z0d+Z1dZ2d,Z3dZ4d-Z5d.Z6d/Z7d0Z8d1Z9id2d6d3d6Z:dZ;d&Z<d6Z=d7Z>d8Z?d9Z@eAd:ZBeAd;ZCeAd<ZDeAd=ZEeAd>ZFeAd?ZGeAd@ZHeAdAZIeJdBZKdCZLdDZMdEZNeOdFZPdGZQd|dHZRd|dIZSd|eTdJZUd|dKZVdLZWdMZXdNZYdOZZdPZ[d|eTeTdQZ\e]dRZ^d|d|dSZ_dTZ`d|dUdVZadWZbdXZcdYZddZZed[Zfd\Zgd]Zhd^Zie]d_Zjd`ZkdaZldbZmdcZnddZoe]deZpdfZqeOdgZrdhZsdiZteTd|d|djZudkZvdlZwdmZxdnZyd|doZzdpZ{d|d|d|d|eTeTd|dqZ|drZ}dsZ~dtZduZdvZdwdxZe]dwdyZRS(sNImplementation of the BootLoader interface for the GRUB2 boot loader. itbiostuefi64tx86susr/lib/grub2/biossusr/lib/grub2/uefi64si386-pcs x86_64-efis lib/grub/t-t_tminicmdtreboottvbetefi_gopsC1024x768x32;1024x768x16;800x600x16;640x480x16;640x480x15;640x480x32ssbin/grub-installssbin/grub-mkconfigsbin/grub-mkimagesbin/grub-mkpasswd-pbkdf2is.boot_loader_update_requiredtrootis boot/grubtthemest/tsolarissshare/grub/themes/%s/theme.txttjpegtjpgtpngttgatpf2sshare/grub/unicode.pf2s unicode.pf2sboot/grub/splash.jpgs splash.jpgsboot/grub/pxegrub2sboot/grub/grub2netx64.efiscore.imgs custom.cfgsgrub.cfgs menu.confs grub2_defs.%ss auth.confisauth.cfgis boot/bios.imgs boot/uefi.imgiiit343434tF7FBFFs grub.pbkdf2cKs'|jd}|dks*|jdkr.dS|jtjkr`tdkr`|jddS|jtjkr|jdk rt j |S|jtj krt j |S|jtjkry|j ||jdWn$tk r}|jd|dSXt j|Std|jdS(s%Probe for GRUB2 on a system. t bootconfigR*s0GRUB2 boot loader not supported on this platformtfwtypes#[PROBE ABORTED DUE TO EXCEPTION] %ssBoot class %s not supportedN(tgettNonet boot_classRtBOOT_CLASS_NETRt_debugtBOOT_CLASS_DISKt boot_fstypeR't _probe_disktBOOT_CLASS_ODDt _probe_oddt_validate_platform_and_firmwareRt _probe_netR(tclstkwargsR<tbmerr((s-../../common/bootmgmt/backend/loader/grub2.pytprobes,     cKs|jd}|j}|jd|tjj|jddtjj|jddtjj|jddg}y|j||Wntk rdSXt |S(s]This GRUB2 probe function searches the ODD's root, looking for the GRUB2 core modulesR<sodd_image_root=%sR(s cdboot.imgs kernel.imgR)N( R>tget_rootRBtostpathtjointGRUB_DATA_PATHSt_probe_genericRR?R'(RJRKR<R1todd_data_probe_list((s-../../common/bootmgmt/backend/loader/grub2.pyRGs"         cKs<|jd}tj|}|s(dS||dR't_probe_artifacts_netR?(RJRKR<RU((s-../../common/bootmgmt/backend/loader/grub2.pyRIs  cKs<|jd}|j|}|s(dS||dt_probe_artifacts_diskR?R'(RJRKR<RU((s-../../common/bootmgmt/backend/loader/grub2.pyREs  cCs|dkrtdnyJxC|D];}tjj||}|jd|t|jq%WWn"tk r}td|nXdS(s*Generic probe function for GRUB2. sdataroot is NonesProbing for %ss#IOError when checking for datafilesN( R?RRORPRQRBtopentclosetIOError(RJtdataroott datafilestdatafiletfpathtioerr((s-../../common/bootmgmt/backend/loader/grub2.pyRS!s  cCsg}|j}|jd||jftjdtjdg}tjj|jtj|j }yGtj |}t j |j r|j dkr|tjg7}nWntk rnXy4|j|||tjg7}|tjg7}Wntk r nX|S(sLooks for the menu.conf and the NBPs. There are no "tools" needed for NetBootConfig. The images are preassembled. s#net_image_root=%s, net_data_root=%sR(R)i(RNRBt net_data_rootR'tGRUB_NBP_PATHSRORPRQtMENU_CONF_BASENAMEt pxe_suffixtstattS_ISREGtst_modetst_sizeRtARTIFACT_BOOTLOADER_CONFIGFILEStOSErrorRStARTIFACT_BOOTLOADER_IMAGEStARTIFACT_BOOTLOADER_TOOLSR(RJR<RUR1tnet_data_probe_listt menu_conft stat_info((s-../../common/bootmgmt/backend/loader/grub2.pyRV2s,    !  cCst|dd}|r'|j}n |j}|jdkrK|}n2|jdkrf|j}n|jd|jgStjj |s|jdgS|jd||fg}yetjj |t j t j }tj|}tj|jr |jdkr |tjg7}nWn5ttfk rX}|jd|t|fnXtjj |jd d tjj |jd d tjj |jd d g} y$|j|| |tjg7}Wn)tk r}|jd t|nXtjdj} | d krtjj |jd dtjj |jd dtjj |jd dtjj |jd dg} nt| d krtjj |jd dtjj |jd dtjj |jd dg} n|jd| gSt} x| D]} yZtjj d| }tjj |oHtj!|tj"se|jd|t#} PnWqtk r}|jd|t#} qXqW| s|tj$g7}n|S(sBProbe for artifacts found when used with a DiskBootConfig t boot_loadertufstzfss%[PROBE FAILURE] Unknown filesystem %ssdataroot is not a directorysdataroot=%s cfgdataroot=%sisError while looking for %s: %sR(s diskboot.imgs kernel.imgR)s5Error while looking for GRUB2 kernel/loader files: %sssbin/grub-setupssbin/grub-probessbin/grub-installsbin/grub-mkimagesUnsupported firmware type: %sR3s%s not found or not executables'Error while looking for GRUB2 tools: %sN(%tgetattrR?t_get_boot_loader_data_rootRNRDtzfstopRBRORPtisdirRQR'tBOOT_GRUB_SUBDIRRbRdReRfRgRRhRitAttributeErrortstrRRRSRjRR#R>tfw_nametGRUB_PLATFORM_PREFIXEStFalsetexiststaccesstX_OKtTrueRk(RJR<t bootloaderR[t cfgdatarootRUtmenuconfRntexcpttdisk_data_probe_listtfwnametdisk_execs_probe_listt missing_toolstexecnametfull_exec_pathtoserr((s-../../common/bootmgmt/backend/loader/grub2.pyRWVs        !                           cCsB|jtjkr|j|S|jtjkr>|j|SgS(svReturns a list of artifacts for this BootLoader, given a bootconfig to use for directory information. (R@RRCRWRARV(RJR<((s-../../common/bootmgmt/backend/loader/grub2.pytprobe_artifactss   cCsM|jjtjkr|jS|jjtjkr>|jjSdtjSdS(NR3( t _boot_configR@RRCt_config_dir_diskRAR`R'Rv(tself((s-../../common/bootmgmt/backend/loader/grub2.pyt config_dirs   cKsg|_d|_tt|j|d|_d|_d|_d|_ |j j t j krtjj|jtj|_|j}|d}t|dkr|jdtj||fntjj|jtj|tj|_nt|j j t jkretjj|j jtj|j j|_tjj|j jtj|j j|_n|j j t j t jgkrtjj|jtj|_ t!|j |j|_"t#|j |_$nd|_"d|_$dS(s)Constructor for GRUB2 BootLoader tGRUB2iis'%s is %s: ONLY using %s as target valueN(%t pkg_namestnametsuperR't__init__R?t theme_os_pathttheme_grub_pathttheme_mods_setttheme_fonts_setRR@RRCRORPRQRRbt_menu_conf_patht_get_target_listtlenRBRtPROP_BOOT_TARGStGRUB_BOOT_SUBDIRStAUTH_CFG_BASENAMEt _authcfg_pathRAR`RctAUTH_CONF_BASENAMEt_authconf_pathtGRUB2MenuOrganizert _menu_orgR$t _auth_conf(RRKt target_listttarget((s-../../common/bootmgmt/backend/loader/grub2.pyRsD            cCs(d|_d|_d|_d|_dS(sEUninitialized all theme attributes (resets to default theme) N(R?RRRR(R((s-../../common/bootmgmt/backend/loader/grub2.pyt_clear_theme_states   cCstt|j|jjtjkr>tj|j tj t|t r>t|dkr>|S|jjgSdS(sgReturns a list of firmware targets that this BootLoader must handle at install()-time. iN(tgetpropRRRRRtfirmwareRy(Rttargets((s-../../common/bootmgmt/backend/loader/grub2.pyRs cCs|j|}|j||j}|d}t|dkrc|jdtj||fn|j|}|j||}|r|j ||j ||SdSdS(sTo generate the grub.cfg file, we invoke the grub-mkconfig command. Before doing that, we need to create the grub2_defs.$FW file, which consists of a number of environment variables whose values are derived from the BootLoader properties. Once that file is created, we must store the menu organizer's state (the menu.conf) then we can invoke grub-mkconfig (since the Solaris autogenerator plugin consumes the menu.conf file). Also write auth configuration file. iis'%s is %s: ONLY using %s as target valueN( t_write_menu_conft_write_auth_confRRRBRRt_assemble_other_grub_filest_generate_grub_cfgtextendR?(RRtmenu_conf_tuple_listRRtother_tuple_listtgrub_cfg_tuple_list((s-../../common/bootmgmt/backend/loader/grub2.pyRs       c Cs|j}|d}|rAtjj|tj|tj}n |j}|j||j d|yt |d}Wn"t k r}t d|n^X|j jr|jd|j jddn|j jrd}|j jr|j jd }|d t|d }n|d}|j|g|j jjD]$\} } d jd | | g^q@} |jd j| d n|jyBtj|tjtj|tjdjtjdjWn&tk r} t d|| nXdS(sKGenerate auth.cfg file to the system location if basepath is None. isWriting auth.cfg to %stwsError writing auth.cfgs set menulock=Rs sset superusers=t superuserst"t tpassword_pbkdf2s R1sCouldn't set mode/perms on %sN(RRORPRQR'RRRt _make_basedirRBRXRZRRRtwriteRRRxtitemsRYtchmodtAUTH_CFG_PERMStchowntpwdtgetpwnamtpw_uidtgrptgetgrnamtgr_gidRi( RRRRt authcfg_pathtauthCfgR_t write_strRtuserRtlinesR((s-../../common/bootmgmt/backend/loader/grub2.pyt_buildAuthCfgFromAuthConfsF            : cCsC|j}|d}|r=tjj|tj}t}nt}|j}|j ||j d||j j r|j jj|j j dkr9t|j _|j jjr|j||j jj}||j j d(Rtdef_dictttargnamet vidbackendt video_insmod((s-../../common/bootmgmt/backend/loader/grub2.pyt_generate_grub2_load_video_funcs c Cs&t|jtr6t|jdddkr6t}nt}tj|}d}|rj|j||}n|j drd}d}n d}d}d ||||f} |j |tj || d |} d |rd ndtj f} |j |tj |d | | ft} |r"| | gSdS(s\Generates the stub config files for the platform-specific config directory. RDRRqtuefit multiboot2tmodule2t multiboottmodules0set target=%s set multiboot=%s set module=%s %s Rs%s/boot/grub/%ss/@s!if [ -s %s ]; then source %s fi N( RRRRrRR{R'R$R)t startswithR"tGRUB_CFG_BASENAMEtCUSTOM_CFG_BASENAME( RRRR%RR&R(R-R.t grubscriptt stub_grub_cfgt custom_nametstub_custom_cfg((s-../../common/bootmgmt/backend/loader/grub2.pyt_generate_stub_filess8            cCsd}t}|jjtjkr|jjrS|jjtj d<|j dn|jj sdtj d<|j dqnzyf|r|j |||n<|j ||}|tj d<|j d|j|||jWn<tk r&ytj|jWntk rnXnXWdx|D]}tj |=q2W|r|rt|dt rytj|Wqtk rqXnXdS(s%Create and populate the grub.cfg filetBOOTMGMT_ZPOOL_LISTR{tBOOTMGMT_VALIDATE_BOOTFStBOOTMGMT_GRUB2_DEFAULTSNt preserve_defs(R?tlistRR@RRCt rpool_onlytzfsrpROtenvirontappendtvalidate_bootfst_internal_mkconfigt_generate_grub_defst_invoke_grub_mkconfigRYRtremoveRRiRrR{(RRRt defs_dictR!tgrub_defs_patht reset_envtenv_var((s-../../common/bootmgmt/backend/loader/grub2.pyt_generate_grub_cfg_files@            RcCsd}|r|jj}|tjkrgtj|}tjj|jj |}tjj||}qdtj dtj}tjj||d}n%tjj|j tj} | d}y |j |t |d} Wn9tk r} td|| ntk rnX|j|||| |r|j} | r[d| d} nd} | |jd7} tj|d | d d tjfgS|j||j|| d S( sWrites the grub.cfg file to the appropriate location. If defs_dict is not None, internal grub-mkconfig is used. RR3is.newRs4Error during grub.cfg generation: Couldn't create %ss%(s)s/R1N(RR@RRAR'R0RORPRQtnet_tftproot_subdirRvRRRRZRRIR tlstripRR?RR6t_move_temp_to_grub_cfg(RRRREt filesuffixt dest_pathR@t base_grub_cfgR tfinal_filenameR!R RR((s-../../common/bootmgmt/backend/loader/grub2.pyR3sL           cCsd}t|jtr`t|jdd}|dkrEtj}q|dkrtj}qnIt|jtr~tj }n+t|jt rt j }n |j d|S(s[Returns the token to use when constructing tuples returned from install(). RDRqRps,Unknown BootConfig type -- not using a tokenN( R?RRRRrtTOKEN_ZFS_RPOOL_TOP_DATASETRtTOKEN_SYSTEMROOTRtTOKEN_ODD_ROOTRtTOKEN_TFTP_ROOTRB(RRtfstype((s-../../common/bootmgmt/backend/loader/grub2.pyR hs      cCsy$tj|||jd|Wnitk r}ytj|Wn)tk rr}|jd||fnXtd||f|nXyBtj|t j tj |t j djtjdjWn&tk r}td||nXdS(s6Moves the temporary grub.cfg.new to grub.cfg. sgrub.cfg moved into place as %ss#Error while trying to remove %s: %ssCouldn't move %s to %sR1sCouldn't set mode/perms on %sN(tshutiltmoveRBRZRORDRiRRR'RRRRRRRR(RtsrcRR R((s-../../common/bootmgmt/backend/loader/grub2.pyRL|s$ cCsytjjdtj|tjdtjj|jtj|g}z"|j|d|d||Wd|j XdS(sEInvokes grub-mkconfig and directs its output to the outfile. R3s --prefix=%ss-Generating %s boot loader configuration filess%s grub.cfg generationN( RORPRQR'Rzt GRUB_MKCONFIGRRt _execute_cmdRY(RRR!t grub_mkconfig((s-../../common/bootmgmt/backend/loader/grub2.pyRCs    cCstjjdtj|tjg}y|j|ddtd|d}|jtj }|dkry|j dd S|j d}|dkr|j dd S|||!}|SWn|j dnXd S( s,Invokes grub-mkpasswd-pbkdf2 script R3s#Generating grub pbkdf2 for passwordt return_stdouttinputiis;Error generating pbkdf2 password using grub-mkpasswd-pbkdf2s N( RORPRQR'RztGRUB_MKPASSWORDRZRRRRBR?trfind(RRRtgrub_mkpasswd_pbkdf2tpwt start_indext end_index((s-../../common/bootmgmt/backend/loader/grub2.pyRs&          c Cs|r!tjj|tj}n |j}tjj|tj|}|j|yt|d}Wn"t k r}t d|nXx7|j |j D] \}}|d||fIJqW|j |S(sEGenerate the GRUB2 defaults file either in the specified path or in the system location. Returns the path to the defaults file. This is suitable only for DiskBootConfig. May raise BootmgmtConfigWriteError if there was a problem creating the defaults file (or its parent directory). RsError writing GRUB2 defaultss%s='%s'(RORPRQR'RvRtGRUB_DEFS_PATH_FMTRRXRZRt_generate_grub_defs_dictRRY( RRRtdirpatht defs_patht defs_fileR_RR((s-../../common/bootmgmt/backend/loader/grub2.pyRBs    " cCszi}|jtj}|d kr0tj}nt|dkr|ddkr_|d}ntjj |j tjj |}||di}tjj|}|r+||dt GFX_MODELISTRRRRR?RtupdateR{tPROP_CONSOLE_SERIALtPROP_SERIAL_PARAMSt_grub2_serial_cmdRB( RRRut video_backendtconstintermtouttermt serial_paramst serial_cmd((s-../../common/bootmgmt/backend/loader/grub2.pyt_generate_grub_defs_dict_conss:      cCs$i}|j|j||jtj}|dkrCd}n|d kr[tj}n||d<|jtj}|rt |t kst |rd|d,,, |

,,). | is currently defined to be a | number (valid values depend on the platform, | but '0' is ttya (com1) and '1' is ttyb (com2)). | Serial console parameters (=data bits, |

=parity ('N','E','O'),=stop bits ('0','1'), | =flow control ('H','S',None) for hardware, | software, or none). The default is: | ('0',None,None,None,None,None). tnotNteventEtoddtORs*Serial parameters are None: Using defaultss --unit 0sInvalid serial parameters: %siis --port %ss --unit %sis --speed %sis --word %sis --parity %sis --stop %sN( R?RBRttupleRxRtintthexR>(Rtparamst parity_dicttcmd((s-../../common/bootmgmt/backend/loader/grub2.pyRks*  "!"""!"c sDgtjjtjjj|tjjtjj|}dtjdd|}jj t j krjj dkrd|}ndj d||f|rtjj|tj}tjj|j|ttfd}tjdty0j dftjd |WnBtjtfk r}j d |tjdtnXtjj|}__||fSjj t j krdStjjjtj}j|tjj|tjj|}tjjrtjdty*j dftjWq7tjtfk r}j d |tjdtq7Xn6tjj|s'j d |dSj d |d ||fS(seCopy all files associated with the theme whose theme file is specified into the proper location. Returns a 3-tuple of (1) tuples (if basepath is set) (or None if not), and (2) the *GRUB path* to the theme_file (the GRUB path will be used directly in the grub.cfg file) and (3) The OS path to the theme_file. R3Rqs/@Rs3THEME: src=%s, theme=%s, theme_bn=%s, grub_path=%s c shxa|D]Y}tjj||}tjj|s:qn|jddd}tjjdtj|}tjtjj|d dj d|dddf}j d t |j ||jd d}t|dkr|d}tjj|} | r)j| q`|tjkr`tjj|} j| q`qqWgS( s%dirnm is the source theme's directoryR3Ris%(s)sR1tbinisTHEME: New tuple: %st.N(RORPRQtisfileRR'tBOOT_GRUB_THEME_SUBDIRRRR?R RBRxR?trsplitRtEXTN_TO_MODULER>taddtFONT_EXTN_LIST( tdirnmtlistingtentryt source_filet destcomponentt root_rel_pathtnewtupt extensiontextntmodnametfontpath(tdest_theme_dirtgrub_path_prefixRt source_dirRRt theme_nameR(s-../../common/bootmgmt/backend/loader/grub2.pytcollect_tupless6        t ignore_errorssTHEME: Copying %s -> %stignoresError during theme copy: %ss+Could not fall back to existing theme in %ss$Falling back to existing theme in %sN(NNN(NNN(RORPtdirnameRQRsRoR'RRR@RRCRDRBt _make_dirtreeRRVtrmtreeRtcopytreetErrorRiRRR?Rt THEME_SUBDIRR|( RRt theme_filettheme_file_basenamet grub_pathtdest_dirRtcopyerrtos_path((RRRRRRRRs-../../common/bootmgmt/backend/loader/grub2.pyt_assemble_grub_theme_filessv        $$              c Cs+|j|tj}|jtj}d}|tjkrt}tj |j kr|jtj }|r|tj |}qd}ntj }t }y.|r|j||\}|_|_nWqttfk r}|jd||sqqXn|r|r|j|n|S|r'|SdS(s|Copy other needed GRUB2 files into the proper location. Return the appropriate tuples (if basepath is set). s*Exception while assembling theme files: %sN(t_assemble_grub_files_genericR't GRUB_OTHERSRRRR?RR{RRtTHEME_TEMPLATEtTHEME_DEFAULT_PATHRRRRRZRiRBR( RRRtconstypet theme_tuplest default_themet themenameRR((s-../../common/bootmgmt/backend/loader/grub2.pyR*s6    (  c Csg}x|D]\}}}tjj|j|}|rXtjj|tj}n |j}tjj||}|jd||f|j||stj }nyt j ||Wn5t t j fk r} |jd|| fq nX|styKtj||dtj|tj|djtj|djWqtk rp} td|| qXq |j} | rd| d} nd } | tjd |7} |jtj|d | |d|d|dfq W|r|Sd S( sUsing the list of 3-tuples passed in file_tuples, copy those files to proper destination with the proper modes. This is suitable for DiskBootConfig and ODDBootConfig only. ssrc = %s, dest = %ssCould not copy %s for GRUB2: %siiisCouldn't set mode/perms on %ss%(s)s/R3N(RORPRQRsR'RvRRBRtGRUB_OTHERS_PERM_DEFAULTSRVtcopyRZRRRRRRRRRRiRR R?RRR?( RRt file_tuplesRRXRtpermstdestdirtfulldestRRRR((s-../../common/bootmgmt/backend/loader/grub2.pyRUsD     #cCs|jdt||}|j||x1|jjD]#}|j|||jdq9Wd|kr||jdndS(sjA stripped-down barebones implementation of a GRUB2 menu generator. First, a set of header script code is emitted (its contents depends on the values in the defs_dict (a dict representation of the $prefix/etc/default/grub file), followed by the menuentries that correspond to the boot configuration's boot_instances list. s# GRUB2 configuration file s t NO_CUSTOM_CFGsH if [ -f /boot/grub/custom.cfg ]; then source /boot/grub/custom.cfg fi N(RtGRUB2MenuEntryEmittert_internal_mkconfig_headerRRtwrite_menuentry(RRRER!temittertbootinst((s-../../common/bootmgmt/backend/loader/grub2.pyRAs  cCsQ|jd}|rMt|ttfr.|St|trM|jdSngS(sqReturns the list of lines in the script preamble stored in the definitions dictionary passed in. t__SCRIPT_PREAMBLEs (R>RR;RRtsplit(REtpreamble((s-../../common/bootmgmt/backend/loader/grub2.pyt_grub_cfg_preamblescCswg}|j|j||jd|jd}|jd}g}|r|j}d|kr|jdt}nt}x=|D]5} |j| ||} |j| || g7}qW|r|jd||} |j| |d7}q|jd|n|rxU|jD]G} | |kr;q#n|j| ||t} |j| || 7}q#W|jd|n|ddkr|jdn|jd } |jd } | r|jd | |jd |jd n|jd| |jd|jd} | rH|jd| |jdnx(|D] }|j ||j dqOWdS(sKOutput the grub.cfg header for this target based on the defs_dict. sload_video_$targetRRRsterminal_output %ssterminal_input %siRRRs+if sleep --verbose --interruptible %s; thens set timeout=0tfisset timeout=%sRsset default="%s"s N( RRR?R>RRDRR{t_mkcfg_consdevR(RRER!Rtoutdevtindevt initted_devstoutdevst do_gfxtermtdevt conslinesRRRtline((s-../../common/bootmgmt/backend/loader/grub2.pyRs^                cCs-g}|dkr|r|jd}|jd}|jd}|jd} |jd|r{|jd|ng} |jd} | rw|jrx2|jD]$} |jd | | j| qWn|jrx?|jD]1} |jd | |jd |jd qWn|jd |jd|jd| |jd||jdd}t}n d}t}|j|d|j|d||r|j|d|n| r|j|d| n|rj|jdd}t|dkrRtj j|d}|rR|| krR|j|d|qRn|j|d|n|j ddj }|r|j|d|j|d|n|j|d |r)|jd q)nN|dkr)|jd}|r |j|q)|j d|jdn|S(sGReturn a list of lines that init the specified terminal device RR}RiRjRksinsmod gfxtermsset gfxmode='%s'Rls insmod %ssif ! loadfont %s ; thens set theme_dep_load_failed=1Rs)if [ x$theme_dep_load_failed = x ] ; thens loadfont /boot/grub/unicode.pf2s set theme=%ss terminal_output %stelses Rs)if loadfont /boot/grub/unicode.pf2 ; thens foreground_color %ss background_color %sRis insmod %ss background_image -m stretch %sRRs,No serial command specified -- using default( R>R?RRRR{RRR'RRtstripRB(RRtalldevsRERRtmodestbackimgRxRzt loaded_modst themefileRRtindenttneed_fiRtimgmodtalldevs_minus_gfxtermt serialcmd((s-../../common/bootmgmt/backend/loader/grub2.pyRsv              c Cs|stdn|j}g}|rU|j|}|rU|j|qUnt}x|D]}|j||}|j|}|s|j|||} | r|j| nt}n|j ||d|} | r|j| n|rb|j|qbqbW|S(sTo generate the grub.cfg file for an ODDBootConfig, we create the menu by hand (we do NOT use the grub-mkconfig program). s,basepath must be specified for ODDBootConfigR%( RRRRR{t_create_grub2_imageReRRR6( RRRRt of_tuplestgenerated_grub_cfgRt loader_tuplesREt gcfg_tuplest stub_list((s-../../common/bootmgmt/backend/loader/grub2.pyRQs2      cCs|stdn|j}g}|j|}|rL|j|ndtj}i}x?|D]7}|j|||<||j|||d7}qfW|d7}t}x|D]}|j ||} | r|j| n|s||} t | d<|| d<|j ||| |j j } | rg} xV| D]N} t| }|tjtjkrytj|tjW|j| t }qqqW|S(s3To generate the grub.cfg file for a NetBootConfig, we create the menu by hand (we do NOT use the grub-mkconfig program). Since we will not use a graphical console while network booting, we do not need to assemble other files (i.e. GRUB2 font files and splash screen image). s,basepath must be specified for NetBootConfigs# begin preamble regexp ".*/(.*)" $prefix -s 1:target tr -s target - _ "$target" if [ -z "$target" -o "$target" = "%(bios)s" ]; then set multiboot=multiboot set module=module elif [ "$target" = "%(uefi64)s" ]; then set multiboot=multiboot2 set module=module2 fi s s# end preambleRR(RRRRR'R$ReR)R{RRRRRcR;Rt IDX_FILETYPERtOUTPUT_TYPE_NETCONFIGR?R(RRRRRRt target_dictsRR R RER t config_tuplesttupltlst((s-../../common/bootmgmt/backend/loader/grub2.pyR}sH               cCs tt|j||||}|s.| r2|S|jjtjksh|jdkshd|jj kry|j ddSy'|jj t j ||j dWnftk r}|j dt|tjddtjtjtjdt|tjnXdS( s R*s-No attempt will be made to set the boot orders(UEFI boot variables successfully updateds*Error updating system boot device list: %sspybootmgmt-GRUB2isxFailed to set the UEFI boot device to %s. Manual intervention may be required to boot Solaris when the system restarts.N(RR'tinstallRR@RRCRR?RyRBRR#tPROP_BOOT_DEVICERRxtsyslogtopenlogt LOG_DAEMONt LOG_WARNINGtcloselog(RtlocationRt verbose_fileRRRL((s-../../common/bootmgmt/backend/loader/grub2.pyRs&  !   c" CsLt|jts#|jddSt|dkrU|ddkrU|djpt|dko|ddko|djstjd ddk r|jd dSt d |n|j j }tj j |jtj|}tj j |tj|}|j|tj j d tj|tjd d|d|g} tj|} d} |jjjrt|jjj} | r| jd| | jdq|jdn| r| jddj | n|r| jdn|r | jdnt|trG|jtjrG|dkrG| jdn||jd } | d} t| }|dkr|r| }q|}n|dkrt ||}|st d|nd}d}y4t!t"d|}|r|d}nt#Wnt$k r}nX|syt%j&dd }Wn"t$k r^}t d!|nX|}d"||g}y|j'|WnFt(k rytj)|Wnt*k rnXt d#|nXt+}nt,}|d$}|d%}|d&}ytj-|}Wnt*k r'd}nX|dkr=t+}qt,}y%t.j/||d't,rgt+}nWqt*k r{qXnt0|d(| j|t+}zQy~|r|d)dj | IJ|j'| d*t+d+t+\}}|d,|I|d-|I|d.IJn|j'| d/d0Wnt1k r}t,}|j2tj3krtj j |tj4}yt5|d1j6Wn&t$k r}t d2||nXt7j8d3d4t7j9t7j7t7j:d5|t7j;qt d6|nXWd|dkr1zytj-|} Wnt*k r1d} nX|r| r| j<d4kr|ry%|j|d7t=j>||Wqt$t*t1fk r|jd8qXn|rd9|g}!|j'|!n|r| dks| j<d4krt d:|nWd|r-ytj)|Wq-t*k r)q-XnXnX| rHtj?| ndS(;s/Write the GRUB2 boot loader to disk. We support 4 scenarios: (1) BIOS systems, installation onto a DOS-partitioned disk with a Solaris partition -- boot loader is embedded in the Solaris boot slice (usually slice 8, but really it's any slice that includes cylinder 0). The devname passed in can be directly passed to grub-install, as grub-setup has been modified to write the loader to the appropriate place in the Solaris partition; (2) BIOS systems, installation onto a GPT-partitioned disk. A BIOS Boot Partition (BBP) is required. The devname passed in refers to the partition that includes the ZFS, not the BBP, so we need to figure out if we're on a GPT-partitioned disk, and pass the whole-disk node (p0) to grub-install so *IT* can locate the BBP and install GRUB2 there; (3) UEFI systems, installation onto a DOS-partitioned disk. The device node refers to a VTOC slice, so we need to get the device node for the EFI System Partition, mount it (if it's not already mounted), and invoke grub-install, telling it to install the EFI boot application under EFI/ORACLE/ on the ESP; (4) UEFI systems, installation onto a GPT-partitioned disk. Similar to (3). s/Ignoring _write_loader() for non-DiskBootConfigNiitsiiitBOOTMGMT_TESTINGs%TESTING is set: NOT installing loadersDevice node is not a slice: R3s --no-floppys--grub-directory=%ss--pkglibdir=%sRs--password_file=%st ask_passwds3Failed to append ask_passwd to grub install commands --modules=%sRs--no-check-versionings--debugR(s --force-mbrtp0R)s@Could not determine the EFI System Partition (ESP) for device %st mnt_specialt mnt_mountptdirs/system/volatilesAError while trying to create a temporary dir for mounting the ESPs/usr/lib/fs/pcfs/mounts9Error while trying to mount the EFI System Partition (%s)s /EFI/ORACLEs/efi/boot/bootx64.efis /grubx64.efitshallows is not supporteds5Output from boot loader installation command "%s" is:R\t return_stderrs : %ss : %sssInstalling boot loadersBoot loader installationRsiUnable to install GRUB2 boot loader and unable to create required deferred boot loader activation file %sspybootmgmt-GRUB2isGRUB2 could not be installed at this time. The GRUB2 utilities on the root filesystem are older than (and incompatible with) the GRUB2 modules in %s. The new version of GRUB2 will be installed automatically when booting the Solaris instance in which the new GRUB2 modules are located.sGRUB2 installation faileds /efi/boot/s<Failed to copy boot app to default boot location -- ignorings /sbin/umounts8Error while creating the UEFI boot loader (size=0) on %s(@RRRRBRtisdigitROtgetenvR?RRRyRPRQRR'RRRRRzt GRUB_INSTALLtPRELOADED_MODULESRRR!R?tdictR>Rt PLATOPT_MBRR_RRRRRRZttempfiletmkdtempRZRtrmdirRiRR{RdtfilecmptcmpRRtretcodetEXIT_CODE_INCOMPATIBLEtDEFERRED_ACTIVATION_FILENAMERXRYRRRt LOG_NOTICERRgRVtcopyfileRD("Rtdevnamet data_rootRRRRt prefixdirt fulldatadirt grub_inst_cmdtpreloadsttemp_file_namet base_devnamet wholedisktis_gpttinstdevtesp_devt esp_mountptt esp_tempdirt mntentdictR_t mount_cmdt need_unmounttdefault_bootapptoracle_bootapptdefault_statinfotcopy_efi_boot_to_defaultt cmd_succeededtcmdouttcmderrtbmwerrt defer_filetstatinfot umount_cmd((s-../../common/bootmgmt/backend/loader/grub2.pyt _write_loaders> ""          !                                         c Cs)t|jtrgSt|jts,gStjj|jtj |}g}tj dtj |}|j tjj||xtj |D]}|jdp|jdp|jdp|jdsqn|jdd|kr|jd|qntjj||}tjj|||} ytj|| Wnttjfk r} |jd || | fx7|D]/} ytj| d Wqtk rqXqWtd || f| qX|jtj| dd tjd tjjd||dddfqW|S(sCopies GRUB2 modules (and config files) to a directory under basepath. Returns a list of tuples, each of which describes one of the files copied. This is suitable for DiskBootConfig and ODDBootConfig only. R3s.mods.lsttefiemus.imgRisSkipping copying file %ss Error while copying %s -> %s: %sis'Error while copying GRUB2 file %s to %ss%(s)sR1iN(RRRRRORPRQRsR'RRRvRRtlistdirtendswithR/RRBRVRRiRRDRR?RRR?RS( RRRtexclusion_listtmodpathRt boot_subdirRtsrcpathtdestpathRttup((s-../../common/bootmgmt/backend/loader/grub2.pyt_copy_grub2_modssL     cCs!t|jtr$|j|}nd}d}t|jtr|dkrc|j||}q|dkr|j||}qnQt|jtr|dkr|j|}q|dkr|j |}qn|rt j |n|dk r|St d|jj j|fdS(sConstruct the bootable grub2 image for the specified target. The boot image is BootConfig-specific (BootLoaders associated with ODDBootConfig instances get BIOS-targeted El Torito images and UEFI64- targeted FAT filesystem images with embedded UEFI64-targeted boot applications (suitable for direct inclusion in an ODD image); NetBootConfig boot loaders get BIOS PXE images and UEFI64 net boot application images). R(R)s%s and target=%s not supportedN(RRRt_create_microconfigR?t_create_bios_odd_imaget_create_uefi64_odd_imageRt_create_bios_pxe_imaget_create_uefi64_net_imageRVRRRR(RRRt microconfigttuples((s-../../common/bootmgmt/backend/loader/grub2.pyR s(      c Cstjdtjd}tjj||tj}|j|tjj|tjd}|j|ddddddg}|j tj d|j d|||ytjj|j tj d}tjj|d }t|d } x*||gD]} tjt| | qW| jWn,ttfk rZ} td || nXtj|dddddftj|dd tjd tjjd|tjdddfg} |jd||} | r| j | n| S(sCreate an El Torito image by invoking grub-mkimage with the proper parameters, then prepending the result with cdboot.img. R3R(tbiosdisktiso9660t part_msdost part_sunpctpart_gpttufs1s cdboot.imgtwbs$Could not finish construction of %ss%(s)sR1iN(R'RvRRORPRQtCORE_IMG_BASENAMERtEL_TORITO_IMAGENAMESRR(t_grub2_mkimage_genericRsRRRXRVt copyfileobjRYRiRZRRtOUTPUT_TYPE_BIOS_ELTORITOR?RRRSR[(RRRaRWt imagenametwholeimagenametmodlistRVt cdboot_imgtwholeimgtfnameRRt mod_tuples((s-../../common/bootmgmt/backend/loader/grub2.pyR]; sD          c CsItjj|jtj|}tjjdtj|tj}|r|j||}|j ddddddg|d|d |d tj |d |d g |}nOd}|d|d |d tj |d tjjdtj tj |g|}|j|d|d||rEytj|WqEtk rAqEXndS(sCreate a GRUB2 boot image for the specified target, named imagename, with modlist modules embedded and preloaded. If microconfig is not None, it must be the path to a directory containing a boot/grub/grub.cfg file. R3tmemdiskttartsearchtgziotregexpt configfiles-os-ds-Os-ms--prefix=(memdisk)/boot/grubs --prefix=%ssGenerating %s boot loader images%s boot image generationN(RORPRQRsR'RRRzt GRUB_MKIMAGEt_make_memdisk_imageRtMKIMAGE_FORMATSR?RvRRZRDRi( RRRoRqRaRVtbase_cmdt memdisk_pathtimg_cmd((s-../../common/bootmgmt/backend/loader/grub2.pyRlm s4        cCs<d }d }zytjdddt}tj}tj||jd|ddddg}|j|d |d |||j |j SWn]t k r}|r|j ytj |j Wqt k rqXnt d |nXWd |r7y!tj||jd|Wq7t k r3q7XnXd S( sCreate a "tarfs" (tar file) with the microconfig specified. The microconfig specified is the parent directory -- there must be a boot/grub/grub.cfg under that directory. R"s/system/volatiletdeletes cwd => %ss/bin/tartcfR+tbootsGenerating %s memdisk images%s memdisk image creations-Error during GRUB2 memdisk image constructionN(R?R+tNamedTemporaryFileR{ROtgetcwdtchdirRBRZRYRRiRDR(RRaRt memdisk_imgtorig_dirttar_cmdR((s-../../common/bootmgmt/backend/loader/grub2.pyR} s:         c Cs dj|} |jd| y|r8|j|n|sE| rQtj} n|} |sc|rotj} n| } |rtj}ntj|d|d| d| } |r|d} | jj| | jj| | jjnd}d}g}| tjkr"|j| j j n| tjkrJ|j| j j nx@|D]8}t j |t j }t j |t j|tjBqQWx| jdkry)| tjkr|| j j7}nWn8tk r}|jtjkr|jd|qnXy)| tjkr.|| j j7}nWn8tk ri}|jtjkrj|jd|qjnXtjd |r|jd qqW| j}y)| tjkr|| j j7}nWn#tk r}|jd |nXy)| tjkr|| j j7}nWn#tk r7}|jd |nX|d kr|jd |||f|smd}ntd||d ||fd|n|r|jdn|s|r||fSdSWn<tk r}|jd| |ftd| |nXdS(sSpawn a command. Rs Invoking %ststdintstdouttstderrs Rs(Error while reading from stderr pipe: %sg?Rs#Error reading final stderr data: %sis5.failed (exit code %d). stderr was: %s stdout was: %sscommand executions:Error during %s: %s returned error code %d. stderr was: %sR0s.completed successfully.sError while invoking %s: %ssError invoking %sN(RQRBt subprocesstPIPEtPopenRRRYR?RtfilenoRtfcntltF_GETFLtF_SETFLROt O_NONBLOCKtpollR?treadRZterrnot EWOULDBLOCKttimetsleept returncodeRRi(RRRt whatisthist stdout_filet stdin_fileR\R$R]tfullcmdt stdout_valt stderr_valtproct user_inputt stdout_outputt stderr_outputt filedescstfdesctfcinfoR_R0R((s-../../common/bootmgmt/backend/loader/grub2.pyRZ s        !              csngfd}yEtjdddt}|j|jjfdWn"tk r~}td|nXddd d d g}|jt j d j d ||t j j|t jd yjWn)tk r}|td|nXy~t j j}|t jkrGt j}ntd } | j|d| jd| jjfdWn/ttfk r} |td| nXddg} t| dd; ss5Error during 64-bit UEFI El Torito image constructionRdReRfRgRhR)Ritcs tjS(N(RORD((Ro(s-../../common/bootmgmt/backend/loader/grub2.pyR^ ss /sbin/lofiadms-as-dR\ics jS(N(RZ((t lofiadm_d_cmdR(s-../../common/bootmgmt/backend/loader/grub2.pyRj ss/lofi/s/rlofi/slofi association: %s => %ssCreating pcfs on image size %dKis/usr/lib/fs/pcfs/mkfss-osnofdisk,size=%dRs /dev/zerotrcs tjS(N(ROR-((t mount_tempdir(s-../../common/bootmgmt/backend/loader/grub2.pyR ss/usr/lib/fs/pcfs/mounts /sbin/umountcs jS(N(RZ((RRP(s-../../common/bootmgmt/backend/loader/grub2.pyR ssEFI/BOOTs BOOTx64.EFIs&Unmounting the uefi64 image failed: %ss3Removing temp mount dir for uefi64 image failed: %ss#Removing lofi associated failed: %ss%Removing temp uefi64 image failed: %sN((R+RR{RYRR?RiRRR'R(RlRORPRQRkRRtgetsizetUEFI_FS_MIN_SIZERXtseekRRZR;RZRRRRBR,RRVR4R-RDRtOUTPUT_TYPE_UEFI_ELTORITOR?R[(RRRaRttmpfRRqRLt imagesizet imagefiletun_errt lofiadm_cmdtlofidevt raw_lofidevtmkfs_cmdRDt image_destdirRRRu((RRoRRRRRPs-../../common/bootmgmt/backend/loader/grub2.pyR^" s                           cCs tjj|jjtj|S(sCopies the NBP program for the specified target to the specified path. Raises BootmgmtConfigWriteError if the copy failed. (RORPRQRtnet_osimage_rootR'Ra(RR((s-../../common/bootmgmt/backend/loader/grub2.pyt _nbp_path scCs(tj|jddddddfgS(sYCreate a GRUB2 image bootable via the PXE on systems with BIOS firmware. R(N(RtOUTPUT_TYPE_BIOS_NBPRR?(RR((s-../../common/bootmgmt/backend/loader/grub2.pyR_ s cCs(tj|jddddddfgS(spCreate a GRUB2 UEFI boot application image bootable via the native UEFI network boot mechanism. R)N(RtOUTPUT_TYPE_UEFI64_NBPRR?(RR((s-../../common/bootmgmt/backend/loader/grub2.pyR` s c Csg}t|jtrt}|jd |}|r|j||jdtjj dt j t j ||jdn|j ddj |ntd|jjj|sd Sd }ytjdd}tjj |d }|j|d ttjj |t jd }x(|D] }|j||jdq*W|j|SWn;tk r} |rtj|tntd | nXd S(sCreate a small configuration file whose purpose is one: (a) to locate the REAL root device (since the microconfig file will be loaded from a memdisk baked inside the GRUB2 image), or (b) to source the REAL configuration file (i.e. when booting from the network, the microconfig contains the GRUB2 script that searches the tftp hierarchy, in accordance with the Solaris-defined search order for the GRUB2 configuration file.) sset prefix=($root)%sR3ssource $prefix/grub.cfgsMicroconfig: %ss s/Microconfig creation not supported for class %sR"s/system/volatiles boot/grubiRs-Error while trying to write GRUB2 microconfigN(RRRRtsearch_cmd_genericR?R?RORPRQR'RvRRBRRRR+R,RRXR0RRYRZRVRRR( RRRRt root_searchttmpdirt tmpfiledirtcfgfileRR ((s-../../common/bootmgmt/backend/loader/grub2.pyR\ s@       icCs |jtjj||dS(sCreate directories for dirname(basepath). May raise BootmgmtConfigWriteError if there was a problem creating the directories. N(RRORPR(RRtmode((s-../../common/bootmgmt/backend/loader/grub2.pyR! scCsvtjd}zRytj||Wn7tk r_}|jtjkr`td|q`nXWdtj|XdS(sCreate directories for path. May raise BootmgmtConfigWriteError if there was a problem creating the directories. isCould not create directoryN(ROtumasktmakedirsRiRtEEXISTR(RPRt old_umaskR((s-../../common/bootmgmt/backend/loader/grub2.pyR) s(sbiossuefi64(srootsrootiN(sboot/grub/splash.jpgs splash.jpgNii@(Rt __module__t__doc__tWEIGHTtSUPPORTED_PLATFORMSRRRRRRRpRstPROP_IDENT_FILERtSUPPORTED_PROPSRzRRORPRQRRRR$tPRELOADED_MODULES_COMMONR(R~RRR'RYR|R^R1R2RRvRRt THEME_DEFAULTRRRRR?RRaRjR1R0RRbRRdRRRRRkRRnRRqRtRt classmethodRMRGRIRERSRVRWRtpropertyRRRRRRRRRR{RRRRRRRR"t staticmethodR)R6RIRR RLRCRRBR{RReRrRRRRRARRRRRRRQR[RR]RlR}RZR^RR_R`R\RR(((s-../../common/bootmgmt/backend/loader/grub2.pyR'Ks                        $r  0      4 R >/+ 8 4      0 3  0 + 3  L X , O" 7 & 3 ' + a    ; RcBseZdZdZedZedZdZdZdZ dZ ddZ de d Zed Zd Zd Zd ZdZedZedZRS(s%GRUB2MenuOrganizer includes shared code between the GRUB2 pybootmgmt backend and the GRUB2 menu generator program in $PREFIX/etc/grub.d. Methods are provided to get an ordered list of boot instances from the system (via the autogen backend (which gets the list of BEs and generates a boot instance for each BE) if none exist in the menu.conf) and the rest from the menu.conf, which has sections for each customized boot instance (and, therefore, menu entry)) and to synch a list of boot instances with the menu.conf. cCs2tt|jd|_||_||_dS(s+Constructor for GRUB2MenuOrganizer N(RRRR?t_mcpRR(Rt boot_configtmenu_conf_path((s-../../common/bootmgmt/backend/loader/grub2.pyRF s  cCs|jr|jjStS(sYPseudoproperty returns True of the underlying MenuConfigParser is dirty. (RRR{(R((s-../../common/bootmgmt/backend/loader/grub2.pyRN s  cCs4|jjr|jjS|jjr,|jjSdSdS(s=Accessor for the path to the last menu.conf written. N(Rtlast_written_pathtfilenameR?(R((s-../../common/bootmgmt/backend/loader/grub2.pytmenu_conf_sourceW s     cCst|jt|_dS(s9Start over with a new (empty) menu configuration N(R&RRR(R((s-../../common/bootmgmt/backend/loader/grub2.pyRb scCs8|jj}t|}|jd|jtj|S(s]Returns a dictionary of properties from the global section of the menu.conf. sSerial properties: %s(Rtglobal_optionsR)RBR>RR(Rt global_propstblprops((s-../../common/bootmgmt/backend/loader/grub2.pyRg s    cCs|j}|rU|jj}|r|j||}|rR|jjqRqn|jjtjkrddl m }|j |jdg}x?|D]4}|j j }|j|}|jj||qWn|S(sLoad the menu.conf file and processes the sections, generating BootInstance objects and returning the list to the caller. i(tBootInstanceAutogenFactoryR4(t_build_custom_inst_listRt get_ordert_rearrange_inst_listt clear_orderRR@RRCtbootmgmt.backend.autogenRtautogenRRt_boot_instance_to_propdictt add_entry(RRtexplicit_ordert do_updateRtinstt classnametpropdict((s-../../common/bootmgmt/backend/loader/grub2.pyRs s     cszx|jD]\}}|tjkr |tjkry=g}x!|D]}|jt|qGWdj|}Wqtk r|j dq qXnt||j j |t_menu_conf_entryt_write_menuentry_tcmp_fncs |jkS(N(tsection_string(R(t order_list(s-../../common/bootmgmt/backend/loader/grub2.pyR sN('RR'RRRR?RxRQt TypeErrorRBRRRR@RRCR@R"R?RRRrRt cred_listRRRRR;t_synch_boot_instance_to_entryRRRRRRRt set_ordertdelete_entries(Rtbi_listtbl_propsRRtstrlisttitemtvalid_bootfsesRt inst_bootfsR t custom_entryRRR((Rs-../../common/bootmgmt/backend/loader/grub2.pyR sZ               cCs(|r||_nt|j|_dS(s+Loads the menu configuration file. N(RR&R(RR((s-../../common/bootmgmt/backend/loader/grub2.pyR s cCs|jj||dS(s7Save the menu configuration to stable storage. N(RR(RRR((s-../../common/bootmgmt/backend/loader/grub2.pyR scCs'|rt|dr|jSiSdS(sConvert boot instance to a dictionary suitable for serialization in the menu.conf file. The bulk of the work is performed by methods tailored for each type of BootInstance. tserialization_dictN(thasattrR(R((s-../../common/bootmgmt/backend/loader/grub2.pyR s cCsddl}t|j|d}|rt|}d|krI|d=nd|krt|dtkrt|d|d' must be escaped (replaced with '>>'). t>s>>(Rtescape_str_for_grub_cfgR(trawstrtescstr((s-../../common/bootmgmt/backend/loader/grub2.pytescape_title_str_for_grub_cfgo scCs(|jdd}|jdd}|S(sFEscape a string so it evaluates to its raw value in grub.cfg. s\s\\Rs\"(R(R#t cookedstr((s-../../common/bootmgmt/backend/loader/grub2.pyR"y sN(RRRRRRRRRRRR?RR{RRRRRRRR%R"(((s-../../common/bootmgmt/backend/loader/grub2.pyR; s"     " M  !  2  RcBseZdZddedZdZdZddZddZ ddZ ddZ dd Z d Z ed Zd Zd ZddZRS(s7Emits GRUB menuentry blocks for the grub.cfg file. cCstt|j|s(tj|_n ||_d|_d|_i|_d|_ ||_ |sst j |_nt||_dS(sIf fileobj is None, STDOUT is used. vardict is the dictionary that holds variables that may be used by the menu entry generators. If it's None, os.environ is used. If force_grub2 is True, we instantiate the BootConfigs with a loaderclass keyword arg to ensure we get the BootInstances from GRUB2 and not a different (perhaps higher-ranked) BootLoader, whose BootInstances may be in the BootConfig's boot_instances list. RN(RRRtsysRt_fileobjtmenuentry_theme_stringtsubmenu_theme_stringt _rpool_propsR?tlzfsht force_grub2ROR>t_vardictR)(RtfileobjtvardictR-((s-../../common/bootmgmt/backend/loader/grub2.pyR s       cCst||}|jj|dkr7i|j|R?R RRt ValueErrorRBR (RR,trpooltzphtrawguidthexguidtvalerr((s-../../common/bootmgmt/backend/loader/grub2.pytcache_zpool_props s c Cs8d}tjjdr1tjdjd}ntjjd sWtjddkrct}nd}tj}t|_ x|D]}|r||krqn|j rit d6}|j dnd}t j|d|1}|j|j |x|jD]}|rOt|trOt|dd}|rO||krOqqOn|jsd|jjr|jjd t j|jjd t j|jjd PqqWxp|jD]e}|rt|trt|dd}|r||krqqn|j||jjd qW|jjd t jddjg|D]} | jrD| ^qD} |j|| } |jjd| d| } |jjd| d|} |jjd| | |jf|jjd|jjd|jjd|jjd WdQXqWt |j d|_ dS(sEmit entries to the fileobj specified in __init__. This should only be invoked when this class is instantiated by the GRUB2 autogen script. R7t;R8R{t loaderclasss%Forcing loaderclass = GRUB2BootLoadert init_argdictRsif [ -f $prefix/%s ]; then ssource $prefix/%s sfi s s$if [ "$target" = "%(bios)s" ]; then troot_Rs %s s($%s)/@/boot/grub/menu.lsts if [ -s "%s" ]; then s$Legacy GRUB Menu (from root pool %s)s submenu "%s" "%s" %s{ s& extract_legacy_entries_source "$2" s } s fi N(!R?ROR>thas_keyRR"tlibbe_pytbeGetRootPoolListR R,R-R'RBtlibbetget_boot_configR7RRRRrRRRR(RRRR$RQtisalnumt_search_cmd_for_poolR*R (Rt zpool_listRtall_root_poolsR2targdicttbootconfRRRtrootvart search_cmdtlegacy_cfg_fileR((s-../../common/bootmgmt/backend/loader/grub2.pyt emit_entries st                 2     c Csct|d|jjd}|r1t|ddr1tj|j}d}|jr|jdrtj }|j j d||jddt |jddkrx4|jddD]}|j j d||qWn|j j dd }t }nt}d} |jr8d d d jtt|j} n|d ||j| f} |j j | |||} xI| D]A} | dkr|j j dqx|j j |d | dqxW|j j |d|r_|j j d|j j d||j j d|j j d|j j dq_n.|jd|jjtt|ddfdS(sJCall the BootInstance-specific function to emit a menuentry block RRRisif [ "$target" = "%s"is -o "$target" = "%s"s ]; then s s --users s%s t,smenuentry "%s" %s%s{ s s} selse s9 menuentry "Entry [%s] not supported on this firmware" { s echo "Not supported" s } sfi s2Not emitting entry for instance type %s (title=%s)N(RrRRR?RR"RtTARGETR'R$R(RRRR{RRQtmapRxR)RB( RRRRt clean_titlettabsttargdictt targstringt needclosetauthstrt menu_startRR((s-../../common/bootmgmt/backend/loader/grub2.pyR sR       #      R1cCsY|jj|rG|j|jtrG|j|t}d||fSd||fSdS(s^Returns a string containing the search command to use for the specified pool. s(search --no-floppy --fs-uuid --set=%s %ss&search --no-floppy --label --set=%s %sN(R+R>R(RR2tvarnametguid((s-../../common/bootmgmt/backend/loader/grub2.pyRB= s cCsg}t|dd}t|tsV|jdrF|jdqV|jdn|jrh|jnd}|r|jdd}n|j||d|S( s?Emits a menuentry for a Solaris network boot instance. t _bootconfigR*s insmod efinets insmod pxeRt$s\$N( RrR?RRR/R?tkargsRt_write_menuentry_generic(RRRRR<RY((s-../../common/bootmgmt/backend/loader/grub2.pyt'_write_menuentry_SolarisNetBootInstanceK scCsg}t|dd}t|dd}t|tsI|jdn|jr[|jnd}|j||}|r|j|n|j||d|S(s<Emits a menuentry for a ODD-based Solaris instance. RWRosinsmod iso9660RN(RrR?RRR?RYRRZ(RRRRR<RoRYRx((s-../../common/bootmgmt/backend/loader/grub2.pyt'_write_menuentry_SolarisODDBootInstancee sc Csgg}|jd|jd|jd|jdt|dd}t|dd}|jrp|jnd}|jdkrd}|j||}|r|j|nt} n(|j|||\}}} |sdS|rN|rNy|jt j } Wnt k rqNX|j t jkrN| t jkrN|jd qNn|j||||| S( s5Custom emitter for a SolarisDiskBootInstance sinsmod part_msdossinsmod part_sunpcsinsmod part_gptRRWRoRpNt load_video(R?RrR?RYRURR{t#_handle_zfs_SolarisDiskBootInstanceRRRRR@RRCRRZ( RRRRR<RoRYtrootpathRxt is_encryptedR((s-../../common/bootmgmt/backend/loader/grub2.pyt(_write_menuentry_SolarisDiskBootInstance{ s8       cCsit|ddr|j}nd}| rF|rF|jtj}n|rTd|S|jddSdS(sReturns a search command string that includes the identifying file from either the bootinst (tried first) or boot_loader. t identfiles%search --no-floppy --file --set=root s%no identifying file -- search omittedN(RrR?RbRRRRB(RRRot ident_file((s-../../common/bootmgmt/backend/loader/grub2.pyR s   cCstj|}|jjd}|rQ|ddkrDd|}nd|}ny|jidd6}Wntk r|j}nXy|jidd6}Wntk r|j}nX|jdd ks|jdd kr)|jd |jd |jd |jd |jdn|r>d} d} n d} d} |jd||r|jd||jd| ||f|r|j|n|jdd||f} |jd| |jd| | fn|jd} | dkr|| } nd} |jd|jd| | |f|rU|j|n|jd|jd||jd| |f|S(sGGeneric code for finishing a Solaris boot instance's menuentry R|iRs"%s"sset gfxpayload=%stamd64tkarchs$ISADIRisif cpuid -l; thens set ISADIR=amd64Rs set ISADIR=RR+R,s $multiboots$modules set kern=%ss"echo -n "Loading ${root}%s$kern: "s%s %s/$kern $kern %ss insmod gzios%s%ssecho -n "Loading ${root}%s: "s%s %ss /platforms$kerns echo -n "Loading ${root}$kern: "s%s $kern %s %s( RR"R.R>tkerneltKeyErrort boot_archiveRR?(RRRR_RYR`tgfxpayload_modesRfRhR-R.tbootarch_stringRt ba_rel_kern((s-../../common/bootmgmt/backend/loader/grub2.pyRZ s`                cCs{|r|}n!|r*t|j|}nd}|rwt|j|rw|jd|jd||jdtStS(sChecks if the specified dataset (or implied dataset) has encryption enabled, and if so, emits the proper commands to prompt for and set the zfs key. Returns True if the dataset is encrypted. sinsmod zfscrypts"echo -n "[Encrypted dataset %s] " tzfskeyN(RR,R?R R?RR{(RR2RRt dataset_name((s-../../common/bootmgmt/backend/loader/grub2.pyt_handle_zfs_encrypted_datasets   c Cs t|dd }|r-t|\}}nt|dd }|sV|jdd S|jd|jd|j|}|r|j|n|j|||}|rd|} |jd| n|jdd } |r|jd }nd }|| |fS( snHandle the ZFS-specific part of menuentry generation. Returns the kargs to use in the entry. RR2s0# Cannot determine the root pool for this entry.s insmod zfsRs /ROOT/%s/@szfs-bootfs %s/ zfs_bootfss/zfs-defaultbootfs $root zfs_rootpath zfs_bootfss/${zfs_rootpath}/@s -B $zfs_bootfss-B $zfs_bootfsN(RrR?RR?RBRnR( RRRRYRR2tbenameRHR`R_((s-../../common/bootmgmt/backend/loader/grub2.pyR^s,     cCsg}|jdkst|jtk st|jdkst|jdtk st|jdkrt|jdtk rt|jdtk st|jdkrt|jdtkrt|jddkr|jd|jd|Sdt|jd}t|jdkr_t|jdtkrx|jdD]}y(t|}|dt|d7}WqWt k rt |t rt|dkr|dkr|d krt |t dd}|d |7}qqWXqWWq_y/t|jd}|dt|d7}Wq_t k r[|d|jd7}q_Xn|d 7}|jd ||j r|jd |nt|jdkr|jd|j|jfn|jd|j|S(s3Custom emitter for a ChainDiskBootInstance iiis)Invalid chainloader info in boot instances(# Could not process this chainload entrys(hdRKtatzs,%dt)s set root=%ssparttool %s boot+schainloader --force %s+%sschainloader --force +%sN(t chaininfoR?RRRRRBR?RxR1RRtordt forceactivet chainstartt chaincount(RRRRtdiskstrt tuple_itemtint_itemtpart((s-../../common/bootmgmt/backend/loader/grub2.pyt&_write_menuentry_ChainDiskBootInstanceBsL*%".         N(RRRR?R{RR7RJRRBR[R\RaRRZRnR^R|(((s-../../common/bootmgmt/backend/loader/grub2.pyR s  [ 2    4  B  'cCstgS(sTReturns a list of boot loader classes, consumed by the boot loader factory. (R'(((s-../../common/bootmgmt/backend/loader/grub2.pytbootloader_classes|s(HRRRRR.RR?R=ROtpkg.pkgsubprocesst pkgsubprocessRRRVRdRR'R+RR RRRRRRRRRtbootmgmt.pysolR R R R R RRRRRtbootmgmt.bootloaderRRRRRRRRtbootmgmt.bootutilRRRRRRR R!R"tbootmgmt.bootinfoR#t bootmgmt.backend.loader.authconfR$t bootmgmt.backend.loader.menuconfR%R&t EFISYS_PARTIDt EFISYS_GUIDR'RRR}(((s-../../common/bootmgmt/backend/loader/grub2.pytsT               @F(@I