sWc@s#dZddljZddljZddlZddlZddl Z ddl Z ddl j Z ddlZddlZddlZddlmZmZmZmZmZmZmZmZmZddlmZddlmZddlm Z ddl!m"Z"ddlm#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)dd l*m+Z+m,Z,dd l-m.Z.m/Z/m0Z0ddl1Z1ej2d Z3ej2d Z4ej2d Z5dZ6dZ7dZ8dZ9dZ:dZ;ye j<ddde=j Z>Wnej?j Z>nXdZ@ddZBdZCdZDdZEdZFdZGdddZHddZIdd ZJddd!ZKddd"ZLddd#ZMdeNd$ZOddeNd%ZPe=d&ZQdddd'ZRdddd(ZSd)ZTd*ZUd+ZVd,ZWdd-ZXd.ZYd/ZZd0Z[dddd1Z\dddd2Z]ddddd3Z^ddd4Z_d5Z`d6ZadeNd7Zbd8Zcd9Zdd:Zed;Zfd<Zgd=ZheNd>Zid?Zjd@ZkdAZldBZmdCZneodDkrenndS(Es Helper module to support menu and bootloader bootadm operations. This helper acts as a bridge between bootadm C code and pybootmgmt/libbe. iN( t BootmgmtUnsupportedPropertyErrort"BootmgmtInsufficientDiskSpaceErrortBootmgmtConfigWriteErrortBootmgmtBootPoolFailureErrortBootmgmtZFSErrortBootmgmtInvalidParameterErrort"BootmgmtInvalidParameterValueErrortBootmgmtAddCredentialErrort BootmgmtError(tDiskBootConfig(twrite_temp_file(tGRUB2BootLoader(tLegacyGRUBBootLoader(tget_boot_configt get_active_betset_bootloader_versiont spawn_commandtget_default_benamet beActivatetbe_make_root_ds(tzpool_get_bootfstzfs_get_user_prop(t mnttab_opent getmntentt mnttab_closes^[\.A-Za-z0-9_-]+$s^[\x20-\x7E]+$s ^(.*?)=(.*?)$isSolaris bootenv rctSolaris_reboot_transients%/boot/.bootadm_transient_save_defaultsRFormat is property=: use "" to include whitespace (e.g. property="val val2").tSUNW_OST_OSCMDs/usr/lib/localetfallbackcCs|jgdS(s Write the menu to disk. N(tcommit_boot_config(tboot_cfg((sbootadm-helper.pyt_bootadm_commit_menu\scCs|r4|r4d|kr4||kr4t|dfSny|jdd\}}Wn3tk rtd|tttddfSXt||fS(sGiven a string, return the prop/value pair separated. If there is no value portion, return successfully, but return None for the valuet=isError attempting to parse: %sN(t BAM_SUCCESStNonetsplitt ValueErrortbootadm_perrortBAM_PROPERTY_FORMATt BAM_ERROR(tentrytprops_allowed_to_have_no_valuetproptval((sbootadm-helper.pyt_bootadm_parse_propval`s   cCsnd|}t|d}d}xG|jjD]3}|jj\}}||kr3|}q3q3W|S(s Get the mountpoint the root pool is mounted at. This function is always called from situations where the 'rpool' is guaranteed to be mounted (e.g. by get_boot_config). s+/usr/sbin/zfs list -H -o name,mountpoint %siN(RR!trstript splitlinesR"(trpooltcmdt cmd_stdoutt pool_pathtlinetnametmntpt((sbootadm-helper.pyt_bootadm_get_rpool_mntptqs   cCs4x-t|D]\}}|jr ||fSq WdS(sY Returns what entry is currently set as default and the associated instance. iN(Ni(t enumeratetdefaultR!(t boot_listtidxtinst((sbootadm-helper.pyt_bootadm_find_defaults cCs|t|d}t|}y7t||d}|jt|tSWdQXWn"tk rwttdt SXdS(sH Take the index of the current default entry and dump it to a file. itwNsCouldn't save the default entry to the temporary file. bootadm -m update_temp will not be able to restore the correct default entry( R;R5topentwritetstrR tIOErrorR$t_R&(tzpoolR8t dest_filetindext rpool_mntptttarget((sbootadm-helper.pyt_bootadm_save_default_to_files   c Cst|}||}yt|dn}|j}y!t|}tj||SWn7tk rttd|dSt k r|SXWdQXWn&t k rttd|dSXdS(sA Open in_file and grab the to-be-set-to-default entry index. trssMalformed entry found while trying to restore the default entry from %s. Default entry is now the first in the menuiNs_Couldn't find/read %s to restore the default entry. Default entry is now the first in the menu.( R5R=treadtinttostremoveR#R$RAtOSErrorR@(RBtin_fileREtpathRFRDR9((sbootadm-helper.pyt_bootadm_get_default_from_files*        cCstd|jGHt|tjs"dSd|jGHd|jGHd|jGHt|ddrgd|j GHn d|GHdS( sY Given an instance output its key entries (kernel, boot_archive, bootfs, title). s title: %sNs kernel: %sskernel arguments: %ssboot archive: %stbootfss bootfs: %ssZFS root pool: %s( ttitlet isinstancetbctSolarisDiskBootInstancetkerneltkargst boot_archivetgetattrR!RQ(t boot_instanceRB((sbootadm-helper.pyt_bootadm_pretty_prints    tcCs t}t|}|jtjjkr.|Sd}d}|dkrtjtj j rt j }|dkrt t dqtj|st t dqt j d}||krd}qt t dqt t dn|d krtjj|rnt|d } | j} | jd } | }tj|set t dqd}qt t d |n3|d krd}t t dn|dkr1t|j}|jjrdGHndGHxGt|jD]6\} } d| | jdjtt| jfGHqWWdQXn|dkrnt| }|jjr`dGHndGHWdQXnJ|dkrt|K}xAt|jD]0\} } d| djtt| jfGHqWWdQXn|dkr|jd} x| D]} yt| }|j|}Wn[t k rKt t d| t!}qn.t"k rxt t d|t!}qnXd|djtt|jfGHqWnt t d||rt#|d||t$|t%}t%}t&|||d}nWdQX|S( s Set entire menu password. R\t set_prompts#Please specify a non-empty passwordsAPassword must only contain printable characters (ASCII 0x20-0x7E)sRe-enter password: s menu-passwordsPassword does not matchs2Please use option -f to supply the passwordtsetRHs sfile %s does not existtdelsMenu password is removedtlistsThe entire menulock is onsThe entire menulock is offs%d %s users: %ss, Ntlist_parse_globalsentire_menulock:onsentire_menulock:offt list_parses%d:%stlist_parse_entryt,s(Invalid index passed for an instance: %ss&No menu entry can be found at index %dsError: Unknown command %st/('R R t boot_classRTt BootConfigtBOOT_CLASS_DISKRKtisattytsyststdouttfilenotgetpassR$RAtPASSWD_CRITERIAtmatchROtexistsR=treadlineR,t credentialtpasswordR6tboot_instancesRRtjointmapR?t cred_listR"RJR#R&t IndexErrort_bootadm_set_username_passwordRtFalsetbootadm_install_bootloader(tset_cmdt pw_file_pathtindexstrRBtretvaltmybctset_propRstpassword_reenteredtfpR2tiR:t indexlistRDt boot_insttforcetverbose((sbootadm-helper.pytbootadm_set_menu_passwords            +   1      % c Cst}tjd}tjd}tjd}tjd}|dkrbttdtStjj |sttd|tSt |}|j t j jkr|St|d}x|D]} | jd} g} d } | jd } g| D]} | d kr| ^q} | s+qn| d d d krEqn|j| rjttd qn |j| r|j| } t| jd} | sttdqnd| d<| | d.*?)$sset-menu-password +-s *$s9set-menu +add-user\=(?P.*?) +password\=(?P.*?)$s%set-menu +add-user\=(?P.*?) *$s!Please provide an input file pathsFile %s does not exist RHs R\t it#sBError - format in batch file: set-menu-password -s password= tpws#Error - Failed to set menu passwords-fiisFError - format in batch file: set-menu add-user= password= tuserRs#Error - Failed to set user passwords auth-file=s-PtbootadmRktstderrsError while invoking %s: %sN( R tretcompileR!R$RAR&RKRORpR RfRTRgRhR=R,R"RoR tgrouptpoptinsertt subprocesstPopentPIPEt communicateRjRkR?RMRL(tbatch_file_pathRBRtSET_MENU_PASSWD_CMDtSET_MENU_PASSWD_CMD_NO_PWtSET_MENU_ADD_USER_CMDtSET_MENU_ADD_USER_CMD_NO_PWRRR2tcommandttemp_file_nametitemtmotproctoutterrtoserr((sbootadm-helper.pytbootadm_use_batch+s      %      c Cs@t|.}|j}|dks3|jdkrKttd|tS|jj}|jj}|jj }|jj }g}xU|jj D]G}y-d||jj |f} |j | Wqtk rqXqWtd|jjdj|dj|dj|dj|dj|fGHWdQXtS(s s8Boot pool operations are not applicable to root pool %s.s%s=%ssBoot pool name: %s Parameters: %s Current: %s Pending: %s Platform-specified devices excluded: %s Platform-specified (auto-added, unless excluded): %st:s, N(R t versabootR!t boot_poolR$RAR&tcurrent_membershiptpending_membershiptexcluded_devicestplatform_devicestsettable_parameterst get_paramtappendRt pool_nameRuR ( R.Rtmyvbtcur_listt pend_listt excl_listt plat_listt param_listtparamt param_str((sbootadm-helper.pytbootadm_bootpool_lists,    $c Csit|W}|j}|dks3|jdkrKttd|tSx|D]}|jddkrttd|n|jd\}}|j }|j }y|jj ||WqRt k r}ttd|j tSt k r}ttd|j tSXqRWy|jWn*ttfk r^} tt| tSXWdQXtS(s s8Boot pool operations are not applicable to root pool %s.RisInvalid parameter syntax: %ssInvalid parameter: %ssIllegal value: %sN(R RR!RR$RAR&tcountR"tlowert set_paramRtmsgRtcommitRRR?R ( R.RRRtkeyvaluetkeytvaluet param_errt param_val_errte((sbootadm-helper.pytbootadm_bootpool_set_paramss6       c Csgt|U}|j}|d ks3|jd krKttd|tSt|jj}|j |jj g}x|D]}t |dkr|ddkrd|}nt j j| rt j j|d rttd|q||krttd|q||kr|j|qqWd}xe|D]]}y|jj||d7}WqItk r}ttd ||jj|fqIXqIW|dkrtSyv|jt|jj} | j |jj | |} t | }td ||dkr&d nd fGHWn*ttfk r\} tt| tSXWd QXtS(s s8Boot pool operations are not applicable to root pool %s.iRes /dev/dsk/ts0s$Not adding %s: device does not exists)Not adding %s: device is already a memberis$Could not add %s to boot pool %s: %ssAdded %d device%s successfullytsR\N(R RR!RR$RAR&R^RtunionRtlenRKRORpRt add_deviceRRRRRR?R ( R.tdeviceRRt cur_memberstadd_listtdevRtbmzet new_memberst diff_membersR((sbootadm-helper.pytbootadm_bootpool_add_devicessT   " *      "      c Cs@t|.}|j}|d ks3|jd krKttd|tS|jj}t|jj }|j |d}x|D]}|jj}t |dkr|ddkr||krd|}n||krttd||jj fqt |dkr1ttd|q||jj |kred|GH|jj|n|jj||d7}qW|dkrtSyv|jt|jj } | j |jj|| } t | }td ||dkrd nd fGHWn*ttfk r5} tt| tSXWd QXtS( s s8Boot pool operations are not applicable to root pool %s.iRes /dev/dsk/sCCouldn't remove %s from %s: device is not a member of the boot poolis5Not allowing removal of the last boot pool device: %ss EXCLUDE: %ss!Removed %s device%s successfully.RR\N(R RR!RR$RAR&RR^RRRRRtexclude_devicet remove_deviceRRRR?R ( R.tdevicesRRRRRRt new_pend_listRRR((sbootadm-helper.pytbootadm_bootpool_remove_devicessR    .           c CsNt|d|6}|j}|dks9|jdkrQttd|tSd}g|jD]}|jra|^qa}|rt |ddd}n|dkrt |}n|sttd|tS|j}y:|j r|j n|j |d||jWn*ttfk rC}tt|tSXWdQXdS(s Rs8Boot pool operations are not applicable to root pool %s.iRQs/Could not determine default bootfs for pool "s"N(R RR!RR$RAR&RtR7RYRtsynch_membership_neededtsynch_membershiptsynch_rpool_datasetRRRR?( R.RRRtdsnametxtdefaultstbpoolR((sbootadm-helper.pyt"bootadm_bootpool_resynch_active_be<s4  %      c Cst|d|}|j}|dks9|jdkrQttd|tS|j}|jrs|jnt }t }|rx|D]t}t j |} t || } y|j| d|t}Wqttfk r} tt| t}PqXqWnJy |jdtd|t}Wn'tk rPtt| t}nX|ry|jWqtk r} |tkrtt| t}qqXn|SWdQXdS(s Rs8Boot pool operations are not applicable to root pool %s.t clear_firstN(R RR!RR$RAR&RRRzR tlibbe_pytgetzpoolbybenameRRtTrueRRR?t full_resynchR( R.tbe_listRRRRt need_committrettbetbe_rpoolRR((sbootadm-helper.pytbootadm_bootpool_resynch_bes^sJ            c Cs|jd}|d}|d}t|}|j}|dksV|jdkrw|rsttd|ntS|jj}y2td|||fGH|jj |d|Wn*t t fk r}tt |t SXWdQXtS(s Reiis8Boot pool operations are not applicable to root pool %s.s$updating files on boot pool %s:%s/%sRN(R"R RR!RR$RAR RRRRR?R&( tdatasetRtdssplitR.tbe_nameRRtbpnameR((sbootadm-helper.pytbootadm_update_bootpool_datasets(        c Cst}g}g}|r*|jd}n|rB|jd}nt|1}|jrt|jdr|jjrdG|jjGHn|dkri|dkrit|j\}}|dk rd|GHnxb|jj D]T} y:|jj | } | dk rd| t | fGHnWqt k r/qXqWxDt |jD]\} }d| |jfGHqDWnt|||}WdQX|S( s# Print the current menu on screen. Rdt config_dirs7the location of the boot loader configuration files is:R\s default %ds%s %ss%d %sN(R R"R t boot_loaderthasattrRR;RtR!tSUPPORTED_PROPStgetpropR?RR6RRt_show_entry_util( RBtinststrR~RtinstlistRRR:RDtpropnametpropvalR((sbootadm-helper.pytbootadm_list_menus6     c Cs&|dkrg}n|dkr*g}nt}t|}x|D]}yt|}|j|}Wn[tk rttd|t}qFn.t k rttd|t}qFnXt ||qFWxA|D]9}x0|jD]%}||j krt ||qqWqWWdQX|S(s( Print the specified entries on screen. s(Invalid index passed for an instance: %ss&No menu entry can be found at index %dN( R!R R RJRtR#R$RAR&RxR[RR(RBRRRRR:RDR((sbootadm-helper.pyRs4         cCsTy|jj|Wn&tk r<ttd|tSX|jj||tS(s Set a boot loader property. s%s is not a valid property(RRRR$RAR&tsetpropR (RR)R*((sbootadm-helper.pyt_bootadm_set_propertys cCsry t|}t|j|_WnKtk rHttd|tStk rmttd|tSXt S(s; Set the entry at index 'val' as the default entry to boot s:The passed value (%s) is not an integer. Integer expected.sNo entry at index: %d( RJRRtR7R#R$RAR&RxR (RR*RD((sbootadm-helper.pyt_bootadm_handle_set_defaults    cCsyt|}|j|jtksQ|j|jtksQ|j|jdkrnt|j|_t |nYt |j|j}|rt |}|rt t dtSnt t dtSWnKtk rt t d|tStk rt t d|tSXtS(s) Handles bootadm set-menu default=. sActivate failed.s The BE name provided is invalid.s:The passed value (%s) is not an integer. Integer expected.sNo entry at index: %dN(RJRtRRtBAM_BOOTENVRC_ENTRYtBAM_TRANSIENT_ENTRYRQR!RR7RRRR$RAR&R#RxR (RR*RDtbenameR((sbootadm-helper.pyt_bootadm_activate_defaults.      c sIt}|djdd}g|jD]}|jtkr*|^q*}|r|dkr|dkrx|djGHnZ|dkr|djsdn |dj}tj |IJnt t dt |t StS|dkrt t d tt |ft S|s6tjdd d d |d t}t} n\|d}t} t|dkr|d } x-| D]"|jfddtqiWn|dkrt|dkrt t dt S|ddkrt||j\} |_|_| r t Sq&||_n|dkr&||_nt|_| rE|j|ntS(Ntroot_dsReiRVitargsR\sUnknown attribute: %ss2Could not find a "%s" boot entry to retrieve "%s".tfstypetzfsR.RRics |kS(N((R(tdelinst(sbootadm-helper.pytdstallsInvalid (empty) kernel name(RR"RtRRRR!RVRWRjRR$RAR?R&R RTRURRzRtdelete_boot_instancet_handle_kernelR7tadd_boot_instance( RR)R*t active_betpoolnameRt inst_listt printargsR:tis_newtdel_listterror((Rsbootadm-helper.pyt_bootadm_handle_legacy>sT           # !    c Cst}ddg}t|}x|D]}t||\}}}|tkrVtS|dkrtt||}q(|d krt|||}q(||krt|||}q(t|||}q(W|d k r|tkrt t d q|dkrt |qnWd QX|S( s Set a menu-wide property. All properties all handled through BootConfig.boot_loader.setprop(), except 'default' which is an instance-level property and kernel= | args= which have legacy meaning (used by 'eeprom'). RVRR7sadd-usersdel-users del-superusers add-superusers auth-files:The boot loader configuration files have not been changed.N(sadd-usersdel-users del-superusers add-superusers auth-file( R R R+R&Rt_handle_password_propertyRRR!R$RAR( tproplistRBRt LEGACY_PROPSRR'RR)R*((sbootadm-helper.pytbootadm_set_menu{s*         cCst}d}d}d}i}|dkr|}|}tj|sYttddStjtjj rt j }|dkrttdqt j|sttdqt j d}||krt ||||}qttdqttd n|dkrP|}|}|rt ||||}qn_|d kr|} |}tj j| rft| d} x| D]} | jd} tj| rA| jdd} | d}tj|sttd| dS| d}t j|s*ttd| qn|ji||6qttd| qW| jnttd| x2|jD]!\} }t || ||}qWn|S(s) Handle setting the password properties. R\sadd-users5Username must contain alphanumeric '-', '_', and '.'NsCannot have empty passwords<Password must contain printable characters (ASCII 0x20-0x7E)sRe-enter password: sPassword does not matchsZUse -auth-file= to supply the password. File format is = pairs.sdel-users del-superusers add-superusers auth-fileRHs RiisEInvalid line %s. Username must contain alphanumeric '-', '_', and '.'sMInvalid line %s. Password must contain printable characters (ASCII 0x20-0x7E)s4Invalid line %s. File format is "username=password".sfile %s does not exist(sdel-users del-superusers add-superuser(R tUSERNAME_CRITERIARoR$RARKRiRjRkRlRmRnRyRORpR=R,tPASSWD_FILE_CRITERIAR"tupdatetcloset iteritems(RR)R*RtusernameRsRt temp_dictRtfileRR2t split_lineRR((sbootadm-helper.pyRsr                cCs<t}|dks|dkr^y|jj||Wq8tk rZ}tt|q8Xn|dkry|jj|Wq8tk r}tt|q8Xn|dkry|jj|Wq8tk r}ttd|t }q8Xn>|dkr|jj |n|dkr8|jj |n|S(s Set username and password. sadd-users auth-filesdel-users add-superusers2%s. Add user with the 'bootadm add-user' command.s del-superusers menu-password( R Rrtadd_userRR$R?t remove_usert add_superuserRAR&tremove_superusert set_password(RRRsRRR((sbootadm-helper.pyRys.      cCs6t||r"t|||nttddS(NsSInvalid property passed. Use bootadm help for a list of valid properties.(RtsetattrR$RA(R:R)R*((sbootadm-helper.pyt_set_instance_property scCsxt}g}g}|dkr2|dkr2dGHnB|rJ|jd}n|rb|jd}nt|||}|S(s Given an instance (or a list of comma-separated instances), either through an index (indexstr) or through titles (inststr), display the instance details. R\sNo target entry specified.Rd(R R"R(RBRR~RRR((sbootadm-helper.pytbootadm_show_entrysc st}g}g}|r*|jd}n|rB|jd}nt|xa|D]Y}|dkrt|t|dkrttdtSdtn%t|\}|tkrtSx|D] yt } j | } Wndt k r(ttdt}qn7t k r^ttd| ft}qnXdkryj j| Wqtk r} ttd | qXqd krj j| qt| qWx|D]dkrTy)jfd fd Wqtk rP} ttd | qXqd krjfd fdqjfdfdqWqXW|tkrtnWdQX|S(s Given an instance (or a list of comma separated instances), either through an index (indexstr) or through titles (inststr), set the given property (or list of space-separated properties) to it. E.g.: bootadm_change_entry(b, 'kargs="-kd -v" splashimage='boot/background.png', indexstr='2,4') will modify the kargs and splashimage parameters of instances 2 and 4 in the menu. Rds set-defaultis(Only one entry may be set as the defaultR7s5The value "%s" is not a number. A number is required.s8No menu entry can be found at index %d, cannot set %s=%ssadd-auths2%s. Add user with the 'bootadm add-user' command.sdel-authcs |jkS(N(RR(R(R:(sbootadm-helper.pyRoscsjj|S(N(Rrtadd_auth_to_instance(R(RR*(sbootadm-helper.pyRps cs |jkS(N(RR(R(R:(sbootadm-helper.pyRvscsjj|S(N(Rrtdel_auth_from_instance(R(RR*(sbootadm-helper.pyRws cs |jkS(N(RR(R(R:(sbootadm-helper.pyRzscst|S(N(R((R(R)R*(sbootadm-helper.pyR{sN(R R"R RR$RAR&RR+RJRtR#RxRrR*RR+R(tmodify_boot_instanceR( RRBRR~RRRR'RRDRR((R:RR)R*sbootadm-helper.pytbootadm_change_entry+sv                 c sgg}|dk rlt|C}|jddt}|dkr_ttdtStSWdQXn|r|jdn|r|jd}nd}t|4}x|D]}y?t |} | t |j krttd|wnWn&t k r%ttd|tSX|j | |jfd dt } || 7}qW|jfd dt} | |} | dkrttdtS| d krtd GHntd | GHt|tSWdQXtS(s Given an instance or a list of instances either through an index or a title (or a list of indexes/titles), remove the matching entries. cSstS(N(R(R((sbootadm-helper.pyRsR isNo entry removed.NRdsIgnoring invalid index: %ss(Invalid index passed for an instance: %scs |kS(N((R(tdel_bi(sbootadm-helper.pyRscs |jkS(N(RR(R(R(sbootadm-helper.pyRsis1 entry removed.s%d entries removed.(R!R R RR$RAR&R R"RJRRtR#RzR( RBt delete_allRR~RRRtretidxR:RDt retidx_temptretstrttotal((R.Rsbootadm-helper.pytbootadm_remove_entrysT              c Cstjdd|d|}t|t}|r|yt|}Wn&tk rhttd|tSX|j ||n |j |t |t SWdQXdS(sGiven a name and, optionally, a position, create a new entry in the menu with title==name and, optionally, placed at the reqested position RRR.sInvalid index passed: %sN( RTRUR!R RJR#R$RAR&R RR (t entry_nameRBt entry_post new_entryRRD((sbootadm-helper.pytbootadm_add_entrys   cCswt|dtjjtjjtjjgD}| rctjj|j j krct t dt St|WdQXdS(sV Build a new menu configuration based on the available Boot Environments. tflagssNBoot loader configuration has customizations. Use -f to force menu generation.N(R RTRgt BCF_AUTOGENtBCF_NO_LOAD_BOOT_INSTANCEStBCF_LOAD_SILENT_FAILUREtblt BootLoadertARTIFACT_BOOTLOADER_CONFIGFILESRt artifactsR$RAR&R(RBRR((sbootadm-helper.pytbootadm_generate_menus  cCs(x!|D]}|j|kr|SqWdS(s[ Given a list of boot instances, find the one that matches the specified name. N(RRR!(tbisR3R:((sbootadm-helper.pyt_find_bi_by_names c CsKt|9}|js,ttdtSytj|}||j_t|jdy.|dkrx|j }nt j |}Wn.t k r} ttdt| tSXd} |rtj} n|rittjj6} nd} |jj|d|d| d| Wn$tjk r<} t| jtSXtSWdQXdS(s` Install the bootloader to disk from either the current root or an arbitrary mountpoint.s*Unable to determine the system boot loadersNUnable to determine the list of boot devices for boot loader installation (%s)Rt verbose_filetplatdictN(R RR$RAR&RTtSolarisBootInstancetdata_source_boot_instanceRR!tget_boot_device_listR t_complete_boot_device_listRR?RjRRR=R>t PLATOPT_MBRtinstalltBootLoaderInstallErrorRR ( RRRBtsrc_pathtdevlistt write_mbrRtfake_bit target_listtbmet dest_outputREtexc((sbootadm-helper.pyR{s<      cCsbd|}tj|tjr#|Sd|d}tj|tjrJ|Sttd|dS(s: Apply expansion rules to a partial path for update_temp. s/platform/i86pc/s /amd64/unixs(Unable to derive the kernel path from %sR\(RKtaccesstR_OKR$RA(t partial_pathtnew_path((sbootadm-helper.pyt _expand_kpath&s cCsl|dkr@tjdddj}|r7|d}q_d}nt|}|s_tddfSd||fS(NtkmdbR.tunuseds -ks-ki(RTRUR!RVRYR&(t new_kernelt base_kargs((sbootadm-helper.pyR 6s     cCsqt|dt}|tkrmt|t}t|/}t||}|tkrdt|nWdQXn|S(NR(R4RR RPtBAM_TRANSIENT_SAVEFILER RR(RBRRDR((sbootadm-helper.pytbootadm_remove_transient_entryIs  c Cs |jddkrl|jdd}t|3}t||}|tkr_t|n|SWdQXnd}t}t|}t|j t }t|j t }|dkrt j ddt d|}t}nd}d} |dk r|j|_|j|_n|ddkr'|} n8|jd } | d krY|| }|| } n|}|r|dd krt|| \} }} | r| Sn||_n| dk r| |_n|rt|_t|_t||j t|j|nt|WdQXtS( Nsentry=iRiRRR.R\t-RiRe(tfindR"R RR RR!RzRCRtRRRTRURRVRWR t transientR7RGR^R ( tentrystrRBR*RRtbirct new_transientt transient_bittransient_kernelttransient_kargst kernel_endR((sbootadm-helper.pytbootadm_add_transient_entryTsZ                    cCstjtdIJttdrktjdIJtjdIx,tjD]}tjd|IqFWtjJnttdrtjdIJtjdIx,tjD]}tjd|IqWtjJndS(s- List valid properties for bootadm set-prop. s&Valid bootadm set-menu properties are:Rs GRUB Legacy:R7s%ssGRUB2:N(RjRRARR RR (R)((sbootadm-helper.pytbootadm_print_bootloader_propss     cCstjj|}yUtjj|s7tj|nt|d}|jt|tSWdQXWn(t t fk rt t dt SXdS(s9 Writes the specified UUID to the specified path sw+NsCould not set UUID(RKROtdirnameRptmakedirsR=R>R?R R@RMR$RAR&(ROtuuid_strt directorytfobj((sbootadm-helper.pytbootadm_set_uuidscCsGyt|dSWn/tk rB|r>ttd|ndSXdS(s7 Returns the UUID for the specified BE dataset sorg.opensolaris.libbe:uuids*WARNING: Could not get UUID for dataset %sN(RRR$RAR!(trootdsR((sbootadm-helper.pytbootadm_get_uuids  cCs9t}|r!|dr!|dSttddSdS(s3 Returns the UUID string for the active BE Rns!Could not get UUID from active BEN(RR$RAR!(R ((sbootadm-helper.pytbootadm_get_active_be_uuids  cCs?t|}|dkr$t}n|r7t||StSdS(s Creates /boot/solaris/BE_uuid file whose content is the value of org.opensolaris.libbe:uuid property of the root dataset. N(RsR!RtRqR&(RrRORn((sbootadm-helper.pytbootadm_create_BE_uuids     cCs|jddkrdS|jdd}yt|dittj6n}|j}|dksr|jdkrvdS|j}|j sdS|j |}| s|j |rdSWdQXWnt k rnXdS(sChecks to see if a dataset synch is required for the given root dataset. This function also implicitly checks for the existence of the boot pool. If the boot pool does NOT exist, we do NOT create it here (since this function may be called as part of the check in early boot on a systems with GIZ (Global Immutable Zone)). This is different from all other instances when we instantiate the pybootmgmt DiskBootConfig. In this function, we explicitly request that the BootPool NOT be autocreated. Returns: 0: If the boot pool exists and no synch is needed 1: If the boot pool is missing and need to be created 2: If the boot pool exists and a ds synch is needed Reiit init_argdictiN( RR"R RR tARG_NO_CREATE_BOOTPOOLRR!Rtimportedtboot_pool_cached_datasettdataset_synch_requiredR(RrR.RRRtcached_dataset_exists((sbootadm-helper.pyt!bootadm_bootpool_ds_sync_requireds&     cCstjd|IJdS(Ns bootadm: (RjR(R((sbootadm-helper.pyR$scCstddttdgddtdgddtddgddtdgddtdgddd d d d td gddd d d d dS(NRBR.s add-user=roots add-user=usersadd-user=user1sauth-file=/root/password.txtsadd-superuser=roots add-auth=userRR\R~t0s del-auth=user(RRkRR-(((sbootadm-helper.pytmain$s t__main__(pt__doc__tbootmgmt.bootconfigt bootconfigRTtbootmgmt.bootloadert bootloaderR=tlibbeRmtgettextRKtpkg.pkgsubprocesst pkgsubprocessRRt solaris.misctsolarisRjtbootmgmtRRRRRRRRRR tbootmgmt.bootutilR tbootmgmt.backend.loader.grub2R t"bootmgmt.backend.loader.legacygrubR R RRRRRRt bootmgmt.zfsRRtbootmgmt.pysolRRRRRRRnRR&R RRR^R%t translationRRAtmiscRR!R+R5R;RGRPR[RRRRRRRzRRRRRRRRRRRRyR(R)R-R4R8RARCR{RYR R_RjRkRqRsRtRuR|R$R~t__name__(((sbootadm-helper.pyt$s       @4       ` a "78"1 *$  & = ( M  X?   1   Q   .