iVc@sdZddklZlZlZlZlZlZlZl Z l Z l Z l Z l Z lZlZlZlZlZlZddklZlZddklZddklZlZlZlZlZlZl Z l!Z!l"Z"ddk#l$Z$ddk%l&Z&l'Z'l(Z(l)Z)ddk*Z*ddk+i,Z,ddk-i,i.i/Z/ddk0i,i.i1Z1ddk2Zdd k2l3Z3dd k4l4Z4ddk5Z5ddk6Z6ddk7Z7ddk8Z8ddk9Z9ddk:Z:ddk;Z;ddk<Z<ddk=Z=d Z>d efd YZ?defdYZ@defdYZAdefdYZBdefdYZCdeDfdYZEdeDfdYZFdeFfdYZGdeFfdYZHdeFfdYZId eEfd!YZJd"eEfd#YZKd$eEfd%YZLd&eEfd'YZMd(eEfd)YZNd*eCeJeKeLeMfd+YZOd,eCeJeNfd-YZPd.efd/YZQdS(0s VersaBoot Implementation i(tBootmgmtInvalidPropertyErrort$BootmgmtMissingRequiredPropertyErrort#BootmgmtMalformedPropertyValueErrortBootmgmtNotSupportedErrortBootmgmtPropertyReadErrortBootmgmtZFSErrortBootmgmtZFSPoolNotFoundErrort!BootmgmtUnsupportedOperationErrortBootmgmtConfigReadErrortBootmgmtConfigWriteErrort"BootmgmtInsufficientDiskSpaceErrort BootmgmtErrort"BootmgmtVersabootNotSupportedErrortBootmgmtInvalidParameterErrort"BootmgmtInvalidParameterValueErrortBootmgmtReadOnlyStateErrortBootmgmtBootPoolCreationErrortBootmgmtBootPoolFailureError(t LoggerMixintget_current_arch_string(tSystemFirmware( t platform_nametsynch_file_am_timestcompare_usec_file_mtimetprom_get_bootdev_listtdevfs_bootdev_set_listtprom_devfs_to_prom_pathstprom_get_chosen_proptBOOTDEV_OVERWRITEtBOOTDEV_LITERAL(tcontextmanager(tRawConfigParsert NoOptionErrortMissingSectionHeaderErrort ParsingErrorN(tSolarisDiskBootInstance(tdatetimecCs/|id}t|djodS|dS(Nt/ii(tsplittlentNone(tdsnamet components((s"../../common/bootmgmt/versaboot.pytpool_from_dsname;st RecoveryFilecBsqeZdZdZddZdZdZdZdZdZ d Z d Z d Z d Z RS( s0 A simple-to-parse text file format used to hold property values for recovery purposes. Secure properties are stored with property names prepended with SECURE_PROP_PREFIX + ":". A simpler format than ConfigParser allows the kernel's early-boot parser to remain straightforward. tsecureicCs_||_||_||_||_h|_h|_d|_t|_ t|_ |i dS(s N( t_dirnamet _filenamet _file_ownt _file_permst _propdictt _spropdictR(t_fileobjtFalset_dirtytreadonlyt_load(tselftdirnametfilenamet ownershiptperms((s"../../common/bootmgmt/versaboot.pyt__init__Ls         cCs|io|iiny+ttii|i|id|_Wn[tj oO}|i d|i t i jodS|i t i jot |_dSnX|io@h|_h|_x+|iD]}|i|idqWnt|_dS(s( Load the recovery file trsNo recovery file foundNs (R4tclosetopentostpathtjoinR.R/tIOErrort_debugterrnotENOENTtEPERMtTrueR7R2R3t _parse_linetstripR5R6(R9tioerrtline((s"../../common/bootmgmt/versaboot.pyR8Zs&        cCs.|io|iid |_nytid|idt}Wn1tj o%}td|i|i fnXx:|i i D])\}}d||f}|i |qWx@|i i D]/\}}dti||f}|i |qW|itii|i|i}|id|i|fyti|i|yLti||id|id|id joti||inWn.tj o"}|id ||i fnXWn^tj oR}yti|iWntj onXtd |i||i fnXd S( s tdirtdeletes1Couldn't create temporary recovery file in %s: %ss%s=%s s %s:%s=%s sTrying to rename %s to %siiis4OSError when setting ownership/permissions of %s: %ss/Couldn't rename temp recovery file %s to %s: %sN(R4R@R(ttempfiletNamedTemporaryFileR.R5tOSErrorR tstrerrorR2titemstwriteR3R,tSECURE_PROP_PREFIXRBRCRDR/RFtnametrenametchownR0R1tchmodtunlink(R9ttmpftoserrtkeytvalRNtdestfile((s"../../common/bootmgmt/versaboot.pyt_writersF      ! cCs|idd}|di}|di|d<|did}|djo2|id||d|f||i|d= secure:= t=iit:isParsed `%s' to %s=%ss Malformed line `%s' (bad prefix)N(R&RLtfindRFR2R,RWR3(R9RNt equal_splittvaluetcolonR_((s"../../common/bootmgmt/versaboot.pyRKs cCsK|ii|djp|i||jo t|_n||i|R8RbRKRlRnRoRqR@Rr(((s"../../common/bootmgmt/versaboot.pyR,As   /     tBootPoolConfigcBseZdZdZdZdZdZdZeegZhee6Z hee6Z e dZ dZ dZd Zed Zed Zd Zd ZedZRS(s sbpool-device-listsbpool-exclude-listteviction_algorithmtnonetlruc Cs*|itiiijotdn|idjotdntii |i ||_ ||_ ||_ tii |i ||_||_||_|id|id|_g|_g|_h|_g|_g|_h|_ti|iti<||_| o|indS(s sABootPools are supported on disk-based BootConfig subclasses onlytzfssKBootPools are supported on ZFS-based disk-based BootConfig subclasses onlysConfig file is %sN(t boot_classtbootmgmtt bootconfigt BootConfigtBOOT_CLASS_DISKRt boot_fstypeRBRCRDtzfstopt_cfg_dirt _cfg_dir_ownt_cfg_dir_permst _cfg_filet _cfg_file_ownt_cfg_file_permsRFR(t_cfgt _device_listt _exclude_listt_BootPoolConfig__paramst device_listt exclude_listt_paramsRvtBPC_EVICT_ALGO_LRUtBPC_PROP_EVICTION_ALGOt bpool_nameR8( R9tbootcfgRtcfgdirtcfgdir_ownershipt cfgdir_permst cfgfilenametcfgfile_ownershipt cfgfile_permstloadnow((s"../../common/bootmgmt/versaboot.pyR>s,            cCs:t|i|_t|i|_t|i|_dS(s N(tlistRRRRtdictRR(R9((s"../../common/bootmgmt/versaboot.pyt_update_shadowssc Cst|_y|ii|iWnptj o.}d|_td|i|ifn8tt fj o%}td|i|i fnX|i d|i |ii |i pdSy|ii|i ti}Wntj o d}nXy|ii|i ti}Wntj o d}nXti}xtiD]}yn|ii|i |}ti|}||jo+|i d||f|||i|ti|i|id|idti|i|iWn1tj o%}|id|i|ifnX|iWn1tj o%}t d|i|ifnXdS(s RtwNiis(OSError when setting ownership of %s: %ss5Couldn't create boot pool configuration file (%s): %s(!RRRJRRt add_sectiontsetRvRRDRRRRRRt _make_cfg_dirRARt__exit__t __enter__RVRBRZRR[RRSRFRTRRER (R9taddsectRRRtfileobjR^RM((s"../../common/bootmgmt/versaboot.pyt_save_sB     $$ ) c Cs|i}|odSy.tii|pti||inWn.tj o"}td||ifnXy%ti ||i d|i dWn.tj o"}|i d||ifnXdS(s@Create the parent directories of the configuration file Ns,Couldn't create boot data directory (%s): %siis*OSError when changing owner/perm of %s: %s( RRBRCtexiststmakedirsRRSR RTRZRRF(R9R7tdatadirtdiroserrR^((s"../../common/bootmgmt/versaboot.pyRs % cCstiS(s (RvR(R9((s"../../common/bootmgmt/versaboot.pytsettable_parametersscCsU|tijot|n|ti|jot|n||i|RR8RR5RtpropertyRRRRr(((s"../../common/bootmgmt/versaboot.pyRvs$    #  A ,  tBootPoolcBseZdZdZeidiZei di Z dZ dZ eidiZei di ZdZdZeidiZei di ZdZdZdOdPgZdQgZhed6Zhed6ed6ZddedRedZdZdZdZ e!dZ"dZ#e$dZ%e$dZ&eedZ'dZ(dZ)e*dZ+e!dRdZ,d Z-d!Z.d"Z/d#Z0d$Z1e!d%Z2d&Z3d'Z4d(Z5e$d)Z6ed*Z7d+Z8d,Z9d-Z:d.Z;d/Z<d0Z=d1Z>d2Z?dRed3Z@d4ZAee*e*ed5ZBd6ZCed7ZDeeed8ZEd9ZFeGd:ZHeGdRdRd;ZId<ZJd=ZKe!d>ZLd?ZMd@ZNdAZOe$dBZPdCZQdDZRedRdRdRdEZSdFZTedGZUdRedRdRdHZVdIZWdJZXdRdKZYeGedLZZdMZ[dNZ\RS(Ss The BootPool class encapsulates knowledge of a VersaBoot boot pool, which is a ZFS pool whose function is to store boot archives that are used to boot the system. tboottrootis bpool.confis recovery.kvpiscom.oracle:boot-poolsplatform/i86pc/kernel/amd64tunixsplatform/i86pc/amd64t boot_archivesplatform/%(platformname)st platformnametx86tsparctbpooltautocCs|itiiijotdn||_||_||_t i ||_ |i oj|i d|t i |oFyt i|t|_ Wqtj o}|i d|qXqng|_g|_g|_d|_d|_t|_t|_|o|i||_n|ig|_|ioUxR|iD]C}|i||ijo$||ijo|ii|qIqIWn|djo|i} n ddk} t || i!ot"|} n |g} |i#t|_$|i%|i} g} | D]} | | jo | | qq~ }|o|i$i&i'|ng}| D]} | | jo || qhqh~}|o'|i$i(i'||i d|n|i d| | |_)|i oJ|i*\}}}|i d ||f||_||_||_+nt|o|i,n|oW|i oLy|i-d t.d t.Wqt/j o}|i d t0|qXnd t1i2ds                   22        cCs+|io|i}|i|ndS(s N(Rt_get_default_boot_instancest"_complete_boot_pool_loader_install(R9R((s"../../common/bootmgmt/versaboot.pyt deferred_initJs  cCsyPti|i}ti|}ti|}ti|}|||fSWn2tj o&|id|itifnXgdfS(s s*Couldn't get boot pool (%s) disk list (%s)N( Rztzpool_get_configRtzpool_config_to_disklisttzpool_config_to_partlisttzpool_config_to_healthlistRRFtzfs_error_stringR((R9t confignvlRRR((s"../../common/bootmgmt/versaboot.pyRQs c Csti|i|i}y(|id|i||ddfWntj onXy(ti||_ti||_ Wn%tj o}|id|nXdS(sh Imports the boot pool using the membership list as the set of devices to scan. sESuccessfully imported boot pool `%s' with the following config: %s %st vdev_treetchildrens0Error getting current disk list from boot pool: N( Rzt zpool_importRRRFtKeyErrorRRRR(R9R tkeyerr((s"../../common/bootmgmt/versaboot.pyt_import_boot_poolas   cCsti|ti}|S(s Returns the name of the boot pool associated with the specified root pool (if any), or None is there are none. (Rztzfs_get_user_propRtZFS_PROP_BOOTPOOL_LINKAGE(tclst rpoolnametprop((s"../../common/bootmgmt/versaboot.pyRws  cCs|g}|D]!}ti|o ||q q ~}t|t|}t|djo|idt|n|S(s is!Filtered out nonexistent pools %s(RzRRR'RFR(R9tpoolsRtpooltnewlisttdiffset((s"../../common/bootmgmt/versaboot.pyRs 5cCs|iS(s (R(R9((s"../../common/bootmgmt/versaboot.pytimportedscCs|iS(s (R(R9((s"../../common/bootmgmt/versaboot.pyt pool_namesc Cs|io|iio t}nt}y^|id|i|if|otid|iIJnt i |i|it|_ WnEt j o9}|i tijot|_dSt|inXys|it|_|i\}}}|id|i|f||_||_||_|id|iWn(t j o}|id|nX|i|pdS|otidIJn|i}|idtd td t|otid IJn|p|i|ndS( se Create the boot pool and add linkage to any root pool currently associated. s%Creating boot pool %s with members %ssCreating boot pool %s...Ns/[post-create] Current disks in boot pool %s: %ss!successfully created boot pool %ss'Exception during boot pool creation: %ss(Synchronizing essential BE boot files...t clear_firsttverboset noevict_onlys&Installing boot loader on boot pool...(RRRJR5RFRRtsyststderrRztcreate_boot_poolRRt zfs_errnotconstt EZFS_PERMR7Rtmsgt_boot_pool_update_linkageRRRRRt_synch_plat_boot_ordert_synch_default_boot_instancet full_resynchR( R9RRRtzfserrRRRR((s"../../common/bootmgmt/versaboot.pyRsN            c Cs|io|iio t}nt}|ii|i}d }d }|o|d}|i}|o-|iddjo|i dd}n|o<|o5ddk l }||i|||ii |}qn|o t i} nd } z |id|dtd| Wd |or|okti|} | djotd |nyti|Wqtj o|id |qXnXd S( s iR%ii(t#prep_be_for_bootloader_installationt boot_devicesRt verbose_fileNsUnable to unmount BE %ssCouldn't remove mountpoint %s(RRRJR5t_complete_boot_device_listtboot_device_listR(tbootfstcountR&tlibbeR,RR R!t_boot_pool_install_loadertlibbe_pyt beUnmountR RBtrmdirRSRF( R9RRR-tmntpttbe_nametbinsttroot_dsR,t verb_filetret((s"../../common/bootmgmt/versaboot.pyRs<        cCsy*|it|_|id|iWnStj o|id|in/tj o"}|id|i|fnXdS(s If the boot pool doesn't exist on the system, try to use zfs to import it. If that fails, we're out of luck. s"Successfully imported boot pool %ssCouldn't find boot pool %ss#Error while trying to import %s: %sN(RRJRRFRRR(R9R((s"../../common/bootmgmt/versaboot.pyRs   c CsOt|i|itititiftititi ti fti d|S(s R( RvRRRtBOOT_POOL_CFG_SUBDIRtBOOT_POOL_CFG_SUBDIR_OWNERtBOOT_POOL_CFG_SUBDIR_GRPtBOOT_POOL_CFG_SUBDIR_PERMStBOOT_POOL_CFG_FILEtBOOT_POOL_CFG_FILE_OWNERtBOOT_POOL_CFG_FILE_GRPtBOOT_POOL_CFG_FILE_PERMS(R9R((s"../../common/bootmgmt/versaboot.pyRs   cCsy|o'|io|iio|ii}n ti}|iti}t|to|i}n|djo g}nWn&t j o|i dg}nXxGt |D]9\}}|i |i||<|i d||qW|S(Ns.Couldn't get list of boot pool members from FWs$boot pool list item normalized to %s(t boot_loadertfirmwareRRiRotPROP_BOOT_POOL_LISTRt basestringR&R(RRFt enumeratet_whole_disk_devRL(RRtfwtbplisttindextitem((s"../../common/bootmgmt/versaboot.pyR#s$      cCs|i|i}g}y|i|_t|ii}|ii}|id||id|xJ|D]B}||jo|i|n||jo|i |qoqoW|i |Wn8t j o,}|id|i d|_|}nX|S(s Loads the set of devices that should be in the boot pool. First, we consult the firmware device list, then add devices from the OSdb, and finally we prune devices excluded by the OSdb. sBPC device list is %ssBPC exclude list is %ss'Loading the boot pool config failed: %sN(RRRRRRRRFtremoveRRRRTR((R9RMt final_listtbpc_listRROtbcre((s"../../common/bootmgmt/versaboot.pyRBs*       cCs|idS(s Create the boot pool and add linkage to each of the passed root pools to the created boot pool, but does NOT synch any boot artifacts from the root pools, NOR does it install the bootloader. N(R(R9((s"../../common/bootmgmt/versaboot.pyRmscCs t|iS(s (RR(R9((s"../../common/bootmgmt/versaboot.pytpending_membershipvscCs t|iS(s (RR(R9((s"../../common/bootmgmt/versaboot.pytcurrent_membership|scCs |iot|iSdSdS(s N(RRR((R9((s"../../common/bootmgmt/versaboot.pyR0s cCsC|id}|djo|S||dio || S|S(s tsii(trfindtisdigit(Rtdevnametlast_s((s"../../common/bootmgmt/versaboot.pyRKs   cCs|i|}||ijo|id|dS|ii||id|i|iii|y6|iii|}|id||ii|=Wntj onXdS(s s#%s already in boot pool member listNs New boot pool members list: `%s's$Found %s in exclude list -- removing( RKRRFRRRRRNt ValueError(R9tdevpatht found_index((s"../../common/bootmgmt/versaboot.pyt add_devicescCs|i|dS(s N(t_remove_device(R9R\((s"../../common/bootmgmt/versaboot.pyt remove_devicescCs|i|dtdS(s texcludeN(R_RJ(R9R\((s"../../common/bootmgmt/versaboot.pytexclude_devicescCst|iiS(N(RRR(R9((s"../../common/bootmgmt/versaboot.pytexcluded_devicessc Cs|i|}|oO||iijo|id|dS|iii||id|ny0|ii|}|id||i|=Wntj onXy6|iii|}|id||ii|=Wntj onXdS(s s&%s already in boot pool exclusion listNs$%s added to boot pool exclusion lists(Found %s in _bp_members list -- removings#Found %s in device list -- removing( RKRRRFRRRNR[R(R9R\Rat found_idx((s"../../common/bootmgmt/versaboot.pyR_s&cCs9|i\}}|djo|djotStSdS(s Returns True of a membership change on the boot pool is needed based on the current state (current members vs. desired members) of the instance. N(t_compute_membership_changesR(R5RJ(R9taddlistt removelist((s"../../common/bootmgmt/versaboot.pytsynch_membership_neededscCs |iS(s (t_do_synch_membership(R9((s"../../common/bootmgmt/versaboot.pytsynch_membershipscCst|i}t|i}|i|}|pdSg}|D]}||jo ||qDqD~}t|t|}|id||f||fS(s sAdd set = %s | Remove set = %sN(NN(RRRtsymmetric_differenceR(RRF(R9t curmembsett pendmembsettdevsRtdevtadd_listt remove_list((s"../../common/bootmgmt/versaboot.pyRes2c Cs}|i\}}|o/| o'|i o|id|idS|ony5ti|i|\}}|id||fWqtj o&|id|itifqXn|oPyti |i|Wqtj o&|id|itifqXn|p|oW|i \}}}|o||_ ||_ ||_ n|id|itStS(s s*Creating boot pool due to membership synchNsadd: success=%s | failed=%ss)Error adding devices to boot pool %s (%s)s-Error removing devices from boot pool %s (%s)s#Problem getting boot pool disk list(ReRRFRRztadd_devices_to_poolRRR tremove_devices_from_poolRRRRR(RJR5(R9RpRqtsuccesstfailedRRR((s"../../common/bootmgmt/versaboot.pyRis:         c Cstitit}x9t|D]+\}}|d|i|df||s(twalk_be_datasetstsort(R9RRtargdict((R9s"../../common/bootmgmt/versaboot.pyt_build_mru_list^s  c Cs|i}x|D]}|d}|do|id|qn||jo|id|qny|id||df|otid||dfIJnti|}|djo$||d8}|djotSnWqtj o|id|qXqWtS( sj Tries to evict enough boot pool datasets to satisfy the space_needed constraint. R)Rs[noevict] NOT evicting %ssNuking dataset %s for %d bytesRs.Evicting boot pool dataset %s [%d bytes freed]isCannot destroy dataset %s( RRFR R!Rztdestroy_datasetRJRR5(R9Rt space_neededRRtmruR)tretval((s"../../common/bootmgmt/versaboot.pyt_evict_boot_pool_datasetss0         cCsti|}|i|i}|d 7}ti|ti} | djoE|id|| ||| f|| 8}|djo d}qn|||i} | djo d} n| d|i } | djohd| |i d} | |i} |id| | f|ot i d| | fIJn|| 7}n|id ||f||joW|oP|g}|o%t t |it |}n|i|||d |S||jo | otStS( sS Returns True is enough space is available to store [space_required] under the bpdmountpt mount point. If initially insufficient space exists in the boot pool, datasets will be discarded in accordance with the boot pool eviction policy, namely: Eliminate oldest datasets first, ignoring datasets corresponding to BEs that are "noevict" (whose zfs property `com.oracle.boot-pool:eviction-policy' includes "noevict".) If, after processing the maximum number of evictions, there is still insufficient space, we return False. iisOSpace already used by dataset %s: %d (subtracting from %d => %d really requiredidiisSBoot pool free space is below min threshold (at %d%%). Adding %d to space requiredsVBoot pool free space would be below threshold (at %d%%). Adding %d to space required.s#Free space: %d | Space required: %dRi(RBtstatvfstf_frsizetf_bfreeRzRR$RRFtf_blocksR R!RRtunionRR5RJ(R9t bpdmountptt bpdatasettspace_requiredtevictt noevictlistRRt freespacetspace_in_datasettnew_freespace_blockst new_freepctt need_blockst addl_spacet donotevict((s"../../common/bootmgmt/versaboot.pyt_space_availablesH                  % cCsnxgt|D]Y\}} | ditii} g} g} xntdt| D]W} tiii| | }| itii||| itii||qTWtii|| d}tii|| d| d}tii|| d}|p| oy||}ti |}t ||oR|i |i jo?|ot i d||fIJn|id||fw n |odSWqttfj o|odSqXn|id||fyti|Wn?tj o3}|itijotd||q0nXxt| | D]\}}yHti |}ti|t i|iti||i|iWq@tj o}|id|iq@Xq@W|ot i d||fIJnyti||Wn.tj o"}td ||f|nXyt||Wq tj o}|id |iq Xq Wd S( s Copies the essential boot files from rpdmountpt to bpdmountpt. Raises BootmgmtInsufficientDiskSpaceError (and tries to undo all items copied up until that error) if there's not enough space on the destination filesystem. iis)[NOT COPYING] unchanged file %s (vs. %s).s%[NOT COPYING] unchanged file %s -> %ssCopying %s -> %ss)Couldn't create directory %s on boot pools#[IGNORED] attribute copy failed: %ss0Copying %s (from root pool) to %s (on boot pool)s.Couldn't copy essential boot file `%s' to `%s's1[IGNORED] Could not set file access/mod times: %sN( RJR&RBRCtseptxrangeR'RDRRzRR{R R!RFRSRERRGtEEXISTR tzipR[tS_IMODEtst_modeRZtst_uidtst_gidRTtshutiltcopy2R(R9tftupsRR|RRRt checkonlyRNR~tpath_componentstrpathstbpathsRtpathsegtbparenttrfiletbfileRtbsbR^trpathtbpathtstRM((s"../../common/bootmgmt/versaboot.pyt_copy_boot_filessv            cCs|id|}|idd}|pti|d}n|oJ|io@|i} | ititijot }|i dqn| o,|o%|o|id|} | g} nd } |i |i i} z\| ~ } |otid|| fIJn|i| \}}}|pti|h|d6ny|i |i i}z|~}|otid||fIJn|p|i||||| |o?|i||| |||ot nt|}|o|Sntd||fWd QXWn#tj oti|nXWd QX|otid |IJn||jo0|i d ||fti|id|nd S( s Does the heavy lifting of synchronizing a BE's bootable files from the rpool to the boot pool. - Creates the boot pool dataset, if needed - Mounts the boot pool dataset - Mounts the root pool dataset, if needed - Copies essential boot files (boot archive [+ kernel]) to the boot pool dataset if sufficient free space exists on the boot pool. Tries to avoid copying files that are the same size with the same last-modification time as those on the root pool IFF opt==True. - If there is insufficient space, datasets on the boot pool are deleted in accordance with the boot pool eviction policy ("noevict" datasets are deleted last, and others are deleted in LRU order (if eviction is enabled).) - Once sufficient space has been freed, we retry copying the essential boot files. - The root pool dataset is unmounted - The boot pool dataset is unmounted R%iR1s2Overriding eviction to False due to policy settings#Root pool dataset %s mounted on %s.scom.oracle:rootfss#Boot pool dataset %s mounted on %s.scInsufficient disk space: Could not update boot pool dataset %s with boot files from root dataset %sNsRoot pool dataset %s unmounted.s6rpool bootfs set to %s; setting boot pool bootfs to %s(RR&Rztzpool_prop_getRRRvRRR5RFR(t_mount_datasetRRR R!Rtcreate_datasetRRRJR Rtzpool_prop_set(R9tdatasetRRtoptRRRt rpool_bootfstbpct bpool_bootfsRRR|RRRRRt check_value((s"../../common/bootmgmt/versaboot.pytsynch_rpool_dataset8s\   & &        cCs|i|dtS(s Returns True if the specified root dataset is out of synch with the cached dataset (boot files) on the boot pool. R(RRJ(R9R((s"../../common/bootmgmt/versaboot.pytdataset_synch_requiredsc sfd}g}|otidIJni|||otidt|IJnxy|D]q}y=|otid|IJnti|id|Wqftj o}id||fqfXqfWdS(s9Deletes ALL cached BE datasets on the boot pool. cs!id||i|dS(NsAppending %s to listi(RFR(Rtytz(R9(s"../../common/bootmgmt/versaboot.pyt_append_to_lists s*Searching for boot pool cached datasets...sFound %d cached dataset(s)s Destroying %s...sDestroyed boot pool dataset %ss)Failure deleting boot pool dataset %s: %sN(R R!RR'RzRRFR(R9RRt to_be_deletedtbpdsnametbpze((R9s"../../common/bootmgmt/versaboot.pytdelete_all_cached_be_datasetss$   c Csd}|io|iio t}nti\}}|djotd|ng}x|D]}|id} | d joqjn|i| \} } | d jo8t i | t i } t i| } |id| n|tjp| o&|ih| d6| d6| d6qjqjW|p|id d S|id |d t|id ||o)|otidIJn|i|ny2x+|D]#} |i| ddtd|qWWntj onXd S(s cSsBt|d|d}|djo|St|d|dSdS(NRiR(tcmp(RRt noevict_cmp((s"../../common/bootmgmt/versaboot.pyt cmp_mruents is%Couldn't get full BE list (code = %d)R;sUsing creation time for ds %sR)RRs mrulist is empty: Nothing to do.NRtreversesSORTED: [[ %s ]] s)Clearing all boot pool cached datasets...RR(RRRJR5tbeListR RiR(RRzRR$RR$RRFR5RRR R!RRR (R9RRRRR=tbelistRtbetrootdsRRRtmruent((s"../../common/bootmgmt/versaboot.pyR*sH      cCs(||ijo|ii|ndS(sxAdds the specified root pool to the pending list of root pools that are associated with this boot pool. N(RR(R9R((s"../../common/bootmgmt/versaboot.pyt link_rootpoolsccsK|iii}z+|~}|id|i|f|VWdQXdS(sJ Mounts the top-level dataset and returns the mount point s Top dataset for %s mounted on %sN(RRRRFR(R9Rtmountpt((s"../../common/bootmgmt/versaboot.pyt top_datasets# c cs:|djo |in|}ti|}|o |id||f|VdS|p"tidddd}t}n |}t}|id||fti ||z |VWdyS|id|ti ||o+yt i |Wq t j oq XnWn%tj o}|id |nXXdS( s Creates a temporary mount point if none is specified and mounts the top-level dataset of the boot pool there. Yields the mointpoint. s&Found dataset %s already mounted on %sNtsuffixs-bpoolROs/system/volatiles#Mounting boot pool dataset %s on %ssUnmounting boot pool dataset %ss'Error unmounting top-level dataset (%s)(R(RRztdataset_mountpointRFRQtmkdtempRJR5t zfs_mountt zfs_unmountRBR7RSR(R9RRt dataset_namet mounted_ont mountpointtcleanuptbmzerr((s"../../common/bootmgmt/versaboot.pyRs8         c Cstii|ti}tii|p|odSy.tii|pti|tinWn.tj o"}t d||i fnXyti |ti ti Wn.tj o"}|id||i fnXdS(s Ns,Couldn't create boot data directory (%s): %ss*OSError when changing owner/perm of %s: %s(RBRCRDRR>RRRARSR RTRZR?R@RF(R9tbasedirR7RRR^((s"../../common/bootmgmt/versaboot.pyt_do_create_boot_datadir!s cCs|i|i|_g}x|iD]|}|id||ifyti|ti|iWn0tj o$|id|ti fnX|i |q%Wt ||_ dS(s Update boot pool linkage property on all root pools, then update _bp_cur_rpool_list to the list of root pools on which it was set successfully. s$Linking root pool %s to boot pool %ss3Failed to add boot pool linkage property to %s (%s)N( RRRFRRzt zfs_set_propRRRR RRR(R9t success_listR((s"../../common/bootmgmt/versaboot.pyR'7s   cCs |d|S(s R%((Rtrpdstbpname((s"../../common/bootmgmt/versaboot.pytrpool_ds_to_bpool_dsNscCs*|id|}ti|o|SdS(s R%N(RRztdataset_existsR((R9R)tbpoolds((s"../../common/bootmgmt/versaboot.pytboot_pool_cached_datasetTsc Cs<x5|iiD]'}|io|iidd}|o|id|}|id|i}ti|id|oyti |d|iWn4t j o(}|i d||i|fnXy*ti |||i d||fWq,t j o%}|i d|||fq,Xq0q4q q WdS(slRename boot pool datasets according to any changes made to the corresponding root datasets. R1R%scom.oracle:rootfss>Couldn't update boot pool dataset rootfs property %s -> %s: %ss'Renamed boot pool dataset from %s -> %ss3Couldn't rename boot pool dataset from %s -> %s: %sN( Rtboot_instancestoriginal_valuesRiR(RR1RzRRRRFtrename_dataset(R9tinstt orig_bootfsRt new_bpdsnameR((s"../../common/bootmgmt/versaboot.pyt_commit_renamesas2       cCs}g}|i|i|x]|D]U}y!ti||id|Wq tj o}|id||fq Xq WdS(s|Find boot pool datasets that must be deleted based on the presence of the corresponding root pool datasets. s(Destroyed now-stale boot pool dataset %ss)Failure deleting boot pool dataset %s: %sN(Rt_walk_rootds_deletedRzRRFR(R9RRR((s"../../common/bootmgmt/versaboot.pyt_commit_deletionss    cCs|io |iiSdS(s N(RRR((R9((s"../../common/bootmgmt/versaboot.pyRs  cCs1|io|ii||n tddS(s~ Raises: BootmgmtInvalidParameterError(key) BootmgmtInvalidParameterValueError(value) sNo BootPoolConfig existsN(RRR (R9R_Rg((s"../../common/bootmgmt/versaboot.pyRs cCs+|io|ii|StddS(sH Raises: BootmgmtInvalidParameterError(key) sNo BootPoolConfig existsN(RRR(R9R_((s"../../common/bootmgmt/versaboot.pyRs cCsp|io|iddS|io|ii|n|pt|it|ijo:y|iWqtj o}|id|qXny|i o|i nWn't j o}t dd|nXy_|i |i|i|iio|djo ti}n|i||||Wn't j o}t dd|nXdS(s s)Instance data is read only: CANNOT COMMITNs$Error updating boot pool linkage: %ssGeneral boot pool failuretxcpt(R7RFRRrRRRR'R RhRjRRRR R)RRR(R R!R4(R9RR-R.tplatdicttbmerrR((s"../../common/bootmgmt/versaboot.pyRrs6   &        cCse|ii}g}|iiD]A}t|to+|io!t|i|jo ||qq~S(s (RRRRR#tdefaultR+R1(R9RRR((s"../../common/bootmgmt/versaboot.pyRs   cCsh|i}|io|iio t}nx4|D],}|id|i|i|i|q4W|S(s s-Synching default boot instance with bootfs=%s(RRRRJRFR1R(R9RRR((s"../../common/bootmgmt/versaboot.pyR)s    c Cs|ii}|pdS|p h}n|i|d<|iii}z-|~}||d<|i||||WdQXdS(s Nt bi_accessort topdatadir(RRFt_boot_inst_accessorRRRtinstall(R9R-RR.R tbloaderRtbptopdir((s"../../common/bootmgmt/versaboot.pyR4s   # cCs=d}h}||d<||d None(RR1RFtgetattr(R9RtfieldtdefvalueR1((s"../../common/bootmgmt/versaboot.pyR3s  c cs|iii}z||~}tii|ti}|i||t |ti ti ti fti |_z |iVWd|iiXWdQXdS(s{ Returns a context manager that holds open the recovery data file and allows it to be manipulated. N(RRRRBRCRDRR>RR,tRECOVERY_FILENAMEtRECOVERY_FILE_OWNERtRECOVERY_FILE_GRPtRECOVERY_FILE_PERMSRR@(R9R7RRtdestdir((s"../../common/bootmgmt/versaboot.pyt recovery_data@s# cCstdjodS|iS(sSynchronize the platform boot device list such that all members of the boot pool are placed in the boot order. We try to honor user modification of the boot order, we do not insert new members at the front of the boot order. Instead, we look for the first occurrence of an existing boot pool member, and append members not in the boot order after that member. If there are no members in the boot order, all boot pool members are added at the front of the boot order list. RN(Rt_synch_sparc_boot_order(R9((s"../../common/bootmgmt/versaboot.pyR(Xs csd}t\}|djotSt|}|id||id|ig}x\|iD]Q}yt|}|i|Wqftj o}|id||fqfXqfW|p|idtSy}t d}|o`t d|i d}xH|D]6} y|i | } || =Wq t j oq Xq Wng}Wntj o g}nXd } g} xt||D]h} | |jo| i| qnx>t|D]0\} }| |jo| | jo | } qqWqW| o-| d jo| d } n| || | +n|id | | f||jotSttd |t|d }||jo|iot|i}ng}g}|id |xE|D]9}yt|}|i|Wqtj oqXqWnx||joy|i}|i |} Wnt tfj o d } nX|id|| || =ttd|t|d }qWtfd|}|id|t|ttB}|d jotS|id||ftS(s isOriginal plat_bootlist = %ssdevice list = %ss!Error getting prompath for %s: %ss:No boot devices could be derived: not setting boot-device s tboot-listcSs |djS(R((R((s"../../common/bootmgmt/versaboot.pyRsRiis!paths_to_add = %s, last_path = %dcSs t|S((R'(R((s"../../common/bootmgmt/versaboot.pyRssHealthlist = %ss+New boot-device too long. Pruning entry %scSs t|S((R'(R((s"../../common/bootmgmt/versaboot.pyRscsi||S((Ri(R(t aliasdict(s"../../common/bootmgmt/versaboot.pyRssNew plat_bootlist = %ss devfs_bootdev_set_list(%s) => %dN(RR(R5RRFRRRRERtfilterR&RNR[RRJRJtsumtmapR'Rtpopt IndexErrorRRR(R9tBOOT_DEVICE_MAXLENGTHt plat_bootlisttorig_plat_bootlistt bpool_devlistRot bp_promdevsRMt tbootlistRCtidxt last_patht paths_to_addtjt plat_pathtlengthRt prunelisttpromdevsttrypathR=((R!s"../../common/bootmgmt/versaboot.pyR fs                   &         +    (splatform/i86pc/kernel/amd64R(splatform/i86pc/amd64R(splatform/%(platformname)sRN(]RsRtRuR>tpwdtgetpwnamtpw_uidR?tgrptgetgrnamtgr_gidR@RARBRCRDRERRRRRt BOOTFILES_X86tBOOTFILES_SPARCRRyRxR5R(R>RRRt classmethodRRRRRRRRRJRRRRRTRUR0RKR^R`RbRcR_RhRjReRiRRRRRRRRRR*RRRRRR'RRRR RRRRrRR)R4RRRRR(R (((s"../../common/bootmgmt/versaboot.pyRs  `    < .   +          2   * 'A H  S   9  )   %   1    t VersaBootcBseZdZdZd edZdZdZe dZ e dZ e edZdZd Zd Ze d d d d ZRS( s" The main VersaBoot abstraction. Includes: - One or more VersaBootRoot instances, each of which describes a single (long) property string that fully describes how to prepare the boot device and filesystem before mountroot() in early boot. - One or more RootPool instances, each of which describes a Solaris root pool (usually there's only a single root pool) - One BootPool instance that describes the VersaBoot boot pool, the storage pool that is used to cache boot archives from the root pool(s) sos-root-devicecCsj|itiiijp|idjotdn||_g|_d |_ g|_ |o |}nOt i |i}|o"t |d|d|dt}ntd|i||_t|_t|_y|iWn~tj o}|id|n[tj oN}|itititigjo t|_|id|iqfnXd S( s RzsHVersaBoot is supported on disk-based boot configurations using ZFS only.RRRs+VersaBoot is not supported for root pool %ss'Ignoring failure to load properties: %ssError loading properties: %sN(R{R|R}R~RRRRtvbrootsR(t_recovery_vbrootst_vbroots_committedRRRRJt boot_poolR5trecovery_neededR7t_load_propertiesRRFRSRGRItEACCEStEROFSRT(R9Rtbootpooltautocreate_bootpoolRCt bpoolnameRR^((s"../../common/bootmgmt/versaboot.pyR>s8         " cCsA|io3|iio&|i o|ii|indS(s N(RCRR7Rtwrite_recovery(R9((s"../../common/bootmgmt/versaboot.pyRs" cCszti}y|iiii|}Wn#tj otd|nXd}|i o|i i o||i i t i i}zV|~}y-|i|}|oti|}nWntj o d}nXWdQXn|o;ti||_|id|it|i|_n|oI|i|i|p&|id|||ft |_n||_ndS(s Creates and adds one or more VersaBootRoot instances based on the value of the source property (VersaBoot.ROOT_DEVICE_PROPNAME) s'No platform support for the %s variableNsvbroots after load are: %ss_[WARN] Mismatch between platform %s property and its value in the recovery data ["%s" vs. "%s"](R?tROOT_DEVICE_PROPNAMERRFRGRoRR R(RCRRRJRRtVersaBootRootFactorytget_from_propstrRR@RFRRBt_compare_vbrootsRDRA(R9Rtrootdevicesproptrecovery_vbrootsRtrecoverytrecovery_rootdevprop((s"../../common/bootmgmt/versaboot.pyRE s8  )   cCs |iot|iSgSdS(N(RAR(R9((s"../../common/bootmgmt/versaboot.pyRQKs cCsZt|t|jotSx5t||D]$\}}|i|ijotSq.WtS(s (R'R5RtvbpropsRJ(tlistatlistbtvbrootatvbrootb((s"../../common/bootmgmt/versaboot.pyROSs  c Cs,d}g}g}|pl|i|ijoUtg}|iD]}|io ||q=q=~djo|iddSqnx|iD]}|i|dti|if} x|i D]} x| i D]\} } |i i | } | i tj o,| o%| ti7} | d| | f7} q| i o| o|i| | fqqWqW| ti7} || 7}qW|djo|iddS|tti }|id||p|p|i|ijoD|i|||x|D]}|iqWt|i|_n|S(s Ris8No changes to VersaBootRoot list; not writing propertiesNs%s=%sspropstr is emptysdirtylist => %s(RBR@R'tdirtyRFRt VersaBootRoottROOT_TECH_PROPNAMERXtget_metaprop_dictsRURTRit sensitiveRJtPROP_DELIMITERtROOTSPEC_DELIMITERR(t _store_propstcleanR(R9Rtwrite_fwtpropstrtsensitive_prop_listt dirtylistRRtvbroottoneproptpropdictRjtproptypetlocalval((s"../../common/bootmgmt/versaboot.pyt_write_propertiesasJ ?           !c Cs%ti}|o3|id||f|iiii||n|idjo|iddS|ii t i i }z|~}|idti|f|iti||o!|id||i |ny|iWn(tj o}|id|inXWdQXdS(s sSetting %s property to `%s's!No boot pool -- not storing propsNs&[RECOVERY] Setting %s property to `%s's,[RECOVERY] Setting sensitive properties (%s)s+[WARNING] Failed to write recovery data: %s(R?RLRFRRFRGRlRCR(RR5RRRnRrRERT(R9Rctsensitive_propsRbtrdpropRRRRM((s"../../common/bootmgmt/versaboot.pyR`s(  )   cCs%|iot|i|_tStS(s (RARR@RJR5(R9((s"../../common/bootmgmt/versaboot.pytrecover_vbrootss cCsHy|idtdtWn'tj o}tdd|nXdS(s RRbsGeneral boot pool failureR N(RkRJR5RR(R9R((s"../../common/bootmgmt/versaboot.pyRKs  c Csx|iD]}|iq W|ipfy8|io|ii||||n|i|SWqtj o}tdd|qXn tddS(s sGeneral boot pool failureR s<This VersaBoot instance is read-only and cannot be committedN( R@tvalidateR7RCRrRkRRR(R9RR-R.R RfR((s"../../common/bootmgmt/versaboot.pyRrs    N(RsRtRuRLR(RJR>RRERRQt staticmethodROR5RkR`RnRKRr(((s"../../common/bootmgmt/versaboot.pyR?s /  +> #  RZcBseZdZdZdZdZddZedZ dZ dZ dZ d Z d Zd Zd Zd ZedZRS(s s osroot-typet;s;;cCsddk}g}|i|iD]+}t|d|ito ||q#q#~|_h|_t|_|oQ|i d|x$|D]\}}|i ||qW|i dt|_ndS(s iNs _%s__vbpropssInitting from KV pair list: %ssClearing _dirty( tinspecttgetmrot __class__RRsR5t _mixin_basesRTR6RFRl(R9tkvplistRrRRR_R`((s"../../common/bootmgmt/versaboot.pyR>s 1    cCs|iS(s (R6(R9((s"../../common/bootmgmt/versaboot.pyRY scCs|idt|_dS(s sClearing _dirtyN(RFR5R6(R9((s"../../common/bootmgmt/versaboot.pyRa s cCs |iS(s (t_get_all_metapropdicts(R9((s"../../common/bootmgmt/versaboot.pyR\ scCs0g}|iD]}||id|iq~S(s s _%s__vbprops(Rut__dict__Rs(R9Rtmixin((s"../../common/bootmgmt/versaboot.pyRw scCs t|iS(s (RRT(R9((s"../../common/bootmgmt/versaboot.pytgetprops" scCs0||ijo |i|Std|dS(s sUnknown property `%s'N(RTR(R9RX((s"../../common/bootmgmt/versaboot.pyRo( s cCs1x*|iD]}||jo ||Sq WdS(s N(RwR((R9RXtmixin_metapropdict((s"../../common/bootmgmt/versaboot.pyt_prop_type_lookup0 s    cCs|i|}|dj }|o|i||n|ii||jo5||i|<|ip|idt|_qndS(s sSetting _dirtyN(R|R(RoRTRiR6RFRJ(R9RXRgt prop_type_objRo((s"../../common/bootmgmt/versaboot.pyRl9 s    cCsuxn|iD]`}xW|iD]I\}}|ii|}|io!|djotd|q q Wq WdS(s s"Missing a required property (`%s')N(RwRURTRitrequiredR(R(R9RhRjRiRj((s"../../common/bootmgmt/versaboot.pyRoH s  cCsHdig}|iD]*}t|ddo||iqq~S(s R%tcomponent_nameN(RDt __bases__RR(R(RRR((s"../../common/bootmgmt/versaboot.pyRXT sN(RsRtRuR[R^R_R(R>RRYRaR\RwRzRoR|RlRoR>RX(((s"../../common/bootmgmt/versaboot.pyRZs        tVersaBootMixincBseZdZdZRS(s cCsdS(s N((R9((s"../../common/bootmgmt/versaboot.pyR>c s(RsRtRuR>(((s"../../common/bootmgmt/versaboot.pyR_ stVersaBootPropertyTypecBsGeZdZdeedZdZedZedZ RS(s cCs||_||_||_dS(s N(t_maxlent _requiredt _sensitive(R9ttypelenR~R]((s"../../common/bootmgmt/versaboot.pyR>m s  cCsdS(s N((R9RXRg((s"../../common/bootmgmt/versaboot.pyRou scCs|iS(s (R(R9((s"../../common/bootmgmt/versaboot.pyR~{ scCs|iS(s (R(R9((s"../../common/bootmgmt/versaboot.pyR] sN( RsRtRuR(R5R>RoRR~R](((s"../../common/bootmgmt/versaboot.pyRi s  tStringVersaBootPropTypecBseZdZRS(cCs]|djot||dn|io,t||ijot||dndS(Nscannot be Nonestoo long(R(RRR'(R9RXRg((s"../../common/bootmgmt/versaboot.pyRo s     (RsRtRo(((s"../../common/bootmgmt/versaboot.pyR stIBSpecVersaBootPropTypecBs>eZedZedZedZdZRS(cCs=t||jot||dnti||dS(s stoo longN(R'RRt_ibspec_path_to_tuplelist(RXRgt maxlength((s"../../common/bootmgmt/versaboot.pyt_ibspec_validator sc Cs|id}g}x||D]t}|id}t|djot||dnt|djo|i|dd fqnh}x|didD]}|i}|djo$t||d ||dfn|id }|di|d<|ddjo$t||d ||dfnt|djo|d} nd } | ||d s(RsRtRuRRJt_IPoIB_VersaBootMixin__vbpropsRpR(((s"../../common/bootmgmt/versaboot.pyR6 stLocalDisk_VersaBootMixincBs3eZdZheded6ZedZRS(s is osroot-pathcCsdS(s t LocalDisk((((s"../../common/bootmgmt/versaboot.pyRK s(RsRtRuRRJt"_LocalDisk_VersaBootMixin__vbpropsRpR(((s"../../common/bootmgmt/versaboot.pyRE stZFS_iSCSI_IPv4oIB_VersaBootRootcBseZdZRS(s (RsRtRu(((s"../../common/bootmgmt/versaboot.pyRR stZFS_LocalDisk_VersaBootRootcBseZdZRS(s (RsRtRu(((s"../../common/bootmgmt/versaboot.pyR[ sRMcBsGeZdZeegZedZedZedZ RS(s cCs.g}|iD]}||i|fq~S(s (t(_VersaBootRootFactory__root_technologiesRX(RRR((s"../../common/bootmgmt/versaboot.pytget_root_technologiesj scCsOg}|iD]$}|i|jo ||qq~}|o |dSdS(s iN(RRXR((RRXRRtvbrs((s"../../common/bootmgmt/versaboot.pytget_root_technology_by_nameq s; c Cs,|id||pgSg}|iti}x|D]}|iti}d}g}x|D]}|iddjo|idd\} } nqf| tijo*| o#ti | }|id|qf| tijo|i | | fqfqfW|o|i ||q;q;W|S(s Attempts to generate a list of VersaBootRoot instances based on the property passed in. The property is of the form: ((k=v;)+;;)*(k=v;)+ s>Trying to parse potential VersaBoot root descriptor: [[ %s ]]Rciis vbr -> %sN( RFR&RZR_R^R(ReR[RMRR( RRRtpropstrootpropt rootprop_listtvbrt rootprop_kvpst rootprop_elemR_R`((s"../../common/bootmgmt/versaboot.pyRN{ s0 ( RsRtRuRRRR>RRRN(((s"../../common/bootmgmt/versaboot.pyRMd s   (RRuR|RRRRRRRRRR R R R R RRRRtbootmgmt.bootutilRRtbootmgmt.bootinfoRtbootmgmt.pysolRRRRRRRRRt contextlibRt ConfigParserRR R!R"R5t bootmgmt.zfsRztbootmgmt.zfs.libzfs.cfunctlibzfsRtbootmgmt.zfs.libzfs.constR$tbootmgmt.bootconfigR#R$R6R9RGRBRRzR RQRvR+R,RvRR?RZtobjectRRRRRRRRRRRRRM(((s"../../common/bootmgmt/versaboot.pytsf v@"            u   Z