i'dWc@sgdZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z ddlmZddlmZddlmZdd lmZmZmZmZmZmZdd lmZmZmZdd lm Z dd l!m"Z"m#Z#dd l$m%Z%m&Z&m'Z'm(Z(ddl)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m3Z3ddl6m7Z7ddl8m9Z9m:Z:m;Z;m<Z<m=Z=ddl>m?Z?m@Z@ddlAmBZBddlCmDZDmEZEmFZFddlGmHZHdZIdZJdZKdZLdZMdZNdZOdZPdZQdZRdZSd ZTd!ZUd"ZVd#ZWd$ZXd%ZYd&ZZd'Z[d(Z\d)Z]d*Z^d+Z_d,Z`d-Zad.Zbe d/d0d1gZcd2Zdd3Zed4Zfd5egfd6YZhd7egfd8YZid9egfd:YZjd;egfd<YZkd=egfd>YZld?egfd@YZmdAe?fdBYZndCe?fdDYZodEe?fdFYZpdGe?fdHYZqdIe?fdJYZrdKesfdLYZtdMesfdNYZudOesfdPYZvdQesfdRYZwdSe?fdTYZxdUZydS(Vst physical.py -- library containing class definitions for physical DOC objects, including Partition, Slice and Disk. iN(t namedtuple(tUUID(tetree(tSystemFirmware(tExtVTOCContext(t extpartition(tV_NUMPARtV_BACKUPtV_BOOTtV_UNMNTt FD_NUMPARTt MAX_EXT_PARTS(tALIAStDRIVEtPARTITION_ID_MAP(tdescriptor_from_key(tcUUIDt UUID2cUUID(tefi_readtefi_freetefi_initt efi_write( tPARTITION_GUID_ALIASEStPARTITION_GUID_PTAG_MAPt EFI_BIOS_BOOTt EFI_SYSTEMtEFI_USRt EFI_RESERVEDt EFI_UNUSEDtEFI_MIN_ARRAY_SIZEtEFI_NUMUSERPARtEFI_DEFAULT_SYSTEM_SIZEtEFI_PREFERRED_RSVPARtEFI_MIN_RESV_SIZER(tset_chap_password(tCalledProcessErrortPopentruntsystem_temp_patht_(t DataObjectt ParsingError(t getallifaddrs(tLOGICAL_ADJUSTMENTtShadowPhysicaltEFI_BLOCKSIZE_LCM(tSizes/usr/sbin/devfsadms/usr/sbin/dhcpinfos/usr/sbin/dladms/usr/sbin/fdisks/usr/sbin/formats/usr/sbin/ipadms/usr/sbin/iscsiadms/usr/bin/netstats/usr/sbin/prtvtocs/usr/sbin/routes /usr/bin/svcss/usr/sbin/svcadms/usr/sbin/fstyps/usr/lib/fs/pcfs/mkfss/usr/sbin/swaps/usr/sbin/umounts /etc/mnttabiiiii tparttphystEthernett InfinibandtIscsiTargetInfotlun_numt target_namecCstt|jt|jS(s compares partition names (tcmptinttname(tatb((s physical.pytpartition_sortfscCs@|j|jj||j|jjkr.dS||jjSdS(s? fill_right() - function to calculate how much space in the next gap is needed to fulfil a change in size of an object (Slice or Partition) obj - Slice or Partition object desired_size - how much more space the object needs to grow by right_gap - the gap immediately adjacent to the object to grow iN(t start_sectortsizetsectors(tobjt desired_sizet right_gap((s physical.pyt fill_rightls cCs,|j||jkrdS||jjSdS(s@ fill_left() - function to calculate how much space in the previous gap is needed to fulfil a change in size of an object (Slice or Partition) obj - Slice or Partition object desired_size - how much more space the object needs to grow by left_gap - the gap immediately preceeding the object to grow iN(R<R=R>(R?R@tleft_gap((s physical.pyt fill_left}s t DiskNotEmptycBseZdZRS(s User-defined Exception raised when attempting to relabel a disk that has children (GPTPartition, Partitions, or Slices) (t__name__t __module__t__doc__(((s physical.pyREstDuplicatePartitioncBs)eZdZddZedZRS(ss User-defined Exception raised when attempting to add an MBR EFI_SYSTEM partition when it already exists. cCs#tt|j|||_dS(N(tsuperRIt__init__t_dup(tselft duplicatetmsg((s physical.pyRKscCs|jS(N(RL(RM((s physical.pyRNsN(RFRGRHtNoneRKtpropertyRN(((s physical.pyRIs tDuplicateGPTPartitioncBs)eZdZddZedZRS(s User-defined Exception raised when attempting to add an EFI_RESERVED when it already exists or when adding either of EFI_BIOS_BOOT or EFI_SYSTEM when one of those already exist. cCs#tt|j|||_dS(N(RJRRRKRL(RMRNRO((s physical.pyRKscCs|jS(N(RL(RM((s physical.pyRNsN(RFRGRHRPRKRQRN(((s physical.pyRRs tInsufficientSpaceErrorcBseZdZddZRS(si User-defined Exception raised when attempting to change the size of a Slice or Partition object cCs#tt|j|||_dS(N(RJRSRKtavailable_size(RMRTRO((s physical.pyRKsN(RFRGRHRPRK(((s physical.pyRSstNoPartitionSlotsFreecBseZdZRS(s User-defined Exception raised when attempting to add an EFI_SYSTEM partition when no slots are left available for the partition. (RFRGRH(((s physical.pyRUstNoGPTPartitionSlotsFreecBseZdZRS(s User-defined Exception raised when attempting to add an EFI_SYSTEM or EFI_BIOS_BOOT partition when no slots are left available for the partition. (RFRGRH(((s physical.pyRVst GPTPartitioncBseZdZdZedZedZedZedZedZ edZ edZ d Z e jdd Zd Zed Zejd ZedZejdZedZejdZedZedZedZedZedZedZdZdZdZRS(cCstt|j|d|_t|_td|_d|_t |_ d|_ d|_ d|_d|_d|_d|_dS(t Initializetcreatet0biN(RJRWRKtactiontFalsetforceR.R=R<Rt_guidRPtuguidtflagtin_usetin_zpooltin_vdevt_is_pcfs_formatted(RMR8((s physical.pyRKs         cCsItjd}|jdt|j|jd|j|jdt|jjx@tj D]%\}}||j krg|}PqgqgWd|j }|jd||j d k r|jd|j n|j d k r|jd|j ntj|d }|jd t|jjtj|jd t|j|S( s Return as xmlt gpt_partitionR8R[R]s{%s}t part_typeRbRcR=tvalR<N(RtElementtsettstrR8R[R]tlowerRt iteritemstguidRbRPRct SubElementR=R>R.t sector_unitsR<(RMtgparttaliasRmRfR=((s physical.pytto_xmls$ #cCs0|jdkrtS|jddkr,tStS(s Returns True if element has: - the tag 'gpt_partition' - a 'name' attribute otherwise return False ReR8N(ttagR\tgetRPtTrue(tclstelement((s physical.pyt can_handles c Cs|jd}|jd}|jd}|jd}|jd}|jd}t|}|dk ry%itd6td6|j|_Wqtk rtd d qXn|j d } | dk rAt | jd |_ | jd } | dk r5yt | } Wq5tdq5Xn| |_ n||_|dkretdny ||_Wn'ttfk rtd|nX|dk r||_n|dk r||_n|S(NR8RfR[R]RbRcttruetfalses&GPTPartition elements force attribute s must be either 'true' or 'false'R=RgR<s>GPTPartition size element has invalid 'start_sector' attributesMissing GPT Partition types*'%s' is not a supported GPT partition type(RtRWRPRuR\RkR]tKeyErrorR)tfindR.R=R7R<R[Rmt ValueErrort TypeErrorRbRc( RvRwR8RfR[R]RbRcRpR=R<((s physical.pytfrom_xmlsH  %           cCs tj|S(sk alias_to_guid - given a GPT partition alias, lookup the corresponding partition GUID. (RRt(Rvt alias_name((s physical.pyt alias_to_guid>scCs'tj|}|dk r#|dSdS(sh guid_to_name - given a GPT partition GUID, lookup the corresponding partition name iN(RRtRP(Rvt gpart_guidtdata((s physical.pyt guid_to_nameEs cCs'tj|}|dk r#|dSdS(si guid_to_ptag - given a GPT partition GUID, lookup the corresponding partition P_TAG iN(RRtRP(RvRR((s physical.pyt guid_to_ptagNs cCsCx<tjD].\}\}}|j|jkr |Sq WdS(sh name_to_guid - given a GPT partition name, lookup the corresponding partition GUID N(RRltupperRP(Rvt gpart_nametp_guidtp_nametp_tag((s physical.pyt name_to_guidWscCsCx<tjD].\}\}}|j|jkr |Sq WdS(si name_to_ptag - given a GPT partition name, lookup the corresponding partition P_TAG N(RRlRRP(RvRRRR((s physical.pyt name_to_ptagascCsBd|jj|jf}t|g}t|dtdddS(s format_pcfs() - method to format a GPT partition with a FAT/pcfs filesystem. This should be used when creating a new EFI system partition on the disk s/dev/rdsk/%ss%ststdins /dev/zerotrN(tparenttctdR8tPCFSMKFSR%topen(RMtrdsk_devtcmd((s physical.pyt format_pcfsks c Csb|dkr|j}n|j|jj|j||d|d|jd|jd|j}|S(s resize() - method to resize a GPTPartition object. start_sector is optional. If not provided, use the existing start_sector. t size_unitstpartition_typeRbRcN( RPR<tdeleteRtadd_gptpartitionR8RmRbRc(RMR=RR<t resized_gpart((s physical.pytresizets     c CsS|j|jj|j|j|jjdtjd|d|j d|j }|S(s^ change_type() - method to change the partition type of a GPTPartition object RRRbRc( RRRR8R<R=R>R.RoRbRc(RMtnew_typetnew_gptpartition((s physical.pyt change_types   cCs|jS(sf guid returns the cUUID object that represents the identifier for this partition. (R^(RM((s physical.pyRmscCs)|dkrtdnt|tr3|}nt|trQt|}nt|trxtjD](\}\}}||krm|}PqmqmWtd|npt|t rt j |}|dkrt j |}n|dkrt|}qnt dt|||_dS(sc attempt to set the guid for this GPT partition being as flexible as possible. s'None' is an invalid GUID values%d not a known tags&unable to convert '%s' object to cUUIDN(RPR}t isinstanceRRRR7RRlt basestringRWRRR~ttypeR^(RMRgRmRRR((s physical.pyRms,     cCstj|jd\}}|S(s Friendly string or NoneN(NN(RRtRmRP(RMR8R((s physical.pyRfscCs ||_dS(sX they really just meant to set guid (which accepts just about anything) N(Rm(RMRg((s physical.pyRfscCstj|jd\}}|S(s: integer tag for libefi corresponding to self.guid or NoneN(NN(RRtRmRP(RMR8R((s physical.pyRsscCs ||_dS(sX they really just meant to set guid (which accepts just about anything) N(Rm(RMRg((s physical.pyRsscCs |jtkS(s is_bios_boot() - instance property to return a Boolean value of True if the GPT partition GUID is a BIOS boot partition (RmR(RM((s physical.pyt is_bios_bootscCs |jtkS(s is_efi_system() - instance property to return a Boolean value of True if the GPT partition GUID is an EFI system partition (RmR(RM((s physical.pyt is_efi_systemscCs|jS(s is_pcfs_formatted() instance property Returns: - True if the GPT partition guid is formatted with a pcfs filesystem. - False if the GPT partition is not formatted with a pcfs filesystem. - None if unknown This test is useful in conjuction with the is_efi_system property to determine if an existing EFI system partition can be reused to store the Solaris UEFI boot program. If False, a format using mkfs on the partition would be required. (Rd(RM((s physical.pytis_pcfs_formatteds cCs |jtkS(s is_solaris() - instance property to return a Boolean value of True if the GPT partition GUID is a Solaris partition (RmR(RM((s physical.pyt is_solarisscCs |jtkS(s is_reserved() - instance property to return a Boolean value of True if the GPT partition GUID is a Solaris Reserved partition (RmR(RM((s physical.pyt is_reservedscCs |jtkS(s is_unused() - instance property to return a Boolean value of True if the GPT partition GUID is an unused partition (RmR(RM((s physical.pyt is_unusedscCsZ|jdk rV|jj}x5|D]*}|j|jj|jdkr%|Sq%WndS(s Returns the HoleyObject gap that occurs immediately before this GPTPartition, or None if there is no such gap. iN(RRPtget_gapsR<R=R>(RMtgapstgap((s physical.pytget_gap_befores  cCsZ|jdk rV|jj}x5|D]*}|j|jj|jdkr%|Sq%WndS(s~ Returns the HoleyObject gap that occurs immediately after this GPTPartition, or None if there is no such gap iN(RRPRR<R=R>(RMRR((s physical.pyt get_gap_afters    cCsd|j|j|jf}|jdk r?|d|j7}n|jdk rb|d|j7}n|jdk r|d|j7}n|jdk r|d|j7}n|jdk r|d|j7}n|j dk r|d|j 7}n|dt |j t |j f7}|S( Ns*GPTPartition: name=%s; action=%s, force=%ss; part_type=%ss, tag=%ds , flag=%ds , in_use=%ss ; in_zpool=%ss ; in_vdev=%ss; size=%s; start_sector=%s( R8R[R]RfRPRsR`RaRbRcRjR=R<(RMtp((s physical.pyt__repr__,s" N( RFRGRKRrt classmethodRxRRRRRRRR.tgb_unitsRPRRRQRmtsetterRfRsRRRRRRRRR(((s physical.pyRWs6  6     %  t PartitioncBseZdZdZdZdddgZedZdZe dZ e d Z e j d!d!ed Zd Zd Ze j d Ze j d!dZdZdZdZdZdZdd!d!d!edZe dZedZedZedZedZ edZ!edZ"edZ#dZ$dZ%d Z&RS("s, class definition for Partition objects iiii icCstt|j|d|_||_|jd|_tj|_t |_ t d|_ d|_ d|_d|_d|_t||_dS(NRYtSolaris2RZi(RJRRKR[tvalidate_childrent name_to_numRftINACTIVEtbootidR\t is_linux_swapR.R=R<RPRbRcRdR,t _children(RMR8R((s physical.pyRKMs        cCstjd}|jd|j|jdk rM|jdt|jn|jdk rx|jdt|jn|jdk r|jd|jn|j dk r|jd|j ntj |d}|jdt|j j t j|jd t|j|S( Nt partitionR[R8RfRbRcR=RgR<(RRhRiR[R8RPRjRfRbRcRnR=R>R.RoR<(RMRR=((s physical.pyRrds#cCs|jdkrtStS(NR(RsRuR\(RvRw((s physical.pyRxvsc Cs|jd}|jd}|jd}|jd}|jd}|dk rrt|dkrrd}n|dkr|dkrtdnt|d t}|jd }|dk r.t|jd |_|jd } | dk r"yt | } Wq"td q"Xn| |_ n||_ |dk rUt ||_ n|dk rm||_ n|dk r||_n|S(NR8RfR[RbRcituse_existing_solaris2sHPartition name must be provided if action is not 'use_existing_solaris2'RR=RgR<s;Partition size element has invalid 'start_sector' attribute(RtRPtlenR)RR\R|R.R=R7R<R[RfRbRc( RvRwR8RfR[RbRcRR=R<((s physical.pyR|s8          c Cs`t|}tt|t||_||_||_||_||_|j||S(sm add_slice() - method to create a Slice object and add it as a child of the Partition object ( tSliceR.RjR=R<RbRcR]tinsert_children( RMtindexR<R=RRbRcR]t new_slice((s physical.pyt add_slices      cCs|jd|jdtdS(sC delete_slice() - method to delete a specific Slice object R8t class_typeN(tdelete_childrenR8R(RMtslc((s physical.pyt delete_slicescCsBd|jj|jf}t|g}t|dtdddS(s format_pcfs() - method to format a partition with a FAT/pcfs filesystem. This should be used when creating a new EFI system partition on the disk s/dev/rdsk/%sp%sRs /dev/zeroRN(RRR8RR%R(RMRR((s physical.pyRs c Cstt|t|}||jkr;|j||Sd}d}tj|j}|j|jj}x|jD]} t | j| jj|j|j j j kr| }||j7}nt |j|jj| j|j j j kry| }||j7}|j|jj}qyqyW|j|jj} |dk rjt || |} | sj|j||Sn| r|dk rt|| |} n| rt|n||j} |j||d| S(s: resize_slice() - method to resize a Slice child. R<N(R.RjR=RRPtcopyR<R>RtabsRtgeometrytcylsizeRBRDRS( RMRR=Rtnew_sizet previous_gaptnext_gapRTt end_sectorRtremaining_spacetnew_start_sector((s physical.pyt resize_slices8   cCsk|dkr|j}n|j|jj|j||d|d|jd|jd|jd|j }|S(sZ resize() - method to resize a Partition object. start_sector is optional. If not provided, use the existing start_sector. NOTE: the resulting new size is not checked to ensure the resized Partition 'fits' within the current available space. To ensure proper 'fit', use Disk.resize_partition() RRRRbRcN( RPR<RRt add_partitionR8RfRRbRc(RMR=RR<tresized_partition((s physical.pyRs    cCs\|j|jj|j|j|jjdtjd|d|j d|j d|j }|S(s[ change_type() - method to change the partition type of a Partition object RRRRbRc( RRRR8R<R=R>R.RoRRbRc(RMRt new_partition((s physical.pyRs   cCs|tjtjgkr'tdn|j|jj|j|j|j j dt j d|j d|d|jd|j}|S(sC change_bootid() - method to change the partition's bootid s?Partition.bootid must be Partition.ACTIVE or Partition.INACTIVERRRRbRc(RtACTIVERt RuntimeErrorRRRR8R<R=R>R.RoRfRbRc(RMt new_bootidR((s physical.pyt change_bootid#s  cCse|jstd|jgSt}xk|jD]`}|jdkrJq/nt|dtkreq/n|j|j|j|j|jj q/W|j |j dd|j|jj t}d}x|t |dkr`||d||}d|ko|j jjknrS|jt||tt|tjn|d7}qW|S(sc get_gaps() - method to return a list of Holey Objects available on this Partition iRRsii(Rt HoleyObjectR=tlistR[tgetattrRtappendR<R>tsorttinsertRRRRR.RjRo(RMtusagetchildtholestiR=((s physical.pyR7s,    % 'cCs|jdk r|jr4|jj}td}n|jj}|jjj}x;|D]0}t|j |j j |j |krY|SqYWndS(sA Returns the HoleyObject gap that occurs immediately before this partition, or None if there no such gap. If the partition is logical, only logical gaps (gaps within an EXTENDED partition) are considered; otherwise, only Disk gaps (gaps between primary partitions are considered. iN( RRPt is_logicaltget_logical_partition_gapsR+RRRRR<R=R>(RMRt adjacent_sizeR((s physical.pyRcs     cCs|jdk r|jr4|jj}td}n|jj}|jjj}x;|D]0}t|j |j j |j |krY|SqYWndS(sD Returns the HoleyObject gap that occurs immediately after this partition, or None if there is no such gap. If the partition is logical, only logical gaps (gaps within an EXTENDED partition) are considered; otherwise, only Disk gaps (gaps between primary partitions) are considered. iN( RRPRRR+RRRRR<R=R>(RMRRR((s physical.pyRs      t0c Cs|jdt|j}||dj|djjg}itjd6|d6}|dk rl||dR.RoRPRRs( RMR8RbRcRsR]RtargstkwargsR((s physical.pytcreate_entire_partition_slices         cCs=x6tjD](\}}|j|jkr |Sq WdS(se name_to_num - given a partition name, lookup the corresponding partition number N(RRlRRP(Rvt part_nametp_numR((s physical.pyRscCsCtt|jjtg|jD]}|jj^qtjS(s remaining_space() - instance property to return a Size object of the remaining overall space available on the Partition (R.RjR=R>tsumRRo(RMtc((s physical.pyRs)cCs|jS(s is_pcfs_formatted() instance property Returns: - True if the partition is formatted with a pcfs filesystem. - False if the partition is not formatted with a pcfs filesystem. - None if unknown This test is useful in conjuction with the is_efi_system property to determine if an existing EFI system partition can be reused to store the Solaris UEFI boot program. If False, a format using mkfs on the partition would be required. (Rd(RM((s physical.pyRs cCs,|jdk r(t|jtkr(tStS(s| is_primary() - instance property to return a Boolean value of True if the partition is a primary partition N(R8RPR7R RuR\(RM((s physical.pyt is_primarys$cCs |jdks|jrtStS(s| is_logical() - instance property to return a Boolean value of True if the partition is a logical partition N(R8RPRR\Ru(RM((s physical.pyRscCs#|jr|jtjkrtStS(s~ is_extended() - instance property to return a Boolean value of True if the partition is a extended partition (RRfRtEXTENDED_ID_LISTRuR\(RM((s physical.pyt is_extendedscCs|jdkrtStS(s is_solaris() - instance property to return a Boolean value of True if the partition is an EFI system partition i(RfRuR\(RM((s physical.pyRscCs0|jdkr|j s(|jdkr,tStS(s| is_solaris() - instance property to return a Boolean value of True if the partition is a Solaris partition ii(RfRRuR\(RM((s physical.pyRscCs#tt|j|t|_dS(s method to override the parent's version of __setstate__. We do this so deepcopy() sets validate_children to True N(RJRt __setstate__RuR(RMtstate((s physical.pyR scCs1tt|j}t||_t|_|S(s method to override the parent's version of __copy__. We want the _children list to be a shadow list instead of a flat list. We also need to reset validate_children to True. (RJRt__copy__R,RRuR(RMtnew_copy((s physical.pyRs cCsd|j|jf}|jdk r9|d|j7}n|dt|jt|jf7}|jdk r|d|j7}n|jdk r|d|j7}n|j dk r|d|j 7}n|d|j 7}|S(NsPartition: name=%s; action=%ss; part_type=%ss; size=%s; start_sector=%ss ; in_zpool=%ss ; in_vdev=%ss ; bootid=%ds; is_linux_swap=%s( R8R[RfRPRjR=R<RbRcRR(RMts((s physical.pyRs N('RFRGRHRRRRuRKRrRRxRR.RRPR\RRRRRRRRRRRRRQRRRRRRRRRR(((s physical.pyRBs@  +  3   ,          RcBsGeZdZdZdZedZedZdZRS(s& class definition for HoleyObject cCs,tt|jd||_||_dS(Nthole(RJRRKR<R=(RMR<R=((s physical.pyRK2s cCsdS(N((RM((s physical.pyRr7scCstS(N(R\(RvRw((s physical.pyRx:scCsdS(N((RvRw((s physical.pyR>scCsd|j|jf}|S(Ns%HoleyObj: start_sector: %d; size: %s(R<R=(RMR((s physical.pyRBs( RFRGRHRKRrRRxRR(((s physical.pyR.s   RcBskeZdZdZdZedZedZdZdZ e j d dZ dZRS( s( class definition for Slice objects cCsztt|j|d|_t|_t|_td|_d|_ d|_ d|_ d|_ d|_d|_dS(NRYRZi(RJRRKR[R\R]tis_swapR.R=R<RsR`RPRaRbRc(RMR8((s physical.pyRKLs        cCstjd}|jdt|j|jd|j|jdt|jj|jdt|jj|j dk r|jd|j n|j dk r|jd|j ntj |d}|jd t|j jtj|jd t|j|S( NtsliceR8R[R]RRbRcR=RgR<(RRhRiRjR8R[R]RkRRbRPRcRnR=R>R.RoR<(RMRR=((s physical.pyRr`s#cCs0|jdkrtS|jddkr,tStS(s} Returns True if element has: - the tag 'slice' - a 'name' attribute otherwise return False RR8N(RsR\RtRPRu(RvRw((s physical.pyRxrs c Cs|jd}|jd}|jd}|jd}|jd}|jd}t|}|dk ry%itd6td6|j|_Wqtk rtd d qXn|dk ry%itd6td6|j|_ Wqtk rtd d qXn|j d } | dk rt | jd |_ | jd} | dk ryt | } WqtdqXn| |_n||_|dk r||_n|dk r||_n|S(NR8R[R]RRbRcRyRzs%Slice element's force attribute must sbe either 'true' or 'false's'Slice element's is_swap attribute must R=RgR<s7Slice size element has invalid 'start_sector' attribute(RtRRPRuR\RkR]R{R)RR|R.R=R7R<R[RbRc( RvRwR8R[R]RRbRcRR=R<((s physical.pyRsF  %  %         cCsZ|jdk rV|jj}x5|D]*}|j|jj|jdkr%|Sq%WndS(sy Returns the HoleyObject gap that occurs immediately before this Slice, or None if there is no such gap. iN(RRPRR<R=R>(RMRR((s physical.pyRs  cCsZ|jdk rV|jj}x5|D]*}|j|jj|jdkr%|Sq%WndS(sw Returns the HoleyObject gap that occurs immediately after this Slice, or None if there is no such gap iN(RRPRR<R=R>(RMRR((s physical.pyRs    cCsP|dkr|j}n|j|jj|j||||j|j}|S(sj resize() - method to resize a Slice object. start_sector is optional. If not provided, use the existing start_sector. NOTE: the resulting new size is not checked to ensure the resized Slice 'fits' within the current available space. To ensure proper 'fit', use Disk.resize_slice() or Partition.resize_slice() N(RPR<RRRR8RbRc(RMR=RR<t resized_slice((s physical.pyRs     cCsd|j|j|j|jf}|jdk rE|d|j7}n|jdk rh|d|j7}n|jdk r|d|j7}n|jdk r|d|j7}n|j dk r|d|j 7}n|dt |j t |j f7}|S(Ns/Slice: name=%s; action=%s, force=%s, is_swap=%ss, tag=%ds , flag=%ds , in_use=%ss ; in_zpool=%ss ; in_vdev=%ss; size=%s; start_sector=%s( R8R[R]RRsRPR`RaRbRcRjR=R<(RMR((s physical.pyRs N(RFRGRHRKRrRRxRRRR.RRPRR(((s physical.pyRHs  1  tDiskcBseZdZefZedZdZedZ edZ e dZ e j dZ e dZej dZe d Ze d Ze d Ze d Ze d Ze dZe dZe dZedZdZejed;d;edZdZejdZ eje!j"de!j#d;d;dZ$dZ%ejdZ&ejd;d;edZ'dZ(ejdZ)d;dZ*d;dZ+d;dZ,d Z-d!Z.d"Z/d#Z0d$Z1d%Z2d&Z3d'Z4d(Z5d)Z6d*Z7d+Z8d,Z9d-Z:d.Z;d/Z<d0Z=d1Z>d2Z?d3Z@d4ZAd5ZBd6ZCe d7ZDe d8ZEe d9ZFe d:ZGRS(<s$class for modifying disk layout cCstt|j|||_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_t|_t|_t|_t|_tjdkrd|_n d|_d|_d|_t|_d|_t|_t|_tj}d}t tj!}|j"dks<|j"dkr[t#}|j$t#t%|_n%|j"dkrt&}|j$t&n||_'t(||_)d|_*t |_+t |_,t-||_.dS(s# constructor for the class ti386tx86tsparctuefi64tzvmmtbiosN(/RJRRKRRPt disk_propt disk_keywordtiscsiRtvolidtdevpathtdevidt receptacletopathtwwnR\tiscdromt isdedicatedtrequires_mbr_efi_partitiont DiskGeometryRtplatformt processort kernel_archRbRct _whole_diskt_labelt write_cachetall_names_to_xmlRRtRtreserved_guidstfw_nameRRRuRt _sysboot_guidttuplet_required_guidst vdev_labelt active_ctdst passive_ctdsR,R(RMR8Rtfirmwaret sysboot_guidtrequired_guids((s physical.pyRKsR                              cCstjd}|jdk r4|jd|jn|jdk rY|jd|jn|jdt|jjd}|j t kr}tjd}|j dk r|jd|j n|j dk r|jd|j n|j dk r |jd|j n|jdk r0|jd |jn|jdk rU|jd |jn|jdk r}|jd |jq}nd ddd d dg}xt|D]l}t||ddk r|dkrtj|d}n|jd t|||jd |PqqW|dk r(|j|n|jdk rtj|d}|jjdk rt|jd|jjn|jjdk r|jd|jjn|jjdk r|jd|jjn|jjdk r|jdt|jjjtjqn|jdk rBtj|d}|jd|jjn|jdk rtj|d}|jj dk r|jd|jj n|jjdk r|jd |jjn|jj dk r|jd|jj qn|S(NtdiskRbRct whole_diskt disk_nameRRRRRRR8t name_typeRtdev_typet dev_vendort dev_chassistdev_sizeRtkeyR(RRhRbRPRiRcRjR RkRRuRRRRRRRRnRRR#R$R%R&R>R.RoRR'R(RMRR!t priority_listtpriorityRRR((s physical.pyRrMsp    cCs|jdkrtStS(NR(RsRuR\(RvRw((s physical.pyRxscCs|jd}|jd}|jd}tddt}|dk rW||_n|dk ro||_n|dk ry%itd6td6|j|_Wqt k rt dd qXn|j d }|dk r2|jd |_ |jd |_ |jd |_|jd|_|jd|_|jd|_|jd}|d kr~|jd|_ q2|d kr|jd|_ q2|d kr|jd|_q2|dkr|jd|_q2|dkr|jd|_q2|dkr#|jd|_q2t dn|j d}|dk rt} |jd| _|jd| _|jd| _|jd} | dk rt|jd| _n| |_n|j d} | dk r t|_| jd|j_n|j d} |j d} | dk rt|_| jd |j_ | jd|j_| jd |j_n|dkr|dkr| dkr| dkrt dn|S(NRbRcR RRRyRzs$Disk element's whole_disk attribute s must be either 'true' or 'false'R!RRRRRRR"R8sNo Disk identification providedRR#R$R%R&RR'RR(RtRR\RPRbRcRuRkR R{R)R|RRRRRRtDiskPropR#R$R%R.R&Rt DiskKeywordRR't DiskVdevLabelR(RvRwRbRcR RR!R"RtdpR&RRR((s physical.pyRs|                      cCs|jS(sL Returns the disk label. Currently "GPT" and "VTOC" are recognized. (R(RM((s physical.pytlabelscCs|dkrtd|n|dkrfxYttgD]'}|jd|}|r8tq8q8Wn!|jdt}|rtn||_dS(s< Attempt to set the disk label. The disk must be empty of child (DOS) Partitions or Slices if val is "GPT" or empty of GPTPartitions if val is "VTOC" or a a DiskNotEmpty exception is raised. val must be either one of "GPT" or "VTOC" otherwise ValueError is raised. tGPTtVTOCs!%s is not a recognized disk labelRN(R/R0(R}RRt get_childrenRERWR(RMRgR?tchildren((s physical.pyR.s   cCs|jS(s; Returns the whole_disk mode value (True or False) (R(RM((s physical.pyR  scCsZ|rMx8tttgD]'}|jd|}|rtqqWt|_n t|_dS(s Attempt to set the whole_disk mode on the disk If use_whole_disk is true, the disk must be empty of child GPTPartitions, Partitions or Slice objects or a DiskNotEmpty exception is raised. use_whole_disk must be either True or False RN(RWRRR1RERuRR\(RMtuse_whole_diskR?R2((s physical.pyR s   cCs7dt|jj}tt|tjd|jjS(s Returns the Size value that a GPT header including protective MBR and GPE partition entries would occupy on this disk it blocksizei(RRR4R.RjRo(RMtblocks((s physical.pytgpt_primary_table_size's   cCs7dt|jj}tt|tjd|jjS(st Returns the Size value that a GPT header including GPE partition entries would occupy on this disk iR4(RRR4R.RjRo(RMR5((s physical.pytgpt_backup_table_size7s   cCs|jdtS(NR(R1RW(RM((s physical.pytgpt_partitionsFscCs2|jdt}g|D]}|jr|^qS(sh primary_partitions() - instance property to return all primary partitions on this Disk R(R1RR(RMt partitionsR/((s physical.pytprimary_partitionsJscCs2|jdt}g|D]}|jr|^qS(sh logical_partitions() - instance property to return all logical partitions on this Disk R(R1RR(RMR9R/((s physical.pytlogical_partitionsSscCs|jS(s Instance proprerty to return the tuple of additional required partition type GUIDS besides the obvious Solaris partition. (R(RM((s physical.pyR\scCs|jS(s Instance proprerty to return the GUID of the required system boot partition (EFI system or BIOS boot partition) or None for SPARC (R(RM((s physical.pyRcscCs ttttj|jjS(s' Size of the EFI system boot partition (R.RjRt byte_unitsRR4(RM((s physical.pytefi_sysboot_sizekscCs|jdkrttdtd}ttdttd}|r}|tg|jD]}t|j^q[}q|tg|jD]}t|j^q}nDttdt }|tg|j D]}t|j^q}|sdSt t |SdS(s get_next_partition_name() - method to return the next available partition name as a string Supports both GPT and legacy MBR Partition types primary - boolean argument representing which kind of MBR partition to check. If True AND Disk has an MBR label, only check primary partitions. If False, check logical partitions. Ignored on GPT labeled Disks R0iiiN(R.RitrangeR R R:R7R8R;RR8RPRjtmin(RMtprimaryt primary_sett logical_setRt available_settgpt_set((s physical.pytget_next_partition_nameqs //,c Cstd}td}td}td}td}td}td}td}td } td } td } td } d} d}d}d}d}d}d}d}|jdk ry|jjdk r^|jjtd tjkrtj}td}ntj}td}|jjjd|} tj d| |}n|jj }|jj }n|j dk rb|j }|jdk r|jj dkrd}qd}ytt|}|j}Wntk rnX|dk r|j}|dk r_t|r_|dj}|dk r\|j}|jdj}q\q_qnl|jdk r}|j}nQ|jdk r|j}n6|jdk r|j}n|jdk r|j}n|jr| }n|jr| }n| }|j}|dkr| }n|dkr.| }n|dkrC| }n|dkrX| }nd||f}d||||||||||f }|dk rd|||f}n|dk rd|||f}n|dk rd||| f}n||fS(s Returns a tuple of (name, summary) containing details about this disk. Currently, this method is only in use by the gui-installer. Returns: (name, summary) - name, a string indicating the size and controller type of disk. This is suitable for use as the label for the disk icon. - summary, a 5 (or 7) line text string summary of the Disk's details. This is suitable for use as a Gtk+ Tooltip for the disk icon. R.tTypetVendortDevices Boot devicetChassist Receptaclet DedicatedtUnknowns???GBtYestNot1tTBtGBtunitss%.1ftiSCSIis%s %ss"%s: %s %s: %s %s: %s %s: %s %s: %ss %s %s: %sN(R'RPRR&R.ttb_unitsRRttlocaletformatR$R%RR#RR tdrivetOSErrort controllersRt attributesRtsplitRRRRRR t is_boot_diskR(RMt size_labeltctrl_type_labelt vendor_labelt device_labelt bootdev_labelt chassis_labeltreceptacle_labeltdedicated_labelt unknown_labeltunknown_size_labelt yes_labeltno_labelR=tvendortdevicet ctrl_typetbootdevtchassisRt dedicatedRRt units_strtsize_strtdm_drivetdm_aliastdm_controllerst dm_attribsR8tsummary((s physical.pyt get_detailss                         "                    c Csut|} || _tt|t|d|jj| _|| _|| _|| _ || _ |j | | S(sv add_gptpartition() - method to create a GPTPartition object and add it as a child of the Disk object R4( RWRmR.RjRR4R=R<RbRcR]R( RMRR<R=RRRbRcR]t new_gpart((s physical.pyR s       cCs|jd|jdtdS(sY delete_gptpartition() - method to delete a specific GPTPartition object R8RN(RR8RW(RMRp((s physical.pytdelete_gptpartition$sc Cstt|t|d|jj}||jkrG|j||Sd}d}tj|j}|j|jj }x|j D]} | j| jj |jdkr| }||j7}q|j|jj | jdkr| }||j7}|j|jj }qqW|j |jj } |dk rXt || |} | sX|j||Sn| r|dk rt || |} n| rt |n||j } |j||d| S(sH resize_gptpartition() - method to resize a GPTPartition child. R4iR<N(R.RjRR4R=RRPRR<R>RRBRDRS( RMReR=RRRRRTRRRR((s physical.pytresize_gptpartition*s@       Rc Cst|tkrtj}nt|} || _|| _tt|t|d|jj | _ || _ || _ || _ |j| | S(sp add_partition() - method to create a Partition object and add it as a child of the Disk object R4(R7R RRRfRR.RjRR4R=R<RbRcR( RMRR<R=RRRRbRcR((s physical.pyRds         cCs|jd|jdtdS(sK delete_partition() - method to delete a specific Partition object R8RN(RR8R(RMR((s physical.pytdelete_partitionscCstt|t|}||jkr;|j||Sd}d}tj|j}|j|jj}|jr|j } |j j } n|j } t d} x| D]} t| j| jj|j| kr| }||j7}nt|j|jj| j| kr| }||j7}|j|jj}qqW|j|jj} |dk rt|| |} | s|j||Sn| r|dk rt|| |} n| rt|n||j} |j||d| S(sB resize_partition() - method to resize a Partition child. iR<N(R.RjR=RRPRR<R>RRRRRR+RRBRDRS(RMRR=RRRRRTRtgap_listRRRR((s physical.pytresize_partitionsF          c Cslt|}tt|t|d|jj|_||_||_||_||_ |j ||S(sh add_slice() - method to create a Slice object and add it as a child of the Disk object R4( RR.RjRR4R=R<RbRcR]R( RMRR<R=RRbRcR]R((s physical.pyRs      cCs|jd|jdtdS(sC delete_slice() - method to delete a specific Slice object R8RN(RR8R(RMR((s physical.pyRsc Cstt|t|}||jkr;|j||Sd}d}tj|j}|j|jj}x|jD]} t | j| jj|j|j j kr| }||j7}nt |j|jj| j|j j kry| }||j7}|j|jj}qyqyW|j|jj} |dk rdt || |} | sd|j||Sn| r|dk rt || |} n| rt|n||j} |j||d| S(s: resize_slice() - method to resize a Slice child. R<N(R.RjR=RRPRR<R>RRRRRBRDRS( RMRR=RRRRRTRRRR((s physical.pyRs8   c syjdkrd|fSjdkr7tdnjdt}tfd|}|r}t|ddnj}|dkrt dnt t t t j jjj}tfd |Dd}|dk r |j}n0|dkr'tdd nj|jsRtd t n|jswtd t |jn|jd krtdnxf|D]L}|j|jj|jdkr|}j|jj} |j}PqqWj} |j}|jj| } |j| } |j| dt jd| }jt ||jdt jdjdt} | |fS(s Add default system/bios boot for x86 if this is a GPT disk Params - donor a GPTPartition object on the same disk that can be resized as a last resort if the disk doesn't have enough contiguous free space to contain the system partition. Returns tuple: (sys_part, donor) - sys_part The appropriate EFI system or BIOS system that was created. - donor The donor partition which may have been partially or fully used to create space for the system partition. Callers should check the returned copy of donor. RR0s8Can't add EFI_SYSTEM/EFI_BIOS_BOOTto a VTOC labeled diskRcs4|jdko3|jjko3t|jtkS(NR(R[RmRR7R8R(tgpe(RM(s physical.pyt*sisAattempt to add EFI_SYSTEM/EFI_BIOS_BOOT when disk already has onesMattempt to add EFI_SYSTEM/EFI_BIOS_BOOT to disk with no empty partition slotsc3s$|]}|jkr|VqdS(N(R=(t.0R(tsys_size(s physical.pys Css9Insufficient space for EFI_SYSTEM/EFI_BIOS_BOOT partitions0Donor partition does not belong to this disk: %ssGDonor partition must be a solaris partition. Invalid partition type: %stpreserves8Donor partition is a preserved and cannot not be resizedRR<RR]N( RRPR.R}R1RWtfilterRRRERVR.RjRR<RR4RtnextR<RSt name_matchesRRRfR[R=R>RRoRRRu( RMtdonortgpartstsysRRRt gptsys_startRtshortagetnewsizetnewstart_sectortsys_part((RMRs physical.pytadd_gpt_system sd                     c s|jdkrtdn|jdt}td|}|r^t|ddng|D]}t|j^qe}xAtgt t dddD]}||krPqqWt d t |j jdkrd}nt |j j}t||j}t|d d d t} tfd | Dd} | dk ri| j| jj} n&|dkrtdn |j|jstdt|n|jstdt|jn|jdkrtdnxr| D]M} |j|jj| jdkr| } | jj} | j| } PqqW} |j|jj} |jj| }|j|dt j!}|j"t|| t j!dt#dt}||fS(s Add default EFI_RESERVED to disk if this is a GPT disk Returns tuple: (resv_part, donor) - sys_part The Solaris reserved partition that was created. - donor The donor partition which may have been partially or fully used to create space for the reserved partition. Callers should check the returned copy of donor. R0s;Can't add Solaris reserved partition to a VTOC labeled diskRcSs|jo|jdkS(NR(RR[(R}((s physical.pyR~sis5attempt to add EFI_RESERVED when disk already has oneiisMattempt to add EFI_SYSTEM/EFI_BIOS_BOOT to disk with no empty partition slotsR'cSs|jS(N(R<(R((s physical.pyR~streversec3s'|]}|jjkr|VqdS(N(R=R>(RR(t resv_sectors(s physical.pys ss1Insufficient space for Solaris reserved partitions0Donor partition does not belong to this disk: %ssGDonor partition must be a solaris partition. Invalid partition type: %sRs8Donor partition is a preserved and cannot not be resizedRRR]N($R.R}R1RWRRRR7R8R R>RRVR-RR4R!RtsortedRuRRPR<R=R>RSRRRjRRfR[RR.RoRR(RMRRtresvR}tusedRtblock_multipliert unsortedgapsRRt resv_startRRRt resv_part((Rs physical.pytadd_gpt_reservesd     "              c CsA|jsd|fS|jdkr1tdn|r|j|jsbtdt|n|jdkr|j rtdt|qn|j dt }t d|}|rt |dd nd}x0|D](}|j r|jd kr|}PqqWttttj|jj}t jd }|r/|jd t}d} d} |rxH|jD]:} | j|krx| s| j| jkr| } qqxqxW| r| j} qn| s|sX|j}|stn|j} xB| D]:} | j|kr| s3| j| jkr?| } q?qqW| rX| j} qXn| s| so|j rtdd n|j} | r|j| jj}| j} n|j}|j} |jj|}|j|}|j|dtj d|}qn|j!|| |jdtj d|}n|j"t jd}|j} |jd t}|j!|| dj|jdtj d|}|jd t}d}xA|jD]3} |dks| jj|jjkr| }qqW|j!||j|jjdtj dt jdd|j#d|j$}||fS(s Add, if required, an EFI system partition x86 to an MBR/DOS partitioned disk An MBR/DOS EFI system partition is required if and only if the system is UEFI and attempting to install onto an MBR/DOS partitioned disk. Preference is given to using a logical partition slot rather than a primary slot because the small amount of space required by the EFI system partition and the very limited number of primary partition slots available makes for poor use of primary slots and helps avoid large, unusable primary partition gaps. Params - solaris2_part a Solaris2 Partition object on the same disk that can be resized or converted if the disk doesn't have enough contiguous free space or partition slots to contain the EFI system partition. Returns tuple: (sys_part, donor) - efi_part The EFI system partition that was created. The EFI system partition returned will be a logical partition to conserve available primary partition slots. - solaris2_part The Solaris2 partition which may have been modified to create space for the system partition. Callers should check the returned copy of donor as it may have been resized and/or converted from primary to logical type to make room for the EFI system partition R/s8Can't add MBR EFI System partition to a GPT labeled disks7solaris2_part argument does not belong to this disk: %sRYs=solaris2_part argument must be a valid Solaris2 partition: %sRcSs|jdko|jS(NR(R[R(R/((s physical.pyR~- sisGattempt to add an MBR EFI System partition to disk that already has oneRs EFI SystemR@s+Insufficient space for EFI system partitionRR<Rs DOS ExtendedRRbRcN(%R RPR.R}RRRjR[RR1RRRIRR.RR<RR4RRER\RR=R<RURRRSRR>RRoRRRbRc(RMt solaris2_parttpartstefisyst extended_partR/t efisys_sizet efisys_typeRtbestfitt efisys_startRRt s2_pre_gapRt new_s2_sizet new_s2_startt efisys_parttnew_extended_partt biggest_gap((s physical.pytadd_mbr_systems"                                cCsd}|jdkrcy|j|\}}Wn&tk rY}|j}||nXd}nzy|j|\}}Wn&tk r}|j}||nXy|j|\}}Wntk r}|j}nX|||fS(sK Add, if required, an EFI system partition (fdisk or GPT), and a reserved partition. Returns tuple: (efi_sys, resv, donor) - efi_sys either a Partitioin or GPTPartition or None to be used as the EFI system partition. None is returned if the system does not require an EFI System partition. - resv a GPTPartition to be used by ZFS or None if the system does not require a reserved GPTPartition - donor The donor you passed in or None. cSs%|jr!|js!d|_q!ndS(NRY(RRR[(R/((s physical.pyt check_efi_sys s  R0N(R.RRIRNRPRRRR(RMRRtefi_systerrR((s physical.pytadd_required_partitions s$     cCsst}xT|jD]I}|jdkr.qn|j|j|j|j|jjdqW|jdd|jjdg|dd+|j|j j j|j jt}d}t |j jdkrd}nt |j j}x|t|dkrn||}||d||d}||kra|jt|dtt|tjn|d7}qW|S(sc _get_gpt_gaps() - method to return a list of Holey Objects on a GPT labeled disk. Riii(RRR[RR<R=R>RR6RR&R7R-RR4RRR.RjRo(RMRRRRtmin_block_countR<R=((s physical.pyt _get_gpt_gaps s. "       c Cst}x|jD]}|jdkr.qnt|tr[t|dtkr[qq[nt|tr||jr|qq|n|j |j |j |j |j j qW|j |jdd|j |jjj t}d}x|t|dkr}||}||d||}d|ko?|jjknrp|j t|tt|tjn|d7}qWt}x|D]z}|j |jjdkr|j |jj|jj|jj} | |j } | |_ tt|j j | tj|_ nd|j ko3|jjknr|jdkr|jj|_ tt|j j |jjtj|_ n|j j |jjdkr|j j |jj|jj} tt| tj|_ n|j j |jjkr|j |qqW|S(s _get_vtoc_gaps() - method to return a list of Holey Objects (depending on architecture) available on the Disk. Backup slices (V_BACKUP) and logical partitions (if x86) are skipped. RRsiiiR(RRR[RRRRRRRR<R=R>RRRR&RRRRR.RjRoR( RMRRRRR<R=t final_listRRt differenceR((s physical.pyt_get_vtoc_gaps! sZ       "      % cCst|jdstS|jdkr2|jS|jdkrm|js`td|jjgS|jSn|jdkrx6t t gD](}|j d|}|r|jSqW|j dt }|jr|jStd|jjgSdS(s get_gaps() - method to return a list of Holey Objects, depending depending (primarily) on disk label, available on the Disk. If disk.label is unset, an attempt will be made to identify the disk label based on contents of the disk. R&R/R0iRN(thasattrRRR.RRRR&RRPRRR1RWR2(RMR?R2((s physical.pyRy s"     c Cs|jdt}x7|D](}|jr|jdkr|}PqqWtSg|D]}|jrS|^qS}|st|j|jgSt}x8|D]0}|j |j|j |j|jj qW|j |j d|j|j |j|jj t}d} x| t |dkr|| d|| } | tkr|| t} tt| dttj} |j t| | n| d7} qW|S(s get_logical_partition_gaps() - method to return a list of Holey Objects available within the extended partition of the disk RRiii(R1RRR[RRRR<R=RR>RRRR+R.RjRo( RMt part_listR/RRt logical_listRt logical_partRRR=R<tsize_obj((s physical.pyR s8 "        cCs#tt|j|t|_dS(s method to override the parent's version of __setstate__. We do this so deepcopy() sets validate_children to True N(RJRRRuR(RMR((s physical.pyR scCs1tt|j}t||_t|_|S(s method to override the parent's version of __copy__. We want the _children list to be a shadow list instead of a flat list We also need to reset validate_children to True. (RJRRR,RRuR(RMR((s physical.pyR s cCsd}|d|j|j|j|j|jf7}|jdk r|jjdk rj|d|jj7}n|jjdk r|d|jj7}n|jj dk r|d|jj 7}qn|j dk r|d|j j 7}n|d|j |j |jf7}|jdk r(|d|j7}n|jdk rK|d |j7}n|d |j7}|d |j7}|jr|d d j|j7}n|jr|dd j|j7}n|S(NsDisk: s.ctd=%s; volid=%s; devpath=%s; devid=%s; wwn=%ss; prop:dev_type=%ss; prop:dev_vendor=%ss; prop:dev_size=%ss; keyword: key=%ss(; is_cdrom=%s; label=%s; is_dedicated=%ss ; in_zpool=%ss ; in_vdev=%ss; whole_disk=%ss; write_cache=%ss; active ctd aliases=%ss, s; passive ctd aliases=%s(RRRRRRRPR#R$R&RR'R R.R RbRcR RRtjoinR(RMR((s physical.pyR s2&  cCsd|j}|jjd|jttdI}x?|jD]1}|j|rCtd|g}t|qCqCWWdQXdS(s@ method to unmount all mounted filesystems on this disk s /dev/dsk/%ss"Unmounting filesystems on disk: %sRs-fN( RtloggertdebugRtMNTTABt readlinest startswithtUMOUNTR%(RMtdisk_devtfhtlineR((s physical.pyt_unmount_ufs_filesystems s cCsztdg}t|dtj}xR|jjD]A}|j|kr1|jd}td|g}t|q1q1WdS(sH method to release all UFS swap devices associated on this disk s-lt check_resultis-dN(tSWAPR%R$tANYtstdoutt splitlinesRR[(RMRRRtswap_dev((s physical.pyt_release_ufs_swap s c Csd|j}|jjdx|D]}|dt|j}tdg}t|dtj}xK|j j D]:}|j |rrtd|g}|st|qqrqrWtd|g}|s$t|q$q$WdS( s^ _create_ufs_swap() - method to create a new swap entry from a list of slices s /dev/dsk/%ssCreating ufs swap slice(s)Rs-lRs-ds-aN( RRRRjR8RR%R$RRRR( RMtswap_slice_listtdry_runRt swap_sliceRRRR((s physical.pyt_create_ufs_swap s   c Csq|s|j|jntjddd}t|d}|jtd}x|D]}x0|t|jkr|j d|d7}qhW|j d|j |j dddddd|j |j jf |d7}q_WWdQXd |j}td d ||g}|st|ntj|td |Dd} | dk rm| jd krm| jndS(s` _update_partition_table() - method to lay out the fdisk partitions of the Disk tprefixsfdisk-itws0 0 0 0 0 0 0 0 0 0 s/%s %d %lu %lu %lu %lu %lu %lu %lu %lu iNs/dev/rdsk/%sp0s-ns-Fcss|]}|jr|VqdS(N(R(RR/((s physical.pys [ sRY(RRttempfiletmkstempRRR;R7R8twriteRfRR<R=R>RtFDISKR%tostunlinkRRPR[R( RMRRt tmp_part_fileRt number_partsR/t rdisk_devRR((s physical.pyt_update_partition_table/ s2           cCsx|D]}|jr6|jjdt|qn|jjt|j}|j|_ |j j |_ |j |_|j|_|jdk r|j|_nd|_qWdS(s gpt_struct must be already pre allocated an intialised with the correct number of partitions matching gpart_list by calling efi_init() prior to invocation of this method s0Ignoring invalid "Unused" type GPT partition: %siN(RRtwarningRjtcontentst efi_partsR7R8R<tp_startR=R>tp_sizeR`tp_flagRmRR_RPtp_uguidR(RMt gpt_structt gpart_listRptefi_part((s physical.pyt_update_gpt_struct` s      cCs4|jdkr*|jjd|jdSd|j}d}x&|D]}tt|j|}qDW|d}|dkrdStd|Dd}|s0t j |t j t j B}z |rvzt |} | j} x|D]}}|jd krt|j} | | jkr;td |jjt|fn| j| } tj| j|_qqWWdt| Xnt||} zG|j| ||jjd |jjt| t|| Wdt| XWdt j|Xtd |Dd}|dk r0|jd kr0|jq0ndS(s _update_gptpartition_table() method to initialise and write a DK_GPT structure with the desired partition information. R0s)Unable to change a VTOC labeled disk (%s)Ns/dev/rdsk/%ss0iiicss3|])}|jdkr|jdkr|VqdS(RN(R[R_RP(RR((s physical.pys sRsKGPT partition with preserve action does not exist on disk: %s Partition: %ssGPT layout for efi_write():css|]}|jr|VqdS(N(R(RR}((s physical.pys sRY(R.RRRtmaxR7R8RRPRRtO_RDWRtO_NDELAYRRR[t efi_npartsRRRjRRRR_RRRt_pretty_print_dk_gptpRtcloseR(RMRRRt max_gpart_numRpt num_gpartstno_uguidRt orig_gptptorig_gptRRtgptpR((s physical.pyt_update_gptpartition_tablez sT              c Cswtddddddddgt}t}t|_t|_t|_|jdkrxK|j dt D]!}|j rn|j j |_qnqnWn|jj||_||d<|jdkrt}t|_t|_t|_t||_||d RRtncylRtBOOT_SLICE_RES_CYLRsR`R<R7R8tv_part( RMt vtoc_structt slice_listtnsecstslicestbackupR/tbootRtslc_data((s physical.pyt_update_vtoc_struct s4(                 c Cs|jdkr*|jjd|jdSt|}|dkrFdS|st|j*}|j|||jj|jj WdQXndS(sz _update_slices() _ method to read and (re)write an extvtoc structure with the desired slice information. R/s4Unable to change the VTOC of a GPT labeled disk (%s)Ni( R.RRRRRRRtnheadstnsectors(RMRRt num_slicestextvtoc((s physical.pyt_update_slices s    cCs&tddd|jg}t|dS(sA force_vtoc() - method to force a VTOC label onto a disk s-Ltvtocs-dN(tFORMATRR%(RMR((s physical.pyt force_vtoc scCs&tddd|jg}t|dS(sD force_efi() - method to force an EFI/GPT label onto a disk s-Ltefis-dN(RRR%(RMR((s physical.pyt force_efi scCs|s|jtt|j}|jj}t|j|j|j }|j |_ |j|_|j |_ ||_ t t|j |j|j t j|j_d|_ndS(s _set_vtoc_label_and_geometry() - method to force a VTOC label and to set all of the disk geometery including dev_size R0N(RRR RtmediaRZR R4RRt ncylindersRRR.RjRoRR&R.(RMRRWtdmat new_geometry((s physical.pyt_set_vtoc_label_and_geometry" s       cCstjdddtd}t|d}d}|j|WdQXtd|jd |g}|s|jjd d j |t |d dnt j |dS(sD _label_disk() - method to label the disk with a VTOC label Rsformat-tdiriRslabel Ns-ds-fs Executing: %st Ri(ii( RRR&RRRRRRRR%RR(RMRt tmp_cmd_fileRtoptionsR((s physical.pyt _label_disk8 scCstjdddtd}t|d}d|}|j|WdQXtd|jd |g}|s|jjd d j |yt |d dWq|jj di|d6|jd6qXnt j |dS(s~ set_disk_partition_tag() - method to set the tag for the partition number 0 of the disk using format command Rsformat-R iRspartition 0 %s label Ns-ds-fs Executing: %sR Ris;Failed to update partition tag to %(tag)s for disk %(ctd)s.RsR(ii(RRR&RRRRRRRR%terrorRR(RMRsRR RR R((s physical.pytset_disk_partition_tagF s   cCs |dkrtS|jdkr}|jdkr}|jdkr}|jdkr}|jdkr}|jdkr}|jdkr}tS|jdk r|j|jkr|jdkr|jdkr|jdkr|jdkr|jdkr|jdkr|j|j krt StSn|jdk r=|j|jkr=tSn|jdk re|j|jkretSn|jdk r|j|jkrtSn|jdk r|j|jkrtSn|jdk r|j|jkrtSn|jdk r|j|jkrtSnt S(sReturns True if 'other' Disk's name fields matches this Disk. Matching only occurs on fields that have been specified in 'other'. Comparison to the fields ctd, volid, devpath, devid, wwn opath and receptacle is only done if they are not None. Returns False if no fields match. If the only property specified in other is ctd then an additional match will be True if active_ctds of this object contains other.ctd. N( RPR\RRRRRRRRRu(RMtother((s physical.pyRZ sP  cCs)|jdk r%|jjdkr%tStS(s6Returns True if this Disk has the "boot_disk" keyword.t boot_diskN(RRPR'RuR\(RM((s physical.pyR\ scCsFtt|jjjtg|jD]}|jj^qtjS(s remaining_space() - instance property to return a Size object of the remaining overall space available on the Disk ( R.RjRR&R>RRR=Ro(RMR((s physical.pyR s)cCsv|jdks!|jjdkr%tS|jdkrJtd|jn|jjtksn|jj t krrt StS(s Returns True is this disk is firmware bootable, False otherwise. At this time, the only type of disk that is known to not be firmware bootable is an iSCSI disk that is not over Ethernet. RSs$'iSCSI information for '%s' not set.N( RRPR#RuRRRtlocal_datalink_classtDATALINK_CLASS_PHYStlocal_datalink_mediatDATALINK_MEDIA_ETHERNETR\(RM((s physical.pytis_firmware_bootable s!cCsv|jdks!|jjdkr%tS|jdkrJtd|jn|jjtkrr|jj t krrt StS(s? Returns True if this disk is an iSCSI disk that is over IPoIB RSs#Disk '%s' has no iSCSI information.N( RRPR#R\RRRRtDATALINK_CLASS_PARTRtDATALINK_MEDIA_INFINIBANDRu(RM((s physical.pytis_iscsi_over_infiniband s!cCsv|jdks!|jjdkr%tS|jdkrJtd|jn|jjtkrr|jj t krrt StS(s> Returns True if this disk is an iSCSI disk that is over IPoE RSs#Disk '%s' has no iSCSI information.N( RRPR#R\RRRRRRRRu(RM((s physical.pytis_iscsi_over_ethernet s!N(HRFRGRHRRRuRKRrRRxRRQR.RR R6R7R8R:R;RRR=RERvR.RRRPR\RRxRyRRRRRzR|RRRRRRRRRRRRRRRRRRRRRRRRR RRRR\RRRR(((s physical.pyRs  M DV   # y :  = 3 s u 2 7 X % 4    1  P 3       >  R cBseZdZdddZRS(s/ class definition for DiskGeometry objects icCs:||_||_t|_d|_d|_d|_dS(Ni(R4RR\RRRR(RMR4R((s physical.pyRK s      (RFRGRHRK(((s physical.pyR  sR*cBs eZdZdZdZRS(s+ class definition for DiskProp objects cCs(d|_d|_d|_d|_dS(N(RPR#R$R%R&(RM((s physical.pyRK s   cCsx|jD]}t||dk rt||dk r|dkr_|j|jkrtSqt||jt||jkrtSq t||dkr t||dk r tSq WtS(s Attempt to match disk_prop. Any of the properties dev_type/dev_vendor/dev_chassis/dev_size must been specified For comparrisons of dev_size, a match is found if the size of other's dev_size is smaller than this dev_size R&N(t__dict__RRPR&R\RkRu(RMRtk((s physical.pyt prop_matches s* **(RFRGRHRKR(((s physical.pyR* s R+cBseZdZdZRS(s. class definition for DiskKeyword objects cCs d|_dS(NR(R'(RM((s physical.pyRK s(RFRGRHRK(((s physical.pyR+ sR,cBseZdZdZRS(s0 class definition for DiskVdevLabel objects cCsd|_d|_d|_dS(N(RPRRR(RM((s physical.pyRK" s  (RFRGRHRK(((s physical.pyR, stIscsicBseZdZdZdZdZedZedZdZ dZ dZ e d Z e d Ze d Ze d Ze d Ze dZedZedZdZRS(s( class definition for Iscsi objects t3260cCstt|j|d|_d|_d|_tj|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_d|_t|_t|_d|_dS(N(RJRRKRPtsourceR5t target_luntISCSI_DEFAULT_PORTt target_portt target_iptinitiator_namet chap_namet chap_passwordt_local_datalink_namet_local_datalink_ipt_local_datalink_classt_local_datalink_mediat_local_datalink_deviceRtctd_listtdictt iscsi_dictt sparc_slice(RMR8((s physical.pyRK. s"               cCs;tjd}|jdk r4|jd|jn|jdk rY|jd|jn|jdk r~|jd|jn|jdk r|jd|jn|jdk r|jd|jn|j dk r|jd|j n|j dk r|jd|j n|j dk r7|jd |j n|S( NRR!R5R"R$R%R&R'R(( RRhR!RPRiR5R"R$R%R&R'R((RMRw((s physical.pyRrL s$cCs|jdkrtStS(s` Returns True if element has: - the tag 'iscsi' otherwise return False R(RsR\Ru(RvRw((s physical.pyRx` sc Cs|jd}|jd}|jd}|jd}|jd}|jd}|jd}|jd} td } |d kr|| _nx|dkrtd n || _|dkrtd n || _|dk r|| _n|dk r|| _n|dk r,|| _ n|dk rD|| _ n| dk r\| | _ n| j dk r| j dkrtd n| j dk r| j dkrtdn| S(NR!R5R"R$R%R&R'R(Rtdhcps1Iscsi element must specify 'target_lun' attributes0Iscsi element must specify 'target_ip' attributes-CHAP username specified without CHAP passwords-CHAP password specified without CHAP username( RtRR!RPR)R"R%R5R$R&R'R(( RvRwR!R5R"R$R%R&R'R(R((s physical.pyRk s@                 cCsd}tjjts1ttdtntddd|g}t|dtj }|j dkrttd|n|j j }|d krt d d |g}t|t|dtj }|j j }|d kr+ttd |q+n%|d kr+ttd|ntd}yP|jsOtj}n |j}t|jt|f}tj|ddWntjtjfk r} t|i|jd6|jd6| d6n>tk r} t|i|jd6|jd6| d6nX|jdkre|j} | d9k re|jf|jf|jf| |_qen|jd9k rtddd|jg}t|nktddg}t|didd6}x@|j jD]/} | jdr| j dd|_PqqW|j!d9k r|j"d9k rtddd d!g}t|tddd|j!g}t||j#j$d"t%|j"n|jd9k r|jd#|j} |jd9k r| d$|j7} ntd%d&| g}t|tdd'd(d g}t|tdd)d*| g} ny|j} |jd9k rH| d$|j7} ntd%d+| g}t|tdd'd,d g}t|tdd)d*g} tt&d-d.gxt'dD]p}t| didd6}g|j jD]} d/| kr| ^q}t(d0|s$t)j*dqPqWttd1x|j jD]} | j+} | jd2r| j d}n| jd3r| j dd}n| jd4rK|d9k rK| j,d5d6j-d7d}t.|||j/|Rttimetsleeptlstript rpartitionRR3R0tkeysR.R4R(RMtSVCt state_cmdRRRt socket_errR9taddressRt dhcp_paramsRt discovery_strtiscsi_list_cmdRt iscsi_listRR5R4t iscsi_ctdR((s physical.pyt setup_iscsi s                                            cCstddg}t|didd6}x|jjD]}d|kr8d|krtddd d g}t||jrtd d |jg}t|qqd |krtdddd g}t||jrtd d|jg}t|qqq8q8W|jdk s!|jdk rtddg}t|didd6}xT|jjD]@}d|krYd|krYtddddg}t|qYqYWnd|_d|_t |_ dS(s; remove the iSCSI configuration from the initiator RRBR;R<R=tenabledtStaticR:s--statictdisabletremoves static-configs Send Targetss --sendtargetssdiscovery-addresssinitiator-nodesAuthentication TypeR>s-atnoneN( RIR%RRR5R%R'RPR(RR.(RMRRR((s physical.pytteardownms<                 cCst|jt|jf}tj|}|jd}|jtddddg}t|dt j }x|j j D]e}|j dd}|j dd}||krqn|j dd } | j dd} PqWttd i|d 6td d d| g}t|dt j }|j j} | d krU| } n$ttdi| d6| d6tdddd| g}t|dt j }|j jj dd} |j jj dd }| r| tkr| }n|rhtdddd|g}t|dt j }|j jj dd}|j jj dd }n$ttdi| d6| d6| |_||_| |_||_||_dS(s Method to set this instance's attributes for the local datalink that is used to reach this iSCSI target host is show-addrs-ps-os addr,addrobjRR@REisUiSCSI target reached using local host IP '%(ip)s', but IP not found on any interface.R8sshow-ifs-p-otclasss[Interface '%(interface)s' is expected to have a class of 'ip'. Found '%(interface_class)s't interfacetinterface_classs show-links class,overs show-physs media,deviceskCannot determine underlying datalink for datalink '%(datalink)s' which has a class of '%(datalink_class)s'.tdatalinktdatalink_classN(RjR%R$RNROt getsocknameRtIPADMR%R$RRRR[RR'RLtDLADMRR)R*R+R,R-(RMttarget_addresstsockt local_host_ipRRRtaddrt ipaddresstaddrobjRjRkRlRmt datalink_overtdatalink_mediatdatalink_device((s physical.pyt_get_local_datalinksX               cCs'|jdk r|jS|j|jS(sq Property to return the datalink name of the local datalink used to reach this iSCSI target. N(R)RPRz(RM((s physical.pytlocal_datalink_names cCs'|jdk r|jS|j|jS(sn Property to return the ip address of the local datalink used to reach this iSCSI target. N(R*RPRz(RM((s physical.pytlocal_datalink_ip s cCs'|jdk r|jS|j|jS(sw Property to return the datalink class type of the local datalink used to reach this iSCSI target. N(R+RPRz(RM((s physical.pyRs cCs'|jdk r|jS|j|jS(sw Property to return the datalink media type of the local datalink used to reach this iSCSI target. N(R,RPRz(RM((s physical.pyR#s cCs'|jdk r|jS|j|jS(ss Property to return the datalink device of the local datalink used to reach this iSCSI target. N(R-RPRz(RM((s physical.pytlocal_datalink_device/s cCs>t}|jd|jxGtjD]6\}}|j|jkr-|jd|jPq-q-W|j|j}|d k r|jd|n|jd|j |jd|j |j d k r|jd|j n|jdt t|jd|jd k r1|jd |jnd j|S( s class method to return a properly formatted 'network-boot-arguments' string value for booting this iSCSI target over IPoE. An example return string looks like: host-ip=10.0.0.100,subnet-mask=255.255.255.0, router-ip=10.0.0.1,iscsi-target-ip=192.168.10.200, iscsi-target-name=iqn.1986-03.com.sun:2510. 600a0b80003ab986000000004a13a357, iscsi-port=3260,iscsi-lun=0,iscsi-partition=a s host-ip=%sssubnet-mask=%ss router-ip=%ssiscsi-target-ip=%ssiscsi-target-name=%ss iscsi-port=%ss iscsi-lun=%sisiscsi-partition=%sR?N(RRR|R*titemsR\tnetmaskt get_router_ipR{RPR%R5R$thexR7R"R1R(RMt nbp_propsR8tinfot router_ip((s physical.pytsparc_obp_boot_string;s"  $c Csdtdddddg}t|didd6}t}x&|jjD]}|sw|jjdrGt}qGqGn|j}t |d krt j j d |qGn|d }t |d kr|d |kr\|SqGt d |g}t|didd6}xO|jjD]>}|jjdr|jd } | |krX|SqqWqGWdS(s Return the router ip address for the network configured on datalink_name, if one exists. Otherwise, return None. s-rns-ftinetsflags:+GR;R<R=s--------isARoute entry from netstat(1M) has less than 5 fields, skipping: %siiRts interface:N(tNETSTATR%R\RRRLRRuR[RRMRRtROUTERP( t datalink_nameRt netstat_proctin_tablet netstat_linetfieldstgatewayt route_proct route_lineRj((s physical.pyRgs2     cCsd}ytdg}t|}Wnttfk r;nXX|jr|jjdr|jjjdd}|dg}|j |dn|S(s Checks if DHCP Autodiscovery is available. If yes, return the parameters received. Returns: a list with 4 items (IP, port, LUN and target) or None. trootpathRR@iiiN( RPtDHCPINFOR%RXR#RRRLR[textend(tparamsRRt all_params((s physical.pyRRs  cCs d|j}|jdk r0|d|j7}n|jdk rS|d|j7}n|jdk rv|d|j7}n|jdk r|d|j7}n|jdk r|d|j7}n|jr|d|j7}n |d7}|jdk r|d |j7}n|S( Ns target_ip=%ss; target_lun=%ss; target_name=%ss; target_port=%ss; initiator_name=%ss; chap_name=%ss; ctd=%ss; ctd=NOT MAPPEDs ; source=%s( R%R"RPR5R$R&R'R.R!(RMR((s physical.pyRs"   (RFRGRHR#RKRrRRxRRbRhRzRQR{R|RRR}Rt staticmethodRRRR(((s physical.pyR( s$   3 / c     ,4cCs:|j}d}|d7}|dt|jd7}|dt|jd7}|dt|jd7}|dt|jd7}|dt|jd7}|d t|jd7}|d t|jd7}|d t|j d7}|d t|j d7}|d7}xt |jD] }|d t|d7}|dt|j |j d7}|dt|j |jd7}|dt|j |jd7}|dt|j |jd7}|dt|j |jd7}|dt|j |jd7}|dt|j |jd7}q&W|S(Nsdk_gpt struct: s-------------- sefi_version: s sefi_nparts: sefi_part_size: sefi_lbasize: sefi_last_lba: sefi_last_u_lba: sefi_disk_uguid: sefi_flags: sefi_altern_lba: s efi_part #s: s p_start: s p_size: s p_guid: s p_tag: s p_flag: s p_name: s p_uguid: (RRjt efi_versionRt efi_part_sizet efi_lbasizet efi_last_lbatefi_last_u_lbatefi_disk_uguidt efi_flagstefi_altern_lbaR>RRRRRRRR(tdk_gptptdk_gptRR((s physical.pyRs.   """"""&(zRHRRURR RNRRTt collectionsRtuuidRtlxmlRtbootmgmt.bootinfoRtlibadmRtlibadm.cstructRt libadm.constRRRR R R tlibdiskmgt.constR R Rt libdiskmgtRt libefi.cuuidRRtlibefiRRRRt libefi.constRRRRRRRRRRR R!tlibimaR"tsolaris_installR#R$R%R&R'tsolaris_install.data_objectR(R)tsolaris_install.netifR*t&solaris_install.target.shadow.physicalR+R,R-tsolaris_install.target.sizeR.RSRRpRRRoRIRtPRTVTOCRRJRMtFSTYPRRRRRRt BACKUP_SLICEt BOOT_SLICEt ALT_SLICERRRRR3R;RBRDRQRERIRRRSRURVRWRRRRtobjectR R*R+R,RR(((s physical.pyts       ."X(    }%