ɼjWc@sddlZddlZddlZddlZddlZddlZddljZddlZddl Z ddl j Z ddl mZddlmZmZmZmZmZmZmZmZmZmZddlmZddlmZmZmZm Z m!Z!ddlm"Z"m#Z#m$Z$m%Z%m&Z&m'Z'ddl(j)Z*ddl j+Z,ddl-j.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(ZMejNddde9d)ZOd*ZPd+ZQdd,ZRd-ZSd.ZTd/ZUd0ZVd1ZWd2ZXd3ZYd4ZZd5Z[dd6l\m]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)QststatictnoevictcCsKy|jd|d|Wn*tk rF}tjdt|IJnXdS(Nt boot_devicestforces WARNING: %s(tcommit_boot_configRtsyststderrtstr(tbootconftdevlistR-tbpfail((s../../common/libbe.pytcommitZsc Csw|dk r6t| r6tjdIJtjdntj|\}}|dkra||fStjdkrUtj rUyBt dit t j 6#}t|}t|j|WdQXWntk r||fSXd}|rt|dd}nx|D]J}|jdd}|r|r||krAt |dR/R0R?R@tbeRenameRBRCtgetzpoolbybenameREtbe_make_root_dstget_menu_entriesttitleRUtreplacet StandardErrorR7R5( t old_benamet new_benameRYtzpoolR[R8t old_root_dstbisR\((s../../common/libbe.pyRas6        cCstjdd|dd}tj||}|dkrxttj|dkrxtj|td|qxnt d|d}|dkrytj |tj|Wnt k rnXtd|ntj |}|dkr td |ntj|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 mountpointRY((s../../common/libbe.pytbe_bootadm_update_archives*        c Csi|d k rt| s2|d k rOt| rOtjdIJtjdn|stj\}}}}|dkrd Sn|stj\}} |dkrd S|jd\} } } | ri| j rit | } | } x| D]w}|j dd }|sqn|jd\}} }| s|| ks|j rMqnt t || } qWn |} d} t }| d}xl|sd| |f}xB| D]4}|j dd }|sqn||krPqqWt}|d7}qWntj||||||}|d}|ddkr0d Stjdkr\t|tj|}|stjd|IJtjdnt|}t||}t||}g|jD]$}t|d d |kr|^q}|r|}n|}|r9|dj}||_||_t |_|j|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 rpartitiontisdigittintRMtmaxRNRFtbeCopyRBRCR{RbRERctboot_instancesRLtcopyReR7tdefaulttadd_boot_instancetbe_append_menuR5(t dst_benamet src_benametsrc_snapt dest_rpoolt bename_propstbe_descRYtsrc_pooltsrc_dsRZtbasetseptrevtmaxrevR^tobentnbasetnrevtgoodtnumt dest_snapRjR[t src_root_dsR8txt instancestnewtitletbi_copy((s../../common/libbe.pyRs              $    c s\t|s)tjdIJtjdntj|}|s_tjd|IJtjdnt||t}|r|dkrd }t }n g}t }tj |||}|dkr|St j dkrXt|h}|jfdt |rt} nd } d } | rg|jD](} t| dd | dkr5| ^q5} | rt | d_t|| d| d|| d} qnzay,|d kr|j}nt||Wn.tjk r} tj| jIJtjd SXWd | d k rNtj| }|dkr>td |ntj| 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|ddkS(NR7(RLR=(R(R8(s../../common/libbe.pyt|sR7R|tBE_ERR_BOOTFILE_INSTNsUnable to unmount BE %s(R>R/R0R?R@RbRctget_active_on_boot_beR=RFRNt beDestroyRBRCREtdelete_boot_instanceRRLRt#prep_be_for_bootloader_installationtget_boot_device_listR5tbltBootLoaderInstallErrorR(t errorcodeRxRvRsRu(Rt destroy_snapst force_unmountRjt active_beR3tactive_on_boot_be_destroyedRYR[taob_betmntptRtmatchestblerr((R8s../../common/libbe.pyRXsf             c Cst|s)tjdIJtjdntj|}|s_tjd|IJtjdnt||}tjdkrt |}t |||}|st ||}n |d}t |_ d}zmy8t|||||}t |_t||jWn.tjk r=}tj|jIJtjdSXWd|dk rtj|}|dkr|td|ntj|nXWdQXntj|||}|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@RbRcRBRCRERdRRFRR=Rt set_bootfsR5RRRR(RRxRvRsRut beActivateBH( RRjR8R[RlR\RRRY((s../../common/libbe.pyt beActivatesD         cCstd}|stS|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.pyRscCsGt\}}|dkrdSx!|D]}|j|r&|Sq&WdS(Ni(RAR=RM(tattrtretctbestbootenv((s../../common/libbe.pyRs   cCst\}}|dkrdS|dkrIt}t|dd}nd}x<|D]4}|jdd|krV|jdd}PqVqVW|S(s Get the default ZFS BE name. iR7R8R|N(RAR=RHRLRM(R7RRR\RR((s../../common/libbe.pytget_default_benames    c CsyBt3}d}|dkrKxc|jD]}|jr+|}Pq+q+Wn<y|j|}Wn(tk rd}tj|ddfSX|dkrtjj dddk rt j dIJndSd}t j dkrd}nt j dkrd }nitd 6|d 6}t|d d |}|jddk rT|i|d6}n|jddk r~|jd|}nt|dd}|dkrIt|dd} | dkrtjj dddk rt j dIJndSt} t| | }t| |dkrItjj dddk rBt j dIJndSnttd|} t| dk r| d} | dkrt|} | dkrt j d|IJd St|} qn t|} | dkrtjj dddk rt j d|IJnd!S| d|d|j}d|| fSWdQXWnEtk r}tjj dddk rt j 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(RER=RRt IndexErrorR@RRstenvironRMR/R0tplatformt processorRRLtfindRfRR R RRRt unmount_zfstmount_zfs_in_temp_dirtexpanded_kargsRKR1(tentnumR[tinstR\terrRtkdictRR7t rpoolnametlzfshtmntenttmountptRtargstexc((s../../common/libbe.pytget_kargs_and_mountpts                         cCsw|jdkrtdn|j|kr1dSg}x9|jD].}t|dd|krA|j|qAqAW|S(NRPs Not on ZFSR7(t boot_fstypeRvtzfsrpR=RRLtappend(t bootconfigtpoolR8RlR\((s../../common/libbe.pyRdXsc Csd|}d}x|jD]}tj||jdtj}|jj}|j}|dkroqny'||j dd|j d!}Wnt k rqnXPqW|dkr|jrd} |r| d|7} nt j | 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 subprocesstPopenRUtPIPERtreadtwaittindext ValueErrorRR( RzRt boot_loadertcmdtvertpkgnametproctoutputRYtexc_msg((s../../common/libbe.pytget_bootloader_version_from_ipshs*    '  cCsd}tjj|d}tj|}xR|D]J}tjj||}tjj|r1|j|r1|t|Sq1WdS(Nsbootloader-version@s boot/solaris(RstpathRXRttislinkt startswithRrR=(Rzt BLVER_PREFIXtdirnametcontentstitemtfullpath((s../../common/libbe.pyt get_bootloader_version_from_roots !cCs`|jj}yt|}Wntk r7}d}nX|sSt|||}n||_dS(N(tdata_source_boot_instancetrootpathRRyR=Rtversion(RRRzRtose((s../../common/libbe.pytset_bootloader_versions  cCs2tjdddd|d|}|j||S(NtfstypeRPR7Re(tbctSolarisDiskBootInstanceR=R(RR7ReR\((s../../common/libbe.pyRs  cCs)|rd|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.pyRcscCstj|\}}||fS(N(R@tbeGetBootDeviceList(RRR8RYR3((s../../common/libbe.pytbe_get_boot_device_listsc CsHtj|\}}x||D]b}d|kr|jdd|kr|d|kr|d|d}} |r~t} Pq~qqWd \}} t} |stjdd|dd } tj|| }|d krt t j | d krt j | t d |qqn| |_||j_t|j|| rD| SdS( Nt snap_namet orig_be_poolR8tmountedRzRmsbe-%s.Rns/system/volatileisUnable to mount BE %s(NN(R@RARMR=RNRFRoRpRqRrRsRtRuRvRRRR( tbcfgR\RRR8RYtbelisttbenvR Rzt needsmount((s../../common/libbe.pyRs2         c cs|dkrg}n|dkratjdd!\}}|dkrUtj}qj|g}n |g}|stdnd}xT|D]L}y"t||||\}}} Wntk rd}nX|rPqqW|s7tdt|dkrdndt|dkrdnd d j|fn|V|d kr| rd |} t | d} | dkryt j | Wqt k rqXqndS( 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@R}tbeGetRootPoolListRvt_try_load_boot_configRKRrRXRwRsRuRy( RjtflagsR6tverboseRt rpool_listRtboot_cfgt pool_mountedt pool_pathRRY((s../../common/libbe.pyREsB             cCsxd|}t|d}d}xK|jjD]7}|jj\}}}||kr3||fSq3WdtfS(Ns3/usr/sbin/zfs list -H -o name,mountpoint,mounted %si(RwR=trstript splitlinesRURN(tdatasetRt cmd_stdoutRtlinet next_datasettmtpttmtd((s../../common/libbe.pyt_get_zfs_mountinfo1s  c Cs3t|\}}|dkrtjdkrwtrwd|}t|d}|dkrwt|\}}qwn|dkrtjdd|dd}d||f}t|d}|dks| rytj|Wnt k rnXdSqnyo|r(t |t r(t |}ni}|j i|d 6|d 6|d 6tj||} | ||fSWnt k r.tjjd ddk rd dl} tjd|IJ| jn|dkr(|r(d|}t|d}|dkr(ytj|Wq%tk r!q%Xq(nnXdS(NRis/usr/sbin/zfs mount %sRmspool-%s.Rns/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 RwRoRpRsRuRKR=t isinstancetdicttupdateRRRRMt tracebackR/R0t print_excRy( RRR6RRRRRYtkwargsRR,((s../../common/libbe.pyR=sT                 cCsb|r+x|jD]}|jr|SqWdSt(}x|jD]}|jrA|SqAWWdQXdS(N(RRR=RE(RR\R[((s../../common/libbe.pyRH~s   cCsd}|dks6t||ks6t|dkr:tSx6|D].}|dksk|dksk|dkrAtSqAWt|tstStS(s.Returns True if the BE name passed in is validi@iRRt%N(R=RrRNRRRF(RtBE_NAME_MAX_LENtchar((s../../common/libbe.pyR>s0 $cCstjdddd}d||f}t|d}|dkr~tjd|IJytj|Wntk rynXdS|S(NRmslibbe-Rns/system/volatiles'/usr/sbin/zfs mount -o mountpoint=%s %sis!Failed to mount zfs filesystem %s( RoRpRwR/R0RsRuRKR=(tzfsnamettemp_dirRRY((s../../common/libbe.pyRs   cCsd|}t|dS(Ns/usr/sbin/zfs unmount %si(Rw(R7R((s../../common/libbe.pyRs cCs|j}yztj|dtjdtj}|j\}}|j}|dkr{tjd|d|||fIJn||fSWnOtk r}tjd||fIJdSt k r}tjd|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( RURRRt communicatet returncodeR/R0RyR=R(RRRR!t cmd_stderrRYtoserrtval_err((s../../common/libbe.pyRws"      cCs/ytj|ddWntk r*nXdS(s scom.oracle.libbe:be-policyR*N(RPt zfs_set_propR(R ((s../../common/libbe.pyt"_be_reset_policy_to_static_noraises    c Cst|}tg|D]"}|r|jd r|^q}tg|D]%}|rK|jdrK|d^qK}||Btt}|rtt|dnd|krtdn||@}|rt|}|jg|D]}d|^qt|nd|k} i} x|D]} tj | } | sYt | n| j | d d krggf| | RRRwR:RORIRORWtbootmgmt.versabootRSRqRx(((s../../common/libbe.pyts|        F(. ; -  qH 5     _  !     83 A     k  ,