iVc@s2dZddlZddlZddlmZddlmZmZddlm Z m Z m Z m Z m Z mZmZmZdefdYZdefd YZd efd YZd e fd YZdefdYZdefdYZde fdYZdefdYZdS(s( Boot loader abstraction for pybootmgmt iN(tSystemFirmware(t LoggerMixintget_current_arch_string(t BootmgmtErrortBootmgmtNotSupportedErrort BootmgmtUnsupportedPropertyErrort!BootmgmtUnsupportedOperationErrortBootmgmtArgumentErrort BootmgmtUnsupportedPlatformErrortBootmgmtInterfaceCodingErrort#BootmgmtMalformedPropertyValueErrort BootLoadercBseZiZdZdZdZdZdZdZdZ dZ dZ d Z d Z d Zd Zd ZdZdZdZdZed ZdZdZed d\ZZZdZedZedZ edZ!e"dZ#e#j$dZ#e"dZ%dZ&ed+d+dZ(dZ)d+dZ*dZ+e,d Z-d!Z.d"Z/d+e0d#Z1d+d$Z2d+d%Z3d+d&Z4d'Z5d(Z6d)Z7e0d+d+d*Z8RS(,t min_mem64ttimeouttconsolettexttgraphicstserialtquiett splashimaget foregroundt backgroundtthemet serial_paramsiiiiiis ident-files boot-targetst write_mbrcKsddlm}|j|S(Ni(tBackendBootLoaderFactory(tbootmgmt.backend.loaderRtget(tkwargsR((s#../../common/bootmgmt/bootloader.pyRcKsdS(N(NN(tNone(tclsR((s#../../common/bootmgmt/bootloader.pytprobe`scCsgS(sUsing the bootconfig (and optionally its BootLoader instance) as sources for directory information, returns the list of artifacts found for this BootLoader. ((Rt bootconfig((s#../../common/bootmgmt/bootloader.pytprobe_artifactsdscCs|jS(N(t_dirty(tself((s#../../common/bootmgmt/bootloader.pytdirtymscCsPt|tk r!tdn||jkrL|jd|||_ndS(Nsdirty must be a bools dirty => %s(ttypetboolt ValueErrorR"t_debug(R#tvalue((s#../../common/bootmgmt/bootloader.pyR$ss cCsdS(s N(R(R#((s#../../common/bootmgmt/bootloader.pyt config_dir|scKst|_|jd|_i|_d|_|jd|_d|_|jdg|_ |j j |j||jd}|j t j|d}|jdk r|jjdk r|jj}n|jd||_dS(NR tversiont artifactstfwtypet/trootpath(tFalseR"Rt _boot_configt _bl_propsRtfirmwareR+tdata_source_boot_instanceR,t __class__t_validate_platform_and_firmwaretsetpropR tPROP_BOOT_TARGStget_rootR/(R#Rtselected_fwnamest bc_sysroot((s#../../common/bootmgmt/bootloader.pyt__init__s     c Cs|r6|jr6|r!d|_n|j}|j}n3tj|}|rW||_nt}|j}|jd||f|r|j }n |j }|j|}|st d|j |fn|dkr|} n1||krt d|j |fn|f} | S(Ns(which_platform = %s, which_firmware = %ss%s does not support platform %ss$%s does not support firmware type %s( tplatform_requestedRR3tfirmware_requestedRRRtfw_nameR(tSUPPORTED_PLATFORMSRt__name__( RR tblR-twhich_platformtwhich_firmwaretfwinsttsupported_platformstsupported_fwnamesR:((s#../../common/bootmgmt/bootloader.pyR6s4              cCs2|jdk r+|jjdk r+|jjS|jS(s=Returns the root to use as the path to boot loader data filesN(R4RR/(R#((s#../../common/bootmgmt/bootloader.pyt_get_boot_loader_data_roots cCsdS(s N((R#tbasepathtplatdict((s#../../common/bootmgmt/bootloader.pyt _write_configscCsdS(s N((R#tdevnamet data_roottforcet verbose_fileRJ((s#../../common/bootmgmt/bootloader.pyt _write_loaderscCsdS(sIf do_add is True, boot instances loaded from the configuration are added to the BootConfig associated with this BootLoader instance. N((R#tdo_add((s#../../common/bootmgmt/bootloader.pyt load_configscCs'|jtj}i|tj6|_dS(s N(R2R R8(R#t boot_targs((s#../../common/bootmgmt/bootloader.pyt new_configscCsdS(sReturns a tuple of ([Boot Instances], {Properties}) that were loaded from this BootLoader's configuration files. N(NN(R(R#((s#../../common/bootmgmt/bootloader.pytmigrate_configsc Cstjf}t|dg}||krI||krIt|dn|sS|Si|jtj6|jtj6|jtj6}|j |}|r||}|dkr|Sn|S(s.Validate the property key and optionally valuetSUPPORTED_PROPSs is not a supported propertyN( R R8tgetattrRt_validate_boot_targst_validate_serial_paramstPROP_SERIAL_PARAMSt_validate_theme_namet PROP_THEMERR( R#tkeyR)tvalidate_valuet specialpropstpropst validatorstvalfunctrv((s#../../common/bootmgmt/bootloader.pyt_prop_validates    cCs?|r;t|t s#|j r;ttj|dn|S(s5Ensures the theme name is alphanumeric ONLY. sTheme name must be alphanumeric(t isinstancet basestringtisalnumR R R\(R#R)((s#../../common/bootmgmt/bootloader.pyR[s# cCsW|d ks*t|ts*t|tr.|St|trAdd d d d d g}|jd}t|tjkrt tj |nyt|tj kr|tj j }|dkrd }n t |}||tj , , , , , ) depends on the platform and boot configuration that this BootLoader is associated with (defined in child classes). is the path from which the file should be copied. is the path to which the file should be copied (tokens are embedded in the path to instruct the consumer of the final location (see the commit_boot_config() documentation in children of BootConfig for a list of tokens and their expansions)). , , and are the uid, gid, and permissions mode bits (respectively) that should be set on the destination file. If force is True, then the boot loader will be installed forceably (i.e. even if the version of the bootloader on disk is the same or newer). The FORCE flag overrides any checking that the bootloader backend may do. Various platform option flags may also be supported by the bootloader backend and may be required to properly install the boot loader (for example, the PLATOPT_MBR flag is required if the system was originally installed with the boot loader written to the MBR). If verbose_file is not None, it is treated as a file object and the boot loader installation process will be verbosely logged to that file. If platdict is not None, it contains platform-specific key-value pairs that affect how the platform-specific BootLoader subclass behaves. The definition of those keys used in the dict are described by the BootLoader subclasses. sError while accessing "%s": %ssHInvalid location argument (%s) (not a dir and not a char-special device)s-location is empty: Loader will NOT be writtensError stat()ing %s: %stBOOTMGMT_TESTINGsR%s is not a character-special fileN(RHReRftoststattst_modetOSErrortBootLoaderInstallErrortstrerrortS_ISDIRRKtS_ISCHRRPRRR(tgetenv( R#tlocationRNRORJRMtfilemodeRttuplesRL((s#../../common/bootmgmt/bootloader.pytinstallsH9      N(9RAt __module__R@t PROP_MINMEM64t PROP_TIMEOUTt PROP_CONSOLEtPROP_CONSOLE_TEXTtPROP_CONSOLE_GFXtPROP_CONSOLE_SERIALt PROP_QUIETt PROP_SPLASHtPROP_FORECOLORtPROP_BACKCOLORR\RZRtRwRxRzRyR|RstPROP_IDENT_FILER8trangetARTIFACT_BOOTLOADER_TOOLStARTIFACT_BOOTLOADER_IMAGEStARTIFACT_BOOTLOADER_CONFIGFILESt PLATOPT_MBRt staticmethodRt classmethodRR!tpropertyR$tsetterR*R<RR6RHRKRPRRRRTRUR0RdR[RYRXR7RRR(((s#../../common/bootmgmt/bootloader.pyR )s^     )       K    tProxyBootLoadercBs|eZdZdZdZedZedZdZdZ dZ dZ e ddd Zd Zed Zejd Zed ZedZedZedZedZedZedZejdZedZejdZedZejdZedZedZdZRS(sA proxy BootLoader class that, given two BootLoader instances, directs method calls from consumers to either the primary or secondary boot loaders, depending on which one can best service the method in the context of the current dataroot. cCs|j|jk s!|jdkr0tdn|j|jk rQtdn|j|_|j|_||_||_d|_d|_g|_g|_ t |jj }|jj |_ |t |d|j|jj}||j_ dS(s sWPrimary and secondary boot loaders must reference the same non-None BootConfig instancesTPrimary and secondary boot loaders must reference the same data_source_boot_instancetinterposed_delete_boot_instanceN(R1RR R4t+_ProxyBootLoader__data_source_boot_instancet_ProxyBootLoader__primaryt_ProxyBootLoader__secondaryt_ProxyBootLoader__load_sourcet%_ProxyBootLoader__prim_boot_instancest$_ProxyBootLoader__sec_boot_instancesR%tdelete_boot_instancet"_ProxyBootLoader__saved_dbi_methodRWR5(R#tprimary_loadertsecondary_loadert instmethtypetnewmeth((s#../../common/bootmgmt/bootloader.pyR<s&         cCs|j|j_dS(s?Restore the interposed BootConfig.delete_boot_instance N(RR1R(R#((s#../../common/bootmgmt/bootloader.pyt__del__scCs~|j||}|jd||jrz|j}|j|_|j||}|jd||j|_||_n|S(sThis method is an interposer that acts to trap calls to the associated BootConfig's delete_boot_instance() method. The arguments to this method are (a) self, the ProxyBootConfig instance (which is passed by binding this method to the instance via getattr()), (b) bcself, the BootConfig instance reference which is bound via the instantiation of the interposer method, above, and (c)/(d) the normal arguments to delete_boot_instance(). This method will call the BootConfig's delete_boot_instance() method to delete instances in the original boot_instances list, then will swap out that list for the secondary boot loader's boot instance list and repeat the call. The assumption is that calling delete_boot_instance twice will not have any side effects other than changes to the boot_instances list and possibly marking the BootConfig as dirty. It is still desirable to mark the BootConfig as dirty, even if 0 boot instances are deleted from the primary boot loader's boot instance list as long as >0 are deleted from the secondary's list. s1Deleted %d instances from the primary boot loaders3Deleted %d instances from the secondary boot loader(RR(Rtboot_instances(R#tbcselft filter_functalltinstances_deletedtsaved_boot_instancest sec_deleted((s#../../common/bootmgmt/bootloader.pyR$s       c Cs+|j|jjt}|s+g}nt||_|j|_g|_tj |j j krt|j j ntj |jj krmtj |j j krmx6|jD]+}|j }||_|jj|qWt|jjjt|j j}x]|D]U}y)|jj|}|j j||Wqtk rY}|jd|qXqWt|j _nBtj |j j kr|j jt|_|jsg|_qnx\|jD]Q} xH|jD]=}| j|trt|dddkr|| _PqqWqW|r'|jj|n|S(s<If do_add is True, boot instances loaded from the configuration are added to the BootConfig associated with this BootLoader instance. This is where the magic happens for the BootLoader upgrade case (where we have a primary with configuration files, but a secondary without configuration files, boot loader properties are migrated from primary to secondary. Boot instances already loaded by the primary into the BootConfig will be written to the proper boot loader's configuration files at install() time.) s&Exception while copying properties: %stlinked_boot_instanceN(t&_ProxyBootLoader__reevaluate_artifactsRRRR0RpRRRR RRR,RTtcopyRtappendtsetRVt intersectionRR7RR(RR$tcompareRWRR1tadd_boot_instance( R#RQtload_rvtinsttsec_instt props_to_copytpropnametpropvaltbmerrt prim_inst((s#../../common/bootmgmt/bootloader.pyRREsT            cCs|jj|jjdS(s\This is the one case where we need to call new_config on BOTH boot loaders. N(RRTR(R#((s#../../common/bootmgmt/bootloader.pyRTs cCs|jj||dS(sSet a Boot Loader property. Raises BootmgmtUnsupportedPropertyError if the property is not supported - reflect to primary bootloaderN(RR7(R#R]R)((s#../../common/bootmgmt/bootloader.pyR7scCs|jj|S(s:Get a Boot Loader property - reflect to primary bootloader(RR(R#R]((s#../../common/bootmgmt/bootloader.pyRscCs|jj|dS(s=Delete a Boot Loader property - reflect to primary bootloaderN(RR(R#R]((s#../../common/bootmgmt/bootloader.pyRsc Cs;|j|jj|jjkr@tj|jjkr@t}nt}|sY|j n|j r{|j d|j j n|j |jkrI|j d|jj t |trtjj|r|}ng}|jj|t||}|jj}|j|j_|j d|jj |jj||||} ||j_n|j d|jj t |trtjj|r|}ng}|s|jj}|j|j_|jj|t||}||j_nd}|j d|jj |jj||||} t | tr7t |tr7| |S| S(sThis is the other part of the magic of the upgrade case. When the consumer sets the data_source_boot_instance, the proper primary boot loader is swapping into the __primary slot, and so will be installed here. Additionally, we call each boot loader's install() method after swapping its set of boot instances into the BootConfig instance's boot_instances list. sLoad source is %ss.Installing secondary boot loader %s files onlys!Installing primary boot loader %sN(RRtWEIGHTRR RR,RR0t,_ProxyBootLoader__synch_primary_to_secondaryRR(tnameReRfRtpathtisdirRR1RRRRp( R#RRNRORJtdisable_secondary_updatetsecinstt sec_inst_rvtbc_boot_instancest prim_inst_rv((s#../../common/bootmgmt/bootloader.pyRsX      !        !       cCs|jj}|j|j_x|D]}||jkr|jd||j}|jtkrg|jD]}|jtkrl|^ql}x|D]}t|_qWn|jj |||_ |jj |q"t |ddr"|jd|j |j }|jd|||j f|tkr|jd||j f|j j||jtkrg|jD]}|jtkrq|^qq}x|D]}t|_qWn|j|j _qq"q"W||j_dS(sKSynch the set of boot instances from the primary to the secondary. s0Adding new boot instance to secondary loader: %sRsFound a linked boot instancescmp = %s for %s vs %ss(Update needed for boot instance %s -> %sN(R1RRRR(RtdefaultRR0RRRWRRtupdate(R#RRRtxtdeflisttdefitemtcmpval((s#../../common/bootmgmt/bootloader.pyt__synch_primary_to_secondarys>           cCs |jjS(N(RR$(R#((s#../../common/bootmgmt/bootloader.pyR$ascCs||j_dS(N(RR$(R#R)((s#../../common/bootmgmt/bootloader.pyR$gscCs |jjS(sCShadow the primary boot loader's SUPPORTED_PROPS attribute (RRV(R#((s#../../common/bootmgmt/bootloader.pyRVmscCs |jjS(s3Returns the primary bootloader's artifacts (RR,(R#((s#../../common/bootmgmt/bootloader.pyR,tscCst|jdgS(s=Shadow the primary boot loader's pkg_names attribute t pkg_names(RWR(R#((s#../../common/bootmgmt/bootloader.pyRzscCs t|jdr|jjSdS(s;Returns the config_dir for the primary boot loader R*N(thasattrRR*R(R#((s#../../common/bootmgmt/bootloader.pyR*s cCs |jjS(s8Shadow the primary boot loader's name attribute (RR(R#((s#../../common/bootmgmt/bootloader.pyRscCs |jjS(s<Shadow the primary boot loader's firmware attribute (RR3(R#((s#../../common/bootmgmt/bootloader.pyR3scCs |jjS(s<Shadow the primary boot loader's rootpath attribute (RR/(R#((s#../../common/bootmgmt/bootloader.pyR/scCs&||j_||j_|jdS(siSet the primary boot loader's rootpath attribute and reevaluate both loaders' artifacts. N(RR/RR(R#tval((s#../../common/bootmgmt/bootloader.pyR/s  cCs |jjS(s;Shadow the primary boot loader's version attribute (RR+(R#((s#../../common/bootmgmt/bootloader.pyR+scCs||j_dS(s8Set the primary boot loader's version attribute N(RR+(R#t version_str((s#../../common/bootmgmt/bootloader.pyR+scCs|jS(s_Returns the data_source_boot_instance that applies to the proxied BootLoaders. (R(R#((s#../../common/bootmgmt/bootloader.pyR4scCs/||j_||j_||_|jdS(sIntercept setting the data_source_boot_instance so we can invoke each proxied BootLoader's probe_artifacts() class method, to update the set of artifacts supported for the new data root. N(RR4RRR(R#tnew_dsbi((s#../../common/bootmgmt/bootloader.pyR4s   cCstj|jk}tj|jk}|r1| sO|rS|rS|j|jkrS|S| r`|s~|r|r|j|jkr|SdS(N(R RR,RR(Rtyt x_has_imagest y_has_images((s#../../common/bootmgmt/bootloader.pyt__bootloader_with_imagess    cCsbtj||}||kr"dS||kr2dS|j|jkrHdS|j|jkr^dSdS(sCompare two BootLoader instances. The one that includes boot loader images wins. If both have them, the one with the higher weight wins. iii(Rt(_ProxyBootLoader__bootloader_with_imagesR(RRtwhich((s#../../common/bootmgmt/bootloader.pyt&bootloader_cmp_by_artifacts_and_weights  cCs|jj|jk r9|j}||j_||j_n|jj|j}|jdt||jj|j}|jdt|||j_||j_|j |j|j}||jkr|jdt |jt |jf|j|j|_|_ndS(sEnsure that the artifact lists for each BootLoader is up to date with respect to the associated BootConfig's rootpath and this instance's data_source_boot_instance. s Primary bootloader artifacts: %ss"Secondary bootloader artifacts: %ss!Swapping boot loaders [%s <=> %s]N( RR4RRR!R1R(RR,Rtrepr(R#Rtprim_artifactst sec_artifactsR((s#../../common/bootmgmt/bootloader.pyt__reevaluate_artifactss        N( RARt__doc__R<RRRRRRTR7RRR0RRRRR$RRVR,RR*RR3R/R+R4RRRR(((s#../../common/bootmgmt/bootloader.pyRs8 %  ! S    j K  tDualBootLoadercBseZdZedZdZdZdZdZdZ e dddZ e dZejd Ze d Ze d Zejd Ze d ZejdZe dZRS(sA skeletal BootLoader class that manages two underlying BootLoader instances. Used only for building ODDBootConfig derivative instances with multiple boot loaders (typically grub2 and zvboot or sbb and zvboot).cCs|dkr|dkrdS|dkr,|S|dkr<|St|trbt|trb||St|tr|||gSt|tr|g|S||S(N(RReRp(tfirsttsecond((s#../../common/bootmgmt/bootloader.pyt_merge_results s    cCs||_||_dS(N(t_DualBootLoader__first_loadert_DualBootLoader__second_loader(R#t first_loadert second_loader((s#../../common/bootmgmt/bootloader.pyR<s cCs|jj|jjdS(N(RRTR(R#((s#../../common/bootmgmt/bootloader.pyRT"s cCsd}d}y|jj||}Wntk r@}|}nXd}d}y|jj||}Wntk r}|}nX|dks|dkr|j||Std||p|dS(Nskey `%s' does not exist(RRR7t ExceptionRRR(R#R]R)t first_errRRt second_errR((s#../../common/bootmgmt/bootloader.pyR7&s   cCsd}y|jj|}Wntk r/nXd}y|jj|}Wntk r_nX|j||}|dkrt|dn|S(Ns is not a supported property.(RRRRRR(R#R]RRtresult((s#../../common/bootmgmt/bootloader.pyR<s   cCs|j|dt|tjkr5td|nd}y|jj|Wntk rj}|}nXd}y|j j|Wntk r}|}nX|dks|dkrdStd||p|dS(NR^skey `%s' may not be deletedskey `%s' does not exist( RdR0R R8RRRRRR(R#R]RRR((s#../../common/bootmgmt/bootloader.pyRRs$   cCsF|jj||||}|jj||||}|j||S(N(RRRR(R#RRNRORJRR((s#../../common/bootmgmt/bootloader.pyRmscCs|jjp|jjS(N(RR$R(R#((s#../../common/bootmgmt/bootloader.pyR$rscCs$|jj||jj|dS(N(RR$R(R#R)((s#../../common/bootmgmt/bootloader.pyR$vscCs|jj|jjS(N(RRVR(R#((s#../../common/bootmgmt/bootloader.pyRV{scCs |jjS(N(RR4(R#((s#../../common/bootmgmt/bootloader.pyR4scCs||j_||j_dS(N(RR4R(R#R((s#../../common/bootmgmt/bootloader.pyR4s cCs |jjS(N(RR/(R#((s#../../common/bootmgmt/bootloader.pyR/scCs||j_||j_dS(N(RR/R(R#R((s#../../common/bootmgmt/bootloader.pyR/s cCs |jjS(N(RR(R#((s#../../common/bootmgmt/bootloader.pyRsN(RARRRRR<RTR7RRR0RRRR$RRVR4R/R(((s#../../common/bootmgmt/bootloader.pyRs      RcBseZRS((RAR(((s#../../common/bootmgmt/bootloader.pyRstBootPartitionAccessErrorcBseZRS((RAR(((s#../../common/bootmgmt/bootloader.pyR stBootDeviceNotFoundErrorcBseZRS((RAR(((s#../../common/bootmgmt/bootloader.pyR st!BootLoaderFeatureUnsupportedErrorcBseZRS((RAR(((s#../../common/bootmgmt/bootloader.pyR st"BootLoaderUnsupportedPartTypeErrorcBseZRS((RAR(((s#../../common/bootmgmt/bootloader.pyR s(RRRtbootmgmt.bootinfoRtbootmgmt.bootutilRRtbootmgmtRRRRRRR R R RRRR R R R (((s#../../common/bootmgmt/bootloader.pyts   :