ɼjWc@sddkZddkZddkZddkZddkZddkZddkiZddkZddk Z ddk i Z ddk lZddklZlZlZlZlZlZlZlZlZlZddklZddklZlZlZl Z l!Z!ddkl"Z"l#Z#l$Z$l%Z%l&Z&l'Z'ddk(i)Z*ddk i+Z,ddk-i.Z.de/fdYZ0d e/fd YZ1d e/fd YZ2d e/fdYZ3de/fdYZ4de/fdYZ5e6ddgZ7de9dZ:ddZ;dZ<dZ=dddddddZ>e9e9dZ?dZ@dZAdZBdZCddZDd ZEd!ZFd"ZGd#ZHd$ZIdd%ZJdd&ZKd'ZLd(ZMeiNddde9d)ZOd*ZPd+ZQdd,ZRd-ZSd.ZTd/ZUd0ZVd1ZWd2ZXd3ZYd4ZZd5Z[dd6k\l]Z]e9d7Z^e9d8Z_dS(9iN(tDiskBootConfig( t mnttab_opent getmntanyt mnttab_closet machine_namet platform_nametzfs_name_validtZFS_TYPE_FILESYSTEMt libzfs_initt libzfs_finit zone_is_imgz(tget_zpool_default_bootfs(tBootmgmtNotSupportedErrortBootmgmtZFSErrort"BootmgmtInsufficientDiskSpaceErrort BootmgmtErrortBootmgmtBootPoolFailureError(tbeCreateSnapshottbeDestroySnapshott beRollbackt bePrintErrorst beGetErrDesctbeVerifyBENametLibbeOperationErrorcBseZdZRS(cCs||_||_dS(N(t error_strtbe_name(tselftbenamet error_string((s../../common/libbe.pyt__init__:s (t__name__t __module__R(((s../../common/libbe.pyR9stLibbeUnsupportedOperationErrorcBseZdZRS(cCs ||_dS(N(R(RR((s../../common/libbe.pyR?s(RRR(((s../../common/libbe.pyR >stLibbeBadPolicyErrorcBseZdZRS(cCs ||_dS(N(t badpolicy(Rtbadpol((s../../common/libbe.pyRCs(RRR(((s../../common/libbe.pyR!BstLibbePolicyConflictErrorcBseZdZRS(cCs ||_dS(N(t conflicts(Rtconfl((s../../common/libbe.pyRHs(RRR(((s../../common/libbe.pyR$GstLibbeInvalidPolicyErrorcBseZdZRS(cCs ||_dS(N(R(Rtmsg((s../../common/libbe.pyRMs(RRR(((s../../common/libbe.pyR'LstLibbeBEDoesNotExistErrorcBseZdZRS(cCs ||_dS(N(R(RR((s../../common/libbe.pyRRs(RRR(((s../../common/libbe.pyR)QststatictnoevictcCsMy|id|d|Wn,tj o }tidt|IJnXdS(Nt boot_devicestforces WARNING: %s(tcommit_boot_configRtsyststderrtstr(tbootconftdevlistR-tbpfail((s../../common/libbe.pytcommitZsc Cs|dj o,t| otidIJtidnti|\}}|djo ||fStidjoti oyVt dht t i 6ii}z)|~}t|}t|i|WdQXWntj o||fSXd}|ot|dd}nx|D]O}|idd}|o0|o)||jot |dR/R0R?R@tbeRenameRBRCtgetzpoolbybenameRERHRItbe_make_root_dstget_menu_entriesttitleRWtreplacet StandardErrorR7R5( t old_benamet new_benameR[tzpoolR]R^R8t old_root_dstbisR_((s../../common/libbe.pyRds8   #  cCs&tidd|dd}ti||}|djoAtti|djo!ti|td|q|nt d|d}|djoHyti |ti|Wnt j onXtd|nti |}|djotd |nti|d S( s tprefixsbe-%s.tdirs/system/volatileis>Unable to mount BE %s (boot archive UUID will be out of synch)s"/sbin/bootadm update-archive -R %ss*Failed to update boot archive in new BE %ssUnable to unmount BE %sN( ttempfiletmkdtempR@tbeMounttlentostlistdirtrmdirt RuntimeErrort spawn_commandt beUnmounttOSError(Rt mountpointR[((s../../common/libbe.pytbe_bootadm_update_archives*      c Cs|d j ot| p|d j o,t| otidIJtidn|p.ti\}}}}|djod Sn|pti\}} |djod S|id\} } } | o| i ot | } | } x| D]}}|i dd }|pqn|id\}} }| p|| jp|i oqnt t || } qWn |} d} t }| d}xs|pgd| |f}xF| D]8}|i dd }|pqn||joPqqWt}|d7}qWnti||||||}|d}|ddjod StidjoBt|ti|}|p"tid|IJtidnt|ii}z|~}t||}t||}g}|iD]*}t|d d |jo ||qq~}|o |}n|}|o<|di}||_||_t |_|i|nt|||t |Wd QXnd||fS(s*Copy a boot environment from 'src_bename' to 'dst_bename. If 'rpool' is specified, create the new BE in that ZFS pool. If 'src_snap' is specified, base the new BE off that ZFS snapshot. If 'beNameProperties' is specified, it should be a mapping of property names to their values.s?The BE name provided is invalid. Please check it and try again.iiR:t orig_be_names%s-%sis4Failed to find boot environment '%s' in any ZFS poolR7N(iNN(iNN(iNN(!R=R>R/R0R?R@tbeFindCurrentBERAt rpartitiontisdigittintROtmaxRPRFtbeCopyRBRCR~ReRERHRIRftboot_instancesRNtcopyRhR7tdefaulttadd_boot_instancetbe_append_menuR5(t dst_benamet src_benametsrc_snapt dest_rpoolt bename_propstbe_descR[tsrc_pooltsrc_dsR\tbasetseptrevtmaxrevRatobentnbasetnrevtgoodtnumt dest_snapRmR]R^t src_root_dsR8t_[2]txt instancestnewtitletbi_copy((s../../common/libbe.pyRs            #-    cst|ptidIJtidnti|}|p"tid|IJtidnt||t}|o!|djod }t }n g}t }ti |||}|djo|St i djot|ii}z|~} | ifdt |o t} nd } d } | og} | iD].} t| dd | djo | | qZqZ~ }|o5t |d_t| |d| d|| d} qnzey.|d jo| i}nt| |Wn0tij o!}ti|iIJtid SXWd | d j oAti| }|djotd |nti| nXWd QXndS( s Destroy a BE.s?The BE name provided is invalid. Please check it and try again.is4Failed to find boot environment '%s' in any ZFS poolR8icst|ddjS(R7N(RNR=(R(R8(s../../common/libbe.pyt|sR7RtBE_ERR_BOOTFILE_INSTNsUnable to unmount BE %s( R>R/R0R?R@ReRftget_active_on_boot_beR=RFRPt beDestroyRBRCRERHRItdelete_boot_instanceRRNRt#prep_be_for_bootloader_installationtget_boot_device_listR5tbltBootLoaderInstallErrorR(t errorcodeR{RyRvRx(Rt destroy_snapst force_unmountRmt active_beR3tactive_on_boot_be_destroyedR[R]R^taob_betmntptRRtmatchestblerr((R8s../../common/libbe.pyRXsf      #  "    c Cst|ptidIJtidnti|}|p"tid|IJtidnt||}tidjo3t |i i }z|~}t |||}|pt ||}n |d}t|_d}zoy8t|||||}t|_t||iWn0tij o!}ti|iIJtidSXWd|dj oAti|} | djotd|nti|nXWdQXnti|||} | S(sActivate a BE.s?The BE name provided is invalid. Please check it and try again.is4Failed to find boot environment '%s' in any ZFS pooliRNsUnable to unmount BE %s(R>R/R0R?R@ReRfRBRCRERHRIRgRRFRR=Rt set_bootfsR5RRRR(RR{RyRvRxt beActivateBH( RRmR8R]R^RoR_RRR[((s../../common/libbe.pyt beActivatesD   #     cCstd}|ptS|S(s=Return a dict describing the active on boot boot environment.R9(tget_be_by_attributet get_active_be(R9((s../../common/libbe.pyRs cCs tdS(s5Return a dict describing the active boot environment.tactive(R(((s../../common/libbe.pyRscCsKt\}}|djodSx#|D]}|i|o|Sq(WdS(Ni(RAR=RO(tattrtretctbestbootenv((s../../common/libbe.pyRs cCst\}}|djodS|djot}t|dd}nd}x>|D]6}|idd|jo|idd}PqZqZW|S(s Get the default ZFS BE name. iR7R8RN(RAR=RJRNRO(R7RRR_RR((s../../common/libbe.pytget_default_benames    cCsy|tii}z_|~}d}|djo-xh|iD]}|io |}Pq@q@Wn?y|i|}Wn*tj od}ti|ddfSX|djo2t i i dddj ot i dIJndSd}tidjo d}ntidjo d }nhtd 6|d 6}t|d d |}|iddj o|h|d6}n|iddj o|id|}nt|dd} | djot|dd} | djo2t i i dddj ot i dIJndSt} t| | } t| | djo2t i i dddj ot i dIJndSnttd| } t| dj oZ| d} | djo?t| }|djot i d| IJd St| } q n t| } | djo6t i i dddj ot i d| IJnd!S| d|d|i}d|| fSWdQXWnItj o=}t i i dddj ot i t|IJnd"SXdS(#sHelper function for reboot(1M). Returns a tuple of (1) string with the following concatenated (with spaces separating the components): the mountpoint of the BE, the kernel file, and the kernel arguments for the menu item indexed by 'entnum'; (2) the mountpoint for the BE associated with that entry (it will mount the BE on a temporary directory), and (3) an error code. If 'entnum' is -1, return the details of the default entry. Caller is responsible for unmounting the BE and removing the temporary directory.itBE_ERR_NO_MENU_ENTRYtt BE_PRINT_ERRs No boot instance could be found!ti386tamd64tsparctsparcv9tplattkisatkernels'/platform/%(plat)s/kernel/%(kisa)s/unixs %(karch)stkarchs$ISADIRR7trpoolsNo rpool or bootfs in entry!sbootfs could not be determined!t mnt_specialt mnt_mountpt/isCould not unmount %ssCouldn't mount bootfs %s!t N(iRR(iRR(iRR(iRR(iRR(iRR(RERHRIR=RRt IndexErrorR@RRvtenvironROR/R0tplatformt processorRRNtfindRiRR R RRRt unmount_zfstmount_zfs_in_temp_dirtexpanded_kargsRMR1(tentnumR]R^tinstR_terrRtkdictRR7t rpoolnametlzfshtmntenttmountptRtargstexc((s../../common/libbe.pytget_kargs_and_mountpts                          cCs}|idjotdn|i|jodSg}x;|iD]0}t|dd|jo|i|qEqEW|S(NRRs Not on ZFSR7(t boot_fstypeRytzfsrpR=RRNtappend(t bootconfigtpoolR8RoR_((s../../common/libbe.pyRgXs c Csd|}d}x|iD]}ti||idti}|ii}|i}|djoqny'||i dd|i d!}Wnt j o qnXPqW|djo<|io2d} |o| d|7} nt i | n|S( Ns/usr/bin/pkg -R %s list -Hv tstdoutit@iRs&Could not retrieve boot loader versions# for boot loader files in the %s BE( R=t pkg_namest subprocesstPopenRWtPIPERtreadtwaittindext ValueErrorRR( R}Rt boot_loadertcmdtvertpkgnametproctoutputR[texc_msg((s../../common/libbe.pytget_bootloader_version_from_ipshs,     ' cCsd}tii|d}ti|}xU|D]M}tii||}tii|o|i|o|t|Sq1WdS(Nsbootloader-version@s boot/solaris(RvtpathRZRwtislinkt startswithRuR=(R}t BLVER_PREFIXtdirnametcontentstitemtfullpath((s../../common/libbe.pyt get_bootloader_version_from_roots#cCsd|ii}yt|}Wntj o}d}nX|pt|||}n||_dS(N(tdata_source_boot_instancetrootpathRR|R=Rtversion(RRR}Rtose((s../../common/libbe.pytset_bootloader_versions  cCs2tidddd|d|}|i||S(NtfstypeRRR7Rh(tbctSolarisDiskBootInstanceR=R(RR7RhR_((s../../common/libbe.pyRs  cCs+|od|d|fSdd|fSdS(sGiven the name of a boot environment, return the name of the dataset where that boot environment resides. If the optional 'poolname' argument is None (the default), then the path will be relative to the pool root.s%s/%s/%stROOTs%s/%sN((Rtpoolname((s../../common/libbe.pyRfscCsti|\}}||fS(N(R@tbeGetBootDeviceList(RRR8R[R3((s../../common/libbe.pytbe_get_boot_device_listsc CsVti|\}}x|D]h}d|joU|idd|jo<|d|jo+|d|d}} |o t} PqqqWd \}} t} |ptidd|dd } ti|| }|d joAt t i | d jo!t i | t d |qq!n| |_||i_t|i|| o| SdS( Nt snap_namet orig_be_poolR8tmountedR}Rpsbe-%s.Rqs/system/volatileisUnable to mount BE %s(NN(R@RAROR=RPRFRrRsRtRuRvRwRxRyRRRR( tbcfgR_RRR8R[tbelisttbenvRR}t needsmount((s../../common/libbe.pyRs4        c cs|djo g}n|djoCtidd!\}}|djoti}qp|g}n |g}|ptdnd}xX|D]P}y"t||||\}}} Wntj o d}nX|oPqqW|pZtdt|djodndt|djodnd d i|fn|V|d jo]| oVd |} t | d} | djo+yt i | Wqt j oqXqndS( Niis"Could not determine the root pool.sNCould not load the boot configuration (tried loading from %s root pool%s: %s).itthisttheseRtss, tnos/usr/sbin/zfs unmount %s( R=R@RtbeGetRootPoolListRyt_try_load_boot_configRMRuRZRzRvRxR|( RmtflagsR6tverboseRt rpool_listRtboot_cfgt pool_mountedt pool_pathRR[((s../../common/libbe.pyREsD           cCszd|}t|d}d}xM|iiD]9}|ii\}}}||jo ||fSq3WdtfS(Ns3/usr/sbin/zfs list -H -o name,mountpoint,mounted %si(RzR=trstript splitlinesRWRP(tdatasetRt cmd_stdoutR!tlinet next_datasettmtpttmtd((s../../common/libbe.pyt_get_zfs_mountinfo1s  c CsOt|\}}|djotidjoKtoAd|}t|d}|djot|\}}q}n|djotidd|dd}d||f}t|d}|djp| o,yti|Wnt j onXdSqnyr|o t |t ot |}nh}|i h|d 6|d 6|d 6ti||} | ||fSWnt j otiid ddj o+d dk} tid|IJ| in|djo]|oVd|}t|d}|djo+yti|Wq?tj oq?XqCnnXdS(NRis/usr/sbin/zfs mount %sRpspool-%s.Rqs/system/volatiles'/usr/sbin/zfs mount -o mountpoint=%s %strpnamettldpathRRis.Error getting boot configuration from pool %s:s/usr/sbin/zfs unmount %s(NNN(R*RBRCR RzRrRsRvRxRMR=t isinstancetdicttupdateR RRROt tracebackR/R0t print_excR|( RRR6RR!R RR[tkwargsRR0((s../../common/libbe.pyR=sT             c Cs||o(x |iD]}|io|SqWdStii}z0|~}x |iD]}|io|SqYWWdQXdS(N(RRR=RERHRI(RR_R]R^((s../../common/libbe.pyRJ~s      cCsd}|djp&t||jpt|djotSx:|D]2}|djp|djp |djotSqEWt|tptStS(s.Returns True if the BE name passed in is validi@iRRt%N(R=RuRPRRRF(RtBE_NAME_MAX_LENtchar((s../../common/libbe.pyR>s3' cCstidddd}d||f}t|d}|djo=tid|IJyti|Wntj onXdS|S(NRpslibbe-Rqs/system/volatiles'/usr/sbin/zfs mount -o mountpoint=%s %sis!Failed to mount zfs filesystem %s( RrRsRzR/R0RvRxRMR=(tzfsnamettemp_dirRR[((s../../common/libbe.pyRs  cCsd|}t|dS(Ns/usr/sbin/zfs unmount %si(Rz(R7R((s../../common/libbe.pyRs c Cs|i}y|ti|dtidti}|i\}}|i}|djo%tid|d|||fIJn||fSWnStj o!}tid||fIJdSt j o}tid|IJd SXdS( NRR0is0%s returned %d. STDERR was: %s STDOUT was: %s sCould not execute '%s': %sis0Error while creating subprocess.Popen object: %s(iN(iN( RWRRRt communicatet returncodeR/R0R|R=R(RRRR%t cmd_stderrR[toserrtval_err((s../../common/libbe.pyRzs"      cCs1yti|ddWntj onXdS(s scom.oracle.libbe:be-policyR*N(RRt zfs_set_propR(R$((s../../common/libbe.pyt"_be_reset_policy_to_static_noraises   cCs.t|}tg}|D])}|o|id o ||qq~}tg}|D],}|o|ido||dq]q]~}||Btt}|ott|dnd|jotdn||@} | oHt| } | ig} | D]}| d|q~ t| nd|j} h} x|D]}ti |}|pt |n| i |d d joggf| |R1R(tbe_namestpoliciest policy_setR]Rtpolicy_add_setRtpolicy_remove_settbad_policy_sett conflict_sett conflict_listt_[3]tnoevict_presentt synch_besRbRmRct policy_stringtidxterrorsRtdstbmzet_[4]R^tmyvbt_[5]te((s../../common/libbe.pyt beSetPolicys C2    ,   "# >    ,cCs|djp|idjodSxY|D]Q}d|jo>|do3|ii|dot|dnXy| ot i||nWqtj o)} tid||t| fIJqXndS(sMounts the specified BE by calling into libbe_py. Also mounts the boot pool dataset, if applicable and requested, under the BE mountpoint. is/ROOT/s\WARNING: No boot pool could be determined for root pool %s. Not mounting boot pool dataset.s[NOTE: The root dataset was mounted but no corresponding boot pool dataset exists for BE %s.sAWARNING: Could not create %s: %s; Not mounting boot pool dataset sFailed mounting %s on %s: %s(R@RtReRZtrpool_to_bpoolR R/R0trpool_ds_to_bpool_dsRRtdataset_existsRvRRZtBPOOL_DS_REL_MNTPTRFtmkdirR|terrnotEEXISTtstrerrorRPt zfs_mountR1( RRt include_bpoolR[RmR8t bpool_nametbpdstbpds_mnttdo_mountR;tbmzfs((s../../common/libbe.pyRtVsB    c Cs%ti|}|pti||S|d|}yti|}Wntj o d}nX|oti|}|ot i i |t }t i i |odti||}yti|Wntj onXyt i|Wq tj oq Xqqnti||S(sUnmount the BE specified, forcibly if requested. Also unmounts the boot pool dataset, if any, mounted under the BE mountpoint.` s/ROOT/N(R@ReR{RZR[R R=RRtdataset_mountpointRvRRZR^texistsR\t zfs_unmountRxR|(RR-RmR8ReRRgRf((s../../common/libbe.pyR{s. (`t contextlibRvRtstatR/Rrt solaris.zonesRBR@R`tpkg.pkgsubprocesst pkgsubprocessRtbootmgmt.bootconfigRtbootmgmt.pysolRRRRRRRRR R tbootmgmt.bootutilR tbootmgmtR R RRRRRRRRRtbootmgmt.bootloadert bootloaderRRR t bootmgmt.zfsRRRMRR R!R$R'R)RURXR=RPR5RARdR~RRRRRRRRRgRRRRRfRRtcontextmanagerRER*RRJR>RRRzR>RVRKRQR^tbootmgmt.versabootRZRtR{(((s../../common/libbe.pyts|        F(. ; -  qH 5     _  !     83 A     k  ,