iVc@sfdZddlZddlZddlZddlZddlZddlmZmZm Z m Z m Z ddl m Z mZddlmZmZmZmZmZmZddlmZddlmZddlmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#dd l$m%Z%m&Z&d e e fd YZ'd efd YZ(dZ)dS(s6 Legacy GRUB BootLoader Implementation for pybootmgmt iN(t MenuDotLstt MenuLstErrortMenuLstMenuEntrytMenuLstCommandtMenuLstBootLoaderMixIn(t BootLoadertBootLoaderInstallError(t BootConfigtDiskBootConfigt NetBootConfigt BootInstancetSolarisDiskBootInstancetSolarisNetBootInstance(tChainDiskBootInstance(tget_current_arch_string( t BootmgmtErrortBootmgmtArgumentErrort!BootmgmtUnsupportedOperationErrortBootmgmtInterfaceCodingErrort!BootmgmtIncompleteBootConfigErrortBootmgmtConfigReadErrortBootmgmtConfigWriteErrort#BootmgmtMalformedPropertyValueErrortBootmgmtNotSupportedErrort BootmgmtUnsupportedPropertyError(tPopentCalledProcessErrortLegacyGRUBBootLoadercBsreZdZdZid>d6ZdZdZdedeZdZdZ d Z d Z i d d 6d e e d6dd6dd6ded6de d6de d6dd6dd6Z dZdZejejejejejejejejgZiejej6ZdZedZed Zed!Z ed"Z!ed#Z"d$Z#ed%Z$ed&Z%ed'Z&d(Z'e(d)Z)d?d*Z+e,d+Z-e,d,Z.d-Z/d.Z0d/Z1d0Z2d1Z3d?d2Z4d3Z5d4Z6d5Z7d6Z8d7Z9d8Z:d9Z;d:Z<d;Z=e>d?d?d<Z?d=Z@RS(@sImplementation of a Legacy GRUB (GRUB 0.97) BootLoader. Handles parsing the menu.lst file (reading and writing), though reading it and creating BootInstance objects is rather fragileitbiostx86smenu.lsts boot/grubt/s/boot/grub/splash.xpm.gzit343434tF7FBFFs default 0tdefaultstimeout ttimeouts # serial --unit=0 --speed=9600tserials# terminal serialtterminals# splashimage t splashimages# foreground t foregrounds# background t backgroundt#t min_mem64t hiddenmenuiis# default menu entry to boot %(default)s # # menu timeout in second before default OS is booted # set to -1 to wait for user input %(timeout)s # # To enable grub serial console to ttya uncomment the following lines # and comment out the splashimage line below # WARNING: do not enable grub serial console when BIOS console serial # redirection is active. %(serial)s %(terminal)s # # Uncomment the following line to enable GRUB splashimage on console %(splashimage)s %(foreground)s %(background)s # # To chainload another OS # # title Another OS # root (hd,) # chainloader +1 # # To chainload a Solaris release not based on GRUB: # # title Solaris 9 # root (hd,) # chainloader +1 # makeactive # # To load a Solaris instance based on GRUB: # # title Solaris # bootfs /ROOT/ # kernel /platform/i86pc/kernel/amd64/unix # module /platform/i86pc/amd64/boot_archive # # To override Solaris boot args (see kernel(1M)), console device and # properties set via eeprom(1M) edit the "kernel" line to: # # kernel /platform/i86pc/kernel/amd64/unix -B prop=value,... # %(hiddenmenu)s %(min_mem64)s cKs-|jd}|dks*|jdkr.dSt}|jtjkrf|dkrf|jddS|jtjkr|jdk rt j |S|jtj krt j |S|jtjkry|j ||jdWn$tk r}|jd|dSXt j|Std|jdS(sIProbe for Legacy GRUB files for use with the BootConfig passed int bootconfigRs6Legacy GRUB boot loader not supported on this platformtfwtypes#[PROBE ABORTED DUE TO EXCEPTION] %ssBoot class %s not supported.N(tgettNonet boot_classRRtBOOT_CLASS_NETt_debugtBOOT_CLASS_DISKt boot_fstypeRt _probe_disktBOOT_CLASS_ODDt _probe_oddt_validate_platform_and_firmwareRt _probe_netR(tclstkwargsR+tcur_archtbmerr((s2../../common/bootmgmt/backend/loader/legacygrub.pytprobes.       cKsa|jd}|j}|jd|y|j|dgWntk rVdSXt|S(sThis Legacy GRUB probe function searches the ODD's root, looking for the Legacy GRUB menu.lst and stage1 and stage2 filesR+sodd_image_root=%ssboot/grub/stage2_eltoritoN(R-tget_rootR1t_probe_genericRR.R(R9R:R+troot((s2../../common/bootmgmt/backend/loader/legacygrub.pyR6s  cKs<|jd}|j|}|s(dS||d] s data root=%ssboot/grub/pxegrubiN(R>R1R?RtARTIFACT_BOOTLOADER_IMAGEStARTIFACT_BOOTLOADER_TOOLSRR.RERFRGt net_data_rootRt MENU_LST_FILEt pxe_suffixtstattS_ISREGtst_modetst_sizetARTIFACT_BOOTLOADER_CONFIGFILEStOSError(R9R+R@RAtmenu_lstt stat_info((s2../../common/bootmgmt/backend/loader/legacygrub.pyRBs&  ! c Cs|j}t|dd }|r0|j}n |j}|dkrQ|}n,|dkri|j}n|jd|gStjj |s|jdgS|jd||fg}y*|j |t j g|t jg7}Wn)tk r}|jdt|nXy*|j |dd g|t jg7}Wn)tk rg}|jdt|nXyTd }tjj|rtj|tjr|t jg7}n|jd |Wn#tk r} |jd | nX|S(s=Probe for menu.lst, stage1, stage2, and installgrub. t boot_loadertufstzfssUnknown filesystem type: %ssdataroot is not a directorysdataroot=%s cfgdataroot=%ss3Problem checking GRUB Legacy boot loader images: %ssboot/grub/stage1sboot/grub/stage2s/usr/sbin/installgrubs%s not found or not executables-Error while looking for GRUB Legacy tools: %sN(R3tgetattrR.t_get_boot_loader_data_rootR>tzfstopR1RERFtisdirR?Rt_MENU_LST_PATHRRbRRKRYtexiststaccesstX_OKRZRc( R9R+tfstypet bootloaderRLt cfgdatarootRAtbmnsetfull_exec_pathtoserr((s2../../common/bootmgmt/backend/loader/legacygrub.pyRC+sN             cCsB|jtjkr|j|S|jtjkr>|j|SgS(svReturns a list of artifacts for this BootLoader, given a bootconfig to use for directory information. (R/RR2RCR0RB(R9R+((s2../../common/bootmgmt/backend/loader/legacygrub.pytprobe_artifactses   cCs[tt|jt|jtr;|jjtjnt j |jt j Load boot instances and GRUB properties from the menu.lst files+load_config() is not supported for class %sN(RzR/RR2RERFRGt_menu_lst_dir_diskR\R0R[RR]Rt __class__t__name__t_load_config_commontadd_boot_instancetFalsetdirty(RXtdo_addRdtboot_instances((s2../../common/bootmgmt/backend/loader/legacygrub.pyt load_configs  cCs|jdkr;dt|}|j|t|n|jjtjkr]|j|S|jjtj kr|j |S|jjtj kr|j |St ddS(sThe only file that needs to be written is the menu.lst file, using information from the BootConfig instance to which we have a reference. Information from the boot loader's properties is also used to determine which commands are emitted at the global levels/Cannot _write_config(%s) - _boot_config is Nones XXX - Fix MeN(RzR.RKR1RR/RR2t_write_config_diskR5t_write_config_oddR0t_write_config_netR(RXtbasepathtplatdicttmsg((s2../../common/bootmgmt/backend/loader/legacygrub.pyt _write_configs     cCs|js|jS|jj}|tjkrYtjj|jjt j |jj }ny|tj krtjj|jj t jt j }n@|tjkrtjj|jt j }ntd||jd||f|S(s~Returns the ultimate destination of menu.lst, depending on the type of BootConfig stored in self._boot_config sUnknown BootConfig class %ss+Boot class %s detected. MENU_LST_PATH => %s(RzRmR/RR0RERFRGtnet_tftproot_subdirRR\R]R5R>tMENU_LST_SUBDIRR2RRR1(RXR/t menu_lst_path((s2../../common/bootmgmt/backend/loader/legacygrub.pyt MENU_LST_PATHs(       cCs'|jjtjkr|jSdSdS(Ns /boot/grub(RzR/RR2R(RX((s2../../common/bootmgmt/backend/loader/legacygrub.pyt config_dirs cCs|jj}|dkr7|dkr7td|n|dkrR|jj}n|dkrp|jj}ntjj|tj S(NRhRgsUnknown filesystem: %s( RzR3RRkR>RERFRGRR(RXRqt menu_lst_root((s2../../common/bootmgmt/backend/loader/legacygrub.pyRs    cCs|jd|yt||_WnTtk rK}td||n/tk ry}td|t|fnXt}d-}g}xn|jj D]]}t |t ri}|j dd-k s|j dd-k rx|j D]}t |ts qn|jdkr7dj|j|dRRRRRRRRRRmRttempfiletNamedTemporaryFileRRItshutiltcopyRRRJRtOUTPUT_TYPE_BIOS_ELTORITO(RXRtodd_rootRRRttmpfileR((s2../../common/bootmgmt/backend/loader/legacygrub.pyRs6       cCs5|dkrtdn|jd||j||j}xt|D]\}}|tjslqMnt|}t j }|tjj |dkrtj |tj %ssboot/grub/pxegrubN(R.RR1RRRRRRRR\tfindtOUTPUT_TYPE_NETCONFIGRR tTOKEN_TFTP_ROOTRtOUTPUT_TYPE_BIOS_NBPRERFRGRztnet_osimage_root(RXRRRRt menulstfile((s2../../common/bootmgmt/backend/loader/legacygrub.pyRs0      cCstjj}|jjtj}|dk rGdt||d %ssAdding global commands: %sN(tsetRSRRyRRtaddR.t delete_entityRRtset_argsR1Rt differenceRKt add_global( RXRtglobal_cmd_entitiest deleted_cmdsRRt cmd_and_argstsplit_cmd_argsRtcmdlisttmissing_globalst missing_cmd((s2../../common/bootmgmt/backend/loader/legacygrub.pyRs2        )  cCs|jj}d|}t|j|d}|dk rl|jdk r_|jjd|jn|||S|jd||f|jdk rdSdSdS(sUse the BootInstance's class name to find the entry-generator method. Entry generator functions are responsible for producing a string with the rest of the entry (the title is printed by the caller)t_generate_entry_Rs$No entry generator (%s) for class %sRN(RRRiR.Rtupdate_commandRR1(RXtinstancet instclsnamet method_nametentry_generator((s2../../common/bootmgmt/backend/loader/legacygrub.pyR s        cCs4|dkrdn|}t|tjd}t|tjd}t|tjd}|jdkr|ryd|}nd}|rd|}nd}|rd|}qd}nOd}|r|d|7}nd}|rd|}nd}|rd|}ny|jid d 6|_Wn#tk rCt d |jnXd |jks_d |krod |j} n d|j} | |dksdnd|7} y|j id d 6|_ Wn#tk rt d|j nXd |j ksd | krd|j } n d|j } |jdk rx|||| | fD]y} | j dd} t | dkrw|jj | q:t | dkr:|jj| d| djdtq:q:WdSd} |dk r| |d7} n|dk r| |d7} n|dk r| |d7} n| | d7} | | 7} | S(NRs splashimage s foreground s background R%RR&R's$ISADIRtkarchRt$skernel$ skernel Rsmodule$ smodule iiitcreates (R.RiRRRRRRtKeyErrorRRRRtdelete_commandR&RR(RXRRR RRt splash_cmdtfore_cmdtback_cmdt kernel_cmdt module_cmdtnextcmdt nextcmd_argstostr((s2../../common/bootmgmt/backend/loader/legacygrub.pyt_generate_entry_generic&sx                cCs2|j||jj}|jdkr.|SdS(s N(R8RRRR.(RXRR7((s2../../common/bootmgmt/backend/loader/legacygrub.pyt&_generate_entry_SolarisNetBootInstancesc Csd}d}d}d}|jdkr|jdkrT|jdkrTtdn|jdk rw|d|j7}n|jdk rf|jdk rC|jjd}|dk rCdj|j}|j dr@|j d}t |d kr=|j d |d |d |j7}dj|g|d }q=q@qCn|dkrf|d |j7}qfn|j dkr~d}q|j jddkrd|j }q|j }n0|j dk r|j jdkr|j }n|jdk rzxr||fD]d} | j dd } t | d kr;|jj| q|jj| d| d jdtqW|j||dS|j||}d} |dkr|d} n|dkr| |d7} n| |}|S(sCMenu-entry generator function for SolarisDiskBootInstance instancesRRRRhs'bootfs and rpool properties are missingRt(Risreusing findroot hint: %sis (pool_s pool_s-B $ZFS-BOOTFSs $ZFS-BOOTFSis-B $ZFS-BOOTFS iR-s N(RqRR.RRRRRGRRRRR1RRRR/R&RR8( RXRR7Rt bootfs_cmdt findroot_cmdt findroot_origtfindroot_orig_argstfindroot_componentsR5tcmd_argst prepend_cmds((s2../../common/bootmgmt/backend/loader/legacygrub.pyt'_generate_entry_SolarisDiskBootInstancesb       $      cCs|j||jS(N(R8R(RXR((s2../../common/bootmgmt/backend/loader/legacygrub.pyt&_generate_entry_SolarisODDBootInstancesc Cs8|jdkrtdnt|jtk sHt|jdkrWtdnt|jdtk rtdnt|jdkrt|jdtk rt|jdtk rtdnt|jdkr+t|jdtkr+t|jddkr+tdnd t|jd}t|jdkrt|jdtkrxG|jdD]}|d t|7}q~Wq|d t|jd7}n|d 7}|j r|j j d rd |}n d|}d}|j r9|j r0|j j ddgdt qXd}n|j rX|j j ddnd}t|jdkr|tt|j7}n|dtt|j7}|j dk rxM||fD]?}|jdd}|j j |d|djdt qWdS|d|} |r4| d|7} n| S(s Menu-entry generator for ChainDiskBootInstance instances. This is a VERY simple use of the rootnoverify and chainloader Legacy GRUB commands. Chainloading is only supported to a specific, numbered drive, partition specification, and physical sector offset/count.schaininfo property is missingis)chaininfo must be a non-zero-length tupleschaininfo[0] must be an intis$chaininfo[1] must be an int or tupleis$chaininfo[1] must not have > 2 itemss(hdRt)R@sroot s rootnoverify t makeactiveRR-s chainloader t+Rs N(RR.RttypeRRRRRKRRt forceactiveR&Rt chainstartt chaincountRR( RXRtdiskstrt tuple_itemtroot_cmdt active_cmdtchainloader_cmdR5R@R7((s2../../common/bootmgmt/backend/loader/legacygrub.pyt%_generate_entry_ChainDiskBootInstances\*.         cCsv|j}|sdS|j}dgtj}x|D] }|jd s9d|kraq9n|djd}|ddkrtj}n|ddkrtj}n|ddkrtj}np|dd krtj }id d 6d d 6dd6}|j |dd |d,,, |

,,). | is currently defined to be a | number (valid valid 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). iRXRWRZRYR\R[s!Bad parity value in serial_paramsthwtHtswtSs'Bad flow control value in serial_paramsiRQN(RQNNNNN( RRRRRR.R1R.t PROP_SP_FLOWCRRRR(RXRRVtflowct ret_params((s2../../common/bootmgmt/backend/loader/legacygrub.pyRGs:               cCsIx'|jjD]}|jjddq Wtt|j||||S(NR(RzRt__dict__t setdefaultR.RTRtinstall(RXtlocationtforcet verbose_fileRR((s2../../common/bootmgmt/backend/loader/legacygrub.pyRmsc Cst|jts#|jddSt|dkrU|ddkrU|djpt|dko|ddko|djstd |nd g}|jdk r|d |jg7}n|r|d g7}nt|t r|j t j r|d g7}n||d|d|g7}|jddj |d}zHy%tj|dtjdtj}Wntk r_}|jd|j|j}|jtjkrd} |jr4|jjs|jjr4ddj |} |jjr| d|jj7} n|jjr4| d|jj7} q4ntd|dt|j| qn1tk r} td|dt| nXWd|r|r|ddj |IJ|jr|d|jIn|jr|d|jIn|dIJnXdS(spInvoke installgrub to write stage1 and stage2 to disk. Slice nodes (and only slice nodes) are required.s/Ignoring _write_loader() for non-DiskBootConfigNiitsiiisDevice node is not a slice: s/sbin/installgrubs-us-Fs-ms/boot/grub/stage1s/boot/grub/stage2s#_write_loader: Invoking command: %sRtstdouttstderrs_write_loader: Return code = %dRs Output from "%s" was: s : %ss : %ssinstallgrub failed for device s: Return code s4Error while trying to invoke installgrub for device s: sOutput from "%s" was:s(RyRzRR1RtisdigitRtversionR.RR-Rt PLATOPT_MBRRGRt check_calltSTORERt returncodetpopenRtINSTALLGRUB_NOUPDTRsRrRKRc( RXtdevnamet data_rootRoRpRRtpobjtcpetoutputtose((s2../../common/bootmgmt/backend/loader/legacygrub.pyt _write_loadersb ""  !   !  (#   (sbiosN(ARt __module__t__doc__tWEIGHTtSUPPORTED_PLATFORMSR\RRmRtDEFAULT_TIMEOUTRRRKRR{tINSTALLGRUB_NOEINFORR~RRRRRRRtSUPPORTED_PROPSRR|Rt classmethodR=R6R8R4R?RURBRCRwRxRRR.RtpropertyRRRRRRRRRRR8R9RBRCRPRRRRmR(((s2../../common/bootmgmt/backend/loader/legacygrub.pyR9s      4# :   ! . . ( ,  `  E  F , ; RcBseZddZdZRS(s/boot/solaris/menu.lstcCstt|j|dS(N(RTRRU(RXtfilename((s2../../common/bootmgmt/backend/loader/legacygrub.pyRUscCsdS(s Command := Keyword Arguments | VarName '=' Value Arguments := Arguments [ ]+ Argument | Argument Keyword := 'blocklist' | 'boot' | 'bootfs' | 'bootp' | 'cat' | 'chainloader' | 'cmp' | 'color' | 'configfile' | 'debug' | 'default' | 'device' | 'dhcp' | 'displayapm' | 'displaymem' | 'embed' | 'fallback' | 'find' | 'findroot' | 'fstest' | 'geometry' | 'halt' | 'help' | 'hiddenmenu' | 'hide' | 'ifconfig' | 'impsprobe' | 'initrd' | 'install' | 'ioprobe' | 'kernel$' | 'kernel' | 'lock' | 'makeactive' | 'map' | 'md5crypt' | 'min_mem64' | 'module$' | 'module' | 'modulenounzip' | 'pager' | 'partnew' | 'parttype' | 'password' | 'pause' | 'quit' | 'rarp' | 'read' | 'reboot' | 'root' | 'rootnoverify' | 'savedefault' | 'serial' | 'setkey' | 'setup' | 'terminal' | 'terminfo' | 'testload' | 'testvbe' | 'tftpserver' | 'timeout' | 'title' | 'unhide' | 'uppermem' | 'vbeprobe' Argument := [^ ]+ VarName := [A-Za-z0-9]+ Value := [^ ]+ N((RX((s2../../common/bootmgmt/backend/loader/legacygrub.pyt_analyze_syntaxs(RRRUR(((s2../../common/bootmgmt/backend/loader/legacygrub.pyRs cCstgS(N(R(((s2../../common/bootmgmt/backend/loader/legacygrub.pytbootloader_classess(*RRRRER^Rtbootmgmt.backend.loader.menulstRRRRRtbootmgmt.bootloaderRRtbootmgmt.bootconfigRRR R R R R tbootmgmt.bootutilRtbootmgmtRRRRRRRRRRtsolaris_installRRRRR(((s2../../common/bootmgmt/backend/loader/legacygrub.pyts(     (.F #