h'dWc @sdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlmZddlmZddlmZddlmZddlmZmZdd lmZmZdd lm Z mZdd l!m"Z"dd l#m$Z$dd l%m&Z&ddl'm(Z(m)Z)ddl*m+Z+m,Z,m-Z-m.Z.ddl/j0Z0ddl1j2Z3ddl4j5j6j7j8j9j:Z;ej<ddde=jZ>dZ?dZ@dZAdZBdZCdZDe jEjFeDde0jGZHde0jGZIdZJdZKdZLe jMeLaNdZOdZPd ZQd!ZRd"ZSd#d$d%gZTd&ZUd'ZVd(ZWd)ZXd*ZYd+ZZd,Z[eeZ\da^d-Z_d.ej`fd/YZ`d0e`fd1YZad2ebfd3YZcd4edfd5YZed6ejffd7YZfejgefjhd8efjid9efjid:ejjd;e(Zkejgefjhd8efjld9efjlZmd<e"fd=YZnd>edfd?YZodd@ZpddAZqddBZrdCZsdDZtdEZudFZvdGZwdHZxdIZydJejzfdKYZ{dLZ|dMZ}dNZ~dOZdPedQdRZdPe=edQdSZedQdTZdUedfdVYZdWejfdXYZdYZeddZZd[ebfd\YZd]edfd^YZd_edfd`YZeddaZedbZedcZddZddeZdfZdgZdS(hsModule body for solaris_install package Classes, functions and variables that are globally useful to install technologies should go here. i(tprint_functionN(t namedtuple(tcontextmanager(tetree(tselect(tS_IRUSRtS_IWUSR(tfilltdedent(tsleepttime(t DataObject(t!BootmgmtUnsupportedOperationError(tSystemFirmware(tINSTALL_LOGGER_NAMEtSCRIPT_LOGGER_NAME(ttextdomain_addttextdomain_clearttextdomain_installttextdomain_removetsolaris_install_commons/usr/share/localetfallbacks/system/volatiles/tmps/var/log/installs DC specificsDC specific persistentt auto_installs ai.dtd.%ds/usr/share/install/ai.dtd.%diHssvc:/system/rad:locals .*\.dtd\.\d+$ssolaris.archive.adminssolaris.autoinstall.profilessolaris.autoinstall.manifestssolaris.autoinstall.clientssolaris.autoinstall.servicetkeytcerttca_certs client.crts client.keys server.ca.crts manifest.xmls /usr/bin/curls /var/ai/ssls/var/install/sslcCs/tdkr+ddlm}|dantS(s,Get a reference to libc, only load if neededi(tCDLLslibc.soN(t_libctNonetctypesR(R((s __init__.pytget_libc_ctypess tCalledProcessErrorcBs#eZdZddZdZRS(sExpansion of subprocess.CalledProcessError that may optionally store a reference to the Popen object that caused the error. cCs&tt|j||||_dS(N(tsuperRt__init__tpopen(tselft returncodetcmdR"((s __init__.pyR!scCsRd|j|jf}|jrN|jjrN|jjrN|d|jj7}n|S(Ns/Command '%s' returned unexpected exit status %ss (R%R$R"tstderrtstderr_in_exstr(R#terrstr((s __init__.pyt__str__s !N(t__name__t __module__t__doc__RR!R)(((s __init__.pyRs tStderrCalledProcessErrorcBseZdZdZRS(s'A subprocess generated output to stderrcCs d|jS(Ns#Command '%s' generated error output(R%(R#((s __init__.pyR)s(R*R+R,R)(((s __init__.pyR-stUnauthorizedUserErrorcBs eZdZdZdZRS(sPException raised when the user does not have a specified authorization. cCs ||_dS(N(tvalue(R#tmsg((s __init__.pyR!scCs|jS(N(R/(R#((s __init__.pyR)s(R*R+R,R!R)(((s __init__.pyR.s t _LogBuffercBs,eZdZdZedZdZRS(stClass that reads from a filehandle (given by fileno), buffers the output and dumps to a logger on newlines cCs:||_||_||_||_g|_g|_dS(sfileno - File number of the file handle to read from logger - The logger to log to loglevel - The level at which to log bufsize - How much to try and read at any given time N(tfilenotloggertlogleveltbufsizet_buffert_all(R#R2R3R4R5((s __init__.pyR!s      cCstj|j|j}d|ks*|r|rG|dd}}}n|jd\}}}|jj|dj|j}|j}|r|j j |j |n|j j ||f|g|_n|jj|dS(sRead pending output from the filehandle, and store it in the internal buffer. If the output contains a newline, or flush=True, then flush the internal buffer to the logger s tN(tostreadR2R5t rpartitionR6tappendtjointstripR3tlogR4R7textend(R#tflushtoutputtend_buftnewlinet begin_buft flush_outtlog_out((s __init__.pytread_filehandles cCs |jdtdj|jS(sReturn all the output retrievedRAR8(RHtTrueR=R7(R#((s __init__.pyt all_outputs(R*R+R,R!tFalseRHRJ(((s __init__.pyR1s  !tPopencBseZdZejZejZeZeZeZ eZ dZ dZ ddddddeeddeddedZeddddddeeddeddddejejedZdZRS(sEnhanced version of subprocess.Popen with functionality commonly used by install technologies. Functionality that requires blocking until the subprocess completes is contained within the check_call classmethod, which is similar to subprocess.check_call. === Usage examples === The below examples all assume the command to be run is stored in a list named 'cmd', e.g., cmd = ['/usr/bin/ls', '-l', '/tmp'] * Run a command, raising an exception for non-zero return >>> Popen.check_call(cmd) * Run a command, saving all stdout and stderr output >>> ls = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE) >>> print ls.stdout srwxrwxrwx 1 root root 0 2011-02-14 09:14 dbus-zObU7eocIA * Run a command, logging stderr and ignoring stdout >>> mylogger = logging.getLogger('MyLogger') >>> ls = Popen.check_call(cmd, stdout=Popen.DEVNULL, stderr=Popen.STORE, logger=mylogger) * Run a command, logging stderr at the logging.INFO level >>> ls = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE, logger="MyLogger", stderr_loglevel=logging.INFO) * Run a command, triggering an exception if the returncode is anything EXCEPT '4' or '-1' >>> Popen.check_call(cmd, check_result=(-1, 4)) * Run a command, and trigger an exception if it printed anything to stderr >>> Popen.check_call(cmd, stderr=Popen.PIPE, check_result=(Popen.STDERR_EMPTY,)) * Run a command, storing stdout, and ignoring the returncode >>> ls = Popen.check_call(cmd, stdout=Popen.STORE, check_result=Popen.ANY) ii cCs|tjkr$ttjd}n|tjkrHttjd}n|tjkrlttjd}n||_tt|j|d|d|d|d|d|d|d |d | d | d | d | d| d| dS(Nsw+sr+R5t executabletstdintstdoutR&t preexec_fnt close_fdstshelltcwdtenvtuniversal_newlinest startupinfot creationflags(RLtDEVNULLtopenR9tdevnullR'R R!(R#targsR5RMRNROR&RPRQRRRSRTRURVRWR'((s __init__.pyR!"s    cCs |dkrtj}n|tjkr3tj}n|tjkrNtj}n|dk r|tjk r|tjk rtdnt|trtj |}n|j |r|j |d|qn||d|d|d|d|d|d|d |d | d | d | d | d| d|d|}|dkr]|j }|\|_ |_nB|dkrr|}n tj}|j||||\|_ |_|tjkr|S|j|krt|j||n|jr |j|kr t|j||n|S(ssolaris_install.Popen.check_call is interface compatible with subprocess.check_call, accepting all the same positional/keyword arguments. solaris_install.Popen.check_call will store the output from stdout and stderr if they are set to Popen.STORE. Note that Popen.stdout and Popen.stderr are replaced with a string - references to filehandles won't be preserved in the manner that a standard use of the Popen class allows. logger: If given, the stdout and stderr output from the subprocess will be logged to this logger. (This parameter also accepts a string, which will be passed to logging.getLogger() to retrieve an appropriate logger). One or both of stdout/stderr must be set to Popen.PIPE or Popen.STORE for this functionality to work (a ValueError is raised if that is not the case). See also stdout_loglevel and stderr_loglevel stdout_loglevel and stderr_loglevel: If the stdout/stderr output from the subprocess are logged as a result of logger being set, the output will be logged at the specified log level. Defaults are: stdout_loglevel: logging.DEBUG stderr_loglevel: logging.ERROR check_result: If specified, should be an iterable of all "acceptable" values for the return code of the process. If the subprocess' return code is not one of the given values, then a CalledProcessError will be raised upon command completion. In addition to integer values, the special value solaris_install.Popen.STDERR_EMPTY may be included; if it is, then the subprocess will be considered to have exited unsuccessfully (and a CalledProcessError raised) if there was any output to stderr. Note that stderr must be set to Popen.STORE for this to be successful. By default, any non-zero returncodes are considered errors. Setting check_result=Popen.ANY causes this function to mimic subprocess.call (that is, the returncode will be ignored and the caller is expected to ensure that appropriate behavior occurred) sR'logger' argument requires one or both of stdout/stderr to be set to PIPE or STOREs Executing: %sR5RMRNROR&RPRQRRRSRTRURVRWR'iN(RRLtSUCCESStSTOREtPIPEt ValueErrort isinstancet basestringtloggingt getLoggert isEnabledForR?t communicateROR&t LOG_BUFSIZEt_logtANYR$Rt STDERR_EMPTYR-(tclsR[R5RMRNROR&RPRQRRRSRTRURVRWt check_resultR3tstdout_logleveltstderr_loglevelR'R"RBt log_bufsize((s __init__.pyt check_call;sL/               c CsHg}|jrFt|jj|||}|j|jjnd}|jrt|jj|||}|j|jjnd}xs|jdkrt|ggdd}|r|j|kr|jn|r|j|kr|jqqW|r|j } nd} |r8|j } nd} | | fS(sPoll the stdout/stderr pipes for output, occasionally dumping that output to the log. While the subprocess is running, the filehandles are checked (using select) for any pending output. The output is stored in memory, until a newline is found, at which point it's passed to the logger. (see _LogBuffer class, above) Additionally, all output is stored. This function returns a tuple of (stdout, stderr), like Popen.communicate() g?iN( ROR1R2R<RR&tpollRRHRJ( R#R3R5RlRmt select_fromtstdout_logbuffertstderr_logbuffertreadyROR&((s __init__.pyRgs0      (iN(R*R+R,t subprocessR^tSTDOUTtobjectR]RXRhRiR\RfRRKRIR!t classmethodRbtDEBUGtERRORRoRg(((s __init__.pyRLs.'              _ROR&RmR3tApplicationDatacBseZdZdd edZedZedZedZ edZ dZ e dZ e d ZRS( sApplication Data class Provides a location for CUD applications to store application specific data that checkpoints, etc. may require access to. Currently stores: - Application Name - Work Directory, defaulting to /system/volatile s/system/volatile/cCsJtt|j|t|_||_||_||_||_dS(N( R R{R!tdictt data_dictt_application_namet _live_installt_lognamet _work_dir(R#tapplication_nametwork_dirtlognamet live_install((s __init__.pyR!s     cCs|jS(s2Read-only Application Name - set at initialisation(R~(R#((s __init__.pyRscCs|jS(s0Read-only Work Directory - set at initialisation(R(R#((s __init__.pyRscCstjj|j|jS(s)Read-only logname - set at initialization(R9tpathR=RR(R#((s __init__.pyRscCs|jS(s.Read-only Live Install - set at initialization(R(R#((s __init__.pyRscCsdS(N(R(R#((s __init__.pytto_xmlscCstS(N(RK(Rjtelement((s __init__.pyt can_handle scCsdS(N(R(RjR((s __init__.pytfrom_xmlsN(R*R+R,RRKR!tpropertyRRRRRRxRR(((s __init__.pyR{s   t SetUIDasEUIDcBs eZdZdZdZRS(sm SetUIDasEUID - context manager for running section of code with the uid set as the user's euid. cCs2tj|_tj|_tj|jdS(s set the uid as euid N(R9tgeteuidteuidtgetuidtruidtsetuid(R#((s __init__.pyt __enter__scGstj|j|jdS(s reset the uid and euid N(R9tsetreuidRR(R#texc_info((s __init__.pyt__exit__s(R*R+R,RR(((s __init__.pyRs cCsat}t#tjttjs.t}nWdQX|dk rYtjjj ||gS|SdS(s Return System Temporary Directory, with filename string appended SYSTEM_TEMP_DIR or USER_TEMP_DIR is returned if no filename is passed in. N( tSYSTEM_TEMP_DIRRR9taccesstW_OKt USER_TEMP_DIRRRtsepR=(tfilenamet temp_path((s __init__.pytsystem_temp_path#s  cCs-|dk r%tjjjt|gStSdS(s> Return Post-Install Logs Directory, with file string appendedN(RR9RRR=tPOST_INSTALL_LOGS_DIR(tfile((s __init__.pytpost_install_logs_path4s cCs|dkr|dkrEtjdtdt}tj||}nxTtD]I}x@g|jd|D] }|^qhD]}|jdk rxtSqxWqLWntS(s9 Returns True or False if the file contains security datatxmltremove_blank_texttdtd_validationttagN( RRt XMLParserRIRKtparsetSECURITY_XML_TAGStiterttext(Rt file_typetxml_treetparserRttttmp((s __init__.pytcheck_file_for_security_data=s    ,cCsyFtjj|r8tjj| r8tj|n tj|Wn:ttfk r}t |ddt j krqnXdS(s<Delete either a file, a link, or directory and it's sub-treeterrnoN( R9RtisdirtislinktshutiltrmtreetremovetIOErrortOSErrortgetattrRRtENOENT(Rterr((s __init__.pyt force_deleteMs%cCstj|dk S(s.Check if a given path matches the RE for a DTDN(t__dtd_path_regexptmatchR(R((s __init__.pytpath_matches_dtdYscCsktjdtjd}|dkr>d}||d|Sddd g}tj|d tjd tj}|jjd\}}t|}|jd ks|j d kr|d:}n|jdks|j dkr|d9}nn|jdks|j dkr&|d9}n=|jdkrc|j dkrct t d|n|SdS(sfReturns the amount of memory available in the system in MB Basically just as prtconf does. t SC_PAGESIZEt SC_PHYS_PAGESiiiis/bin/shs-es6/usr/sbin/prtconf -vp | /usr/bin/grep '^Memory size: 'ROR&t Kilobytestkbit Gigabytestgbt Terabytesttbt MegabytestmbsUnknown memory size units: %sNii( R9tsysconfRLRoR]ROtsplittlongt capitalizetlowerR_t_(tmemoryRR%tprtconftmem_sizetmem_unit((s __init__.pytget_system_memory`s$   ! $ $ $ $cCsltjdkrdt}ttdr`tj}y|jtj}Wq`tk r\q`Xn|St SdS(s; Check to see if the system supports GPT labeled boot diskstsparctPROP_GPT_SUPPORTEDN( tplatformt processorRKthasattrR tgettgetpropRR RI(t gpt_capabletfirmware((s __init__.pytgpt_firmware_checks  cCsAt}|dk r=|r=|r=|j||dkr=tStS(s!Wrapper around libc's chkauthattriN(RRt chkauthattrRIRK(tusertauthtlibc((s __init__.pytcheck_user_auths  cCsltjtjd}t||sAttd|ntjdkrhttdndS(s Checks whether the user has the specified authorization and euid as 0. Raises UnauthorizedUserError if euid is not 0 or user doesn't have authorization. iseInsufficient permissions to perform operation. Authorization <%s> required to perform this operation.s^Insufficient permission to perform operation. euid required to be 0 to perform this operation.N(tpwdtgetpwuidR9RRR.RR(RR((s __init__.pytcheck_auth_and_euids  cCs.ytj|tSWntk r)tSXdS(s% Checks the log level being passed inN(Rbt getLevelNameRIt NameErrorRK(tlevel((s __init__.pytcheck_log_levels   tRunableProcesscBs>eZdZdZdZedZedZRS(s] subclass of Process to include a Queue to hold the result of the decorated function cOsKtjdd|_|f|}tjj|d|jd|d|dS(NtmaxsizeittargetR[tkwargs(tmultiprocessingtQueuetqueuetProcessR!trun_func(R#tfuncR[R((s __init__.pyR!s cOsMy#|||}|jj|Wn#tk rH}|jj|nXdS(s\ Process target method for controlling execution of the decorated function. N(Rtputt Exception(R#RR[RtresultR((s __init__.pyRs cCs |jjS(N(Rtfull(R#((s __init__.pytdonescCs |jjS(N(RR(R#((s __init__.pyRs(R*R+R,R!RRRR(((s __init__.pyRs  cs"tjfd}|S(s/ function decorator to run a function in a separate multiprocessing Process object. usage: @run_async myfunction(*args, **kwargs) <....> myfunction_proc = myfunction(*args, **kwargs) while not myfunction_proc.done: block result = myfunction_proc.result cs t||}|j|S(N(Rtstart(R[Rtproc(tfunction(s __init__.pytasync_functions (t functoolstwraps(RR((Rs __init__.pyt run_asyncscCstjjdrtStS(sKReturns True if an .install_env file is found. Returns False otherwise.s /.install_env(R9RtisfileRIRK(((s __init__.pytis_install_envscCstt|dtddS(Ntreplace_whitespacetwidthiF(RRRK(R((s __init__.pytscCs djtt|jdS(s! Generic textwrapper for use with installadm. Source modules can use this utility to ensure appropriate formatting for the CLI's output when printing longer-than-70-character strings. Note that the wrap width is not dynamic, it is hardcoded at 70 characters. The argument 'text' is processed into a list of strings and returned as a rejoined string. The text is first dedented, which removes any leading whitespace (as might be seen with a block-quoted string), and it is then line-wrapped at 70 characters. s (R=tmapt _text_wrapt splitlines(R((s __init__.pytcli_wrap s s icCs}t|}|r*t|jd}n|ridjg|jD]}d|t|^qC}nt|d|dS(sUtility method for printing text to stdout Params: - text. Text to output. If not a string it will be converted to one. - end. Line terminator. If text does not have a terminating ' ' and end='', then the cursor will remain at the end of the line. Defaults to ' '. - wrap. If True, wrap the output using cli_wrap(). Defaults to False. - indent. Number of spaces to indent text by. Deafults to 0. s t tendN(tstrRtrstripR=Rtprint(RR twraptindenttline((s __init__.pyttext_outs  0cCst|}|r*t|jd}n|ridjg|jD]}d|t|^qC}n|rtdd|dtjnt|d|dtj|rtdd|dtjndS(s.Utility method for printing text to stderr Params: - text. Text to output. If not a string it will be converted to one. - end. Line terminator. If text does not have a terminating ' ' and end='', then the cursor will remain at the end of the line. Defaults to ' '. - wrap. If True, wrap the output using cli_wrap(). Defaults to False. - add_blanks. If True, add blank lines before and after text. Defaults to False. - indent. Number of spaces to indent text by. Deafults to 0. s R R8R RN(R RR R=RR tsysR&(RR Rt add_blanksRR((s __init__.pyt error_out0s  0c CsrtjjstStd}td}td}td}||g}||dg}d|j|f} t|ts|g}n|j} t | j r| j ddkr| j d | } nxtrmx$|D]} t | d |d |qWyt | j j} Wn"ttfk rIt dtSX| |krZtS| |krtSqWd S( sjPrompt user for yes or no response. Output the message(s) passed in prompt_list. If the last message ends in '?' or ':', insert (localized version of) '[y|N]: ' before end. Catches CTRL-C,CTRL-D terminal interrupt and returns False. Note for localization: the colon should be maintained across translations Params: - prompt_list. List of messages to print before accepting input. If a single item is passed, it will be converted to a list. - wrap, indent. Passed to text_out to format output. Returns: True if yes, False if no (default) tNOtNtYEStYR8s [%s|%s]: is?:s :RRN(RRNtisattyRIRRR`tlisttpoptlenR Rt raw_inputR>tuppertKeyboardInterrupttEOFErrorRK( t prompt_listRRt response_notresponse_no_single_lettert response_yestresponse_yes_single_lettert affirmativetnegativetoptt last_prompttprompttans((s __init__.pyt ask_yes_or_noMs8         (     tSpinnercBs)eZdZdZdZdZRS(s Iterator which provides the set of characters needed for a generic status 'spinner' upon each iteration. Example: for c in Spinner(): sys.stdout.write(c) sys.stdout.flush() sleep(0.2) sys.stdout.write('') cCsd|_d|_dS(Nis/-\|(tindextchars(R#((s __init__.pyR!s cCs|S(N((R#((s __init__.pyt__iter__scCsG|j|j}|jd7_|jt|jkrCd|_n|S(Nii(R/R.R(R#tc((s __init__.pytnexts  (R*R+R,R!R0R2(((s __init__.pyR-s   t SpinnerThreadcBs2eZdZdZdZdZdZRS(sa Killable subclass of the threading module's Thread class. To be used in other contexts to run a "spinner" on the command line as a means of indicating ongoing work. Provides method 'kill' so that a calling context may terminate execution. The thread still needs to be joined as normal. Example: try: spin_t = SpinnerThread() spin_t.start() except: raise RuntimeError("failed to create thread") try: # Some work which may take some time... finally: spin_t.kill() spin_t.join() cCs2tt|jtj|_t|_dS(N(R R3R!t threadingtEventt_killR-tspinner(R#((s __init__.pyR!scCslxe|jD]Z}tjj|tjjtdtjjdtjj|jr dSq WdS(Ng?s(R7RROtwriteRAR tkilled(R#R1((s __init__.pytruns    cCs|jjdS(N(R6tset(R#((s __init__.pytkillscCs |jjS(N(R6tisSet(R#((s __init__.pyR9s(R*R+R,R!R:R<R9(((s __init__.pyR3s   cs"tjfd}|S(sR Decorator which runs 'function' while printing a text spinner to stdout. csZyt}|jWntdnXz||SWd|j|jXdS(Nsfailed to create spinner thread(R3Rt RuntimeErrorR<R=(R[Rtspin_t(R(s __init__.pyt spun_functions  (RR(RR@((Rs __init__.pyt with_spinners ccs|dkr+tdttj}ntjj|r}t|d}|jd}WdQXt t d|nVt|d}|j ttj|j z dVWd|j tj|XdS(s1 Context manager which can be used as a file-based execution lock. The path passed as 'lockfile' argument may be used to derive intent, as it's a generic lock. If the lock is not already instanced, 'lockfile' is created and the lock is yielded back to the calling context. If the lock is held elsewhere, the PID of the process which holds it is returned in a SystemExit exception, which can be caught and handled differently if an exit is not desired. lockfile optional path to lockfile, a generic is used by default slock.%striNsoperation running, process '%s'tw(RRR R9tgetpidRtexistsRYR:t SystemExitRR8RAtclosetunlink(tlockfiletfdt running_pid((s __init__.pyt exec_locks    t LockfileErrorcBseZdZRS(sZ LockfileError - Exception raised when the Lockfile is unable to acquire a lock. (R*R+R,(((s __init__.pyRMstLockfilecBs;eZdZddddZdZdZdZRS(s Lockfile - Context manager for creating a lockfile to prevent multiple processes from accessing a concurrently sensitive area of code at the same time. Raises a LockfileError if unable to acquire a lock. g?cCs[||_||_||_||_d|_|jdkrW|jdkrWd|_ndS(s lockfile - Path of the lockfile tries (optional) - Number of attempts to grab a lock. None indicates infinite number of tries. (tries is set to 1 if both tries and timeout are not specified.) timeout (optional) - Maximum time in seconds allowed to try and get a lock. None indicates that there is no timeout. time_between_tries (optional) - The amount of time in seconds to wait between attempts to acquire a lock. iN(RIttriesttimeoutttime_between_triesRtlock_fd(R#RIRORPRQ((s __init__.pyR!s     cCst}d}x||jp!dkry7t|jd|_tj|jtjtjBPWn.t k r}|j t j kr|qnX|j rt||j kr|j qn|jr|d7}nt|jqW|j dS(s Try "tries" times to acquire a lock. If timeout expires before this, or if the number of tries is met, the lock fails, and a LockfileError is raised. iiRCN(R RORYRIRRtfcntltflocktLOCK_EXtLOCK_NBRRtEAGAINRPtexpireR RQ(R#t start_timeROte((s __init__.pyR+s"     cGs!|jjtj|jdS(s Removes the lockfile N(RRRGR9RRI(R#R((s __init__.pyRPs cCstd|jdS(s{ Raises a LockfileError when all attempts to get a lock within the timeout and maximum tries have failed. s?Could not obtain lock at %s. Already in use by another process.N(RMRI(R#((s __init__.pyRXUsN(R*R+R,RR!RRRX(((s __init__.pyRN s   % t RadConnectioncBsAeZdZdZdZddZdZedZ RS(sRadConnection class provides rad connection. It is implemented as singleton so that there is only 1 RAD connection. cCs.t|j|s'tj||_n|jS(N(R`t _instanceRwt__new__(Rj((s __init__.pyR]fscCs(t|dsd|_n||_dS(Nt _connection(RRR^R3(R#R3((s __init__.pyR!ks cCs&|jr"|jjd|_ndS(s close the connection N(R^RGR(R#((s __init__.pyt__del__ps  cCsd}xt|D]}y5|js7tj|_n|jjtjWnHtk r}|jdk r|jj dnd|_t dqX|jSqWtt dit d6t|d6dS(s Connect to rad daemon using connect_unix(). If connection exist, it will verify connection by querying an object in SMF RAD module. Raise IOError if connection failsis5Failed to connect to RAD daemon. Retrying connection is,Failed to connect to SMF %(rad)s : %(error)stradterrorN(trangeR^tradcont connect_unixt get_objecttsmfbtMasterRR3RtdebugR Rt RAD_SVC_FMRIR (R#tnum_of_retriestiRa((s __init__.pyt connectionvs    N( R*R+R,RR\R]R!R_RRl(((s __init__.pyR[^s    ccsFtj}z%|dk r+tj|ndVWdtj|XdS(s Context manager which can be used to execute a block of code while the current working directory is changed to the specified dirname. N(R9tgetcwdRtchdir(tdirnameRS((s __init__.pyRns    cCsd}tjjtrtjjtt}tjj|rP|d|7}ntjjtt}tjj|r|d|7}ntjjtt}tjj|r|d|7}q|r|d7}qn|S(sxBuild the options that curl will use. allow_insecure - True for PXE installs with security policy=encr-only R8s --cert %ss --key %ss --cacert %ss --insecure(R9RREt AI_SSL_DIRR=t CLIENT_CRTt CLIENT_KEYt SERVER_CA_CRT(tallow_insecuretoptionsRRR((s __init__.pytbuild_curl_optionssc Cs|jd|tjdddd\}}tj|tdtd|||f}|jd||j}y#tj |d tj d tj Wn t k r}d } d } t } td td|||f}|j}x| | kru| ru|j dtd |j d|y)tj |d tj d tj t} Wnt k rg}nX| d7} qW| stj||jd|t |qnX|jdtjj|} tjj| stj| ntj||tj|dtdS(sQDownload the file specified in the URL to a specified local location. sPlanning to download: tdirs/system/volatiletprefixtdownloads %s -f -L --max-time 60 -o %s %sRtsPopen command line: ROR&i is% %s -f -L -C - --max-time 60 -o %s %ss"Download resuming in 10 seconds...sResuming download of %sisUnable to download %ssDownload completed!!t ignore_errorsN(RhttempfiletmkstempR9RGtCURLRvRRLRoR]RRKtinfoR RIRRaRRoREtmakedirsRtmoveR( turltdstR3RttfdescRBtcmd_strR%RROtcountt downloadedtdst_dir((s __init__.pytdownload_filessJ  #      cCstj|tj}tj|}tj|}|j|jksW|j|jkrwtj|td|ntj ||tj|dS(ssecure_chmod(name, perm) -> None securely change the permissions on a file. Raises ValueError - when the file changes before the permissions are set. OSError - if the file can not be accessed. sfile %s changedN( R9RYtO_RDONLYtfstattlstattst_inotst_devRGR_tfchmod(tnametpermRRR((s __init__.pyt secure_chmods $ cCstj|tj}tj|}tj|}|j|jksW|j|jkrwtj|td|ntj |||tj|dS(s/secure_chown(name, uid, gid=-1) -> None securely change the ownership of a file. If gid is not passed in then the group ownership of the file does not change. Raises ValueError - when the file changes before the ownership is set. OSError - if the file can not be accessed. sfile %s changedN( R9RYRRRRRRGR_tfchown(RtuidtgidRRR((s __init__.pyt secure_chown s $ cCs<||krdS||gt||gdtkr8dSdS(s natural sort compare function intended to be passed to "sorted" as cmp argument. Performs "natural sort", rather than ascii sort so that numbers in strings are sorted as numbers. iRii(tsortedt_natural_sort_key(titem1titem2((s __init__.pytnatural_sort_cmp"s  $cCs;gtjd|D]$}|jr1t|n|^qS(s natural_sort key to be passed to sorted's "key'" argument. Turns a string into a list of string and number chunks e.g., "c78at" -> ["c", 78, "at"] s(\d+)(treRtisdigittint(tastringts((s __init__.pyR.s(R,t __future__RRRSRtgettextRbRR9RRRRRuRR4R{t collectionsRt contextlibRtlxmlRRtstatRRttextwrapRRR R tsolaris_install.data_objectR tbootmgmtR tbootmgmt.bootinfoR tsolaris_install.loggerRRtsolaris_install.translateRRRRtsolaris_install.versiontversiont rad.connecttconnectRct)rad.bindings.com.oracle.solaris.rad.smf_1tbindingstcomtoracletsolarisR`tsmf_1Rft translationRIRRRRtDC_LABELt DC_PERS_LABELtIMG_AI_MANIFEST_PATHRR=tDTD_VERSION_AItIMG_AI_MANIFEST_DTDtSYS_AI_MANIFEST_DTDtPKG5_API_VERSIONRit DTD_PATH_REtcompileRtARCHIVE_ADMIN_AUTHt PROFILE_AUTHt MANIFEST_AUTHt CLIENT_AUTHt SERVICE_AUTHRRqRrRstAI_MANIFEST_ATTACHMENT_NAMER}RptINSTALL_SSL_DIRt PERM_OWNER_RWRRRRR-RR.RwR1RLtpartialRoR]RyR:RXt run_silentR{RRRRRRRRRRRRRRRRRRKRRR,R-tThreadR3RARLRMRNR[RnRvRRRRR(((s __init__.pyts               "      ;  6    )   !   ;, R7 4