grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026a d�td/?ã@stdZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl Z e   ¡Z Gdd„de ƒZGdd„deƒZGdd „d eƒZGd d „d eƒZd d „Zdd„Zdd„Zdd„Zdd„ZeZdd„Zdd„ZeZdd„Zdd„Zdd„Zd d!„Zd"d#„Zd$d%„Z d&d'„Z!d(d)„Z"d*d+„Z#d,d-„Z$e d.d/„ƒZ%da  Provides various utility functions. This file is part of RTSLib. Copyright (c) 2011-2013 by Datera, Inc Copyright (c) 2011-2014 by Red Hat, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. éN)Úcontextmanagerc@seZdZdZdS)Ú RTSLibErrorz Generic rtslib error. N©Ú__name__Ú __module__Ú __qualname__Ú__doc__©r r ú0/usr/lib/python3.9/site-packages/rtslib/utils.pyr"src@seZdZdZdS)ÚRTSLibALUANotSupportedz( Backend does not support ALUA. Nrr r r r r (sr c@seZdZdZdS)ÚRTSLibBrokenLinkzC Broken link in configfs, i.e. missing LUN storage object. Nrr r r r r .sr c@seZdZdZdS)ÚRTSLibNotInCFSzß The underlying configfs object does not exist. Happens when calling methods of an object that is instantiated but have been deleted from congifs, or when trying to lookup an object that does not exist. Nrr r r r r 4sr cCs<t|dƒ�}| t|ƒ¡Wdƒn1s.0YdS)a” This function writes a string to a file, and takes care of opening it and closing it. If the file does not exist, it will be created. >>> from rtslib.utils import * >>> fwrite("/tmp/test", "hello") >>> fread("/tmp/test") 'hello' @param path: The file to write to. @type path: string @param string: The string to write to the file. @type string: string ÚwN)ÚopenÚwriteÚstr)ÚpathÚstringÚfile_fdr r r Úfwrite=s rcCs:t|dƒ�}| ¡ ¡WdƒS1s,0YdS)a  This function reads the contents of a file. It takes care of opening and closing it. >>> from rtslib.utils import * >>> fwrite("/tmp/test", "hello") >>> fread("/tmp/test") 'hello' >>> fread("/tmp/notexistingfile") # doctest: +ELLIPSIS Traceback (most recent call last): ... IOError: [Errno 2] No such file or directory: '/tmp/notexistingfile' @param path: The path to the file to read from. @type path: string @return: A string containing the file's contents. ÚrN)rÚreadÚstrip)rrr r r ÚfreadQs rcCs„tj t|ƒ¡}zLtj t|¡}|jdkrFt  |tj tj Btj B¡}nt  |tj tj B¡}Wnt ypYdS0t |¡dSdS)a< This function will check if the device or file referenced by path is already mounted or used as a storage object backend. It works by trying to open the path with O_EXCL flag, which will fail if someone else already did. Note that the file is closed before the function returns, so this does not guaranteed the device will still be available after the check. @param path: path to the file of device to check @type path: string @return: A boolean, True is we cannot get exclusive descriptor on the path, False if we can. Z scsi_genericTFN)ÚosrÚrealpathrÚpyudevÚDeviceÚfrom_device_fileÚ_CONTEXTÚ subsystemrÚO_EXCLÚO_NDELAYÚO_RDWRÚOSErrorÚclose)rÚdevicerr r r Ú is_dev_in_usegs    r'c Csz|j}z| d¡}Wntttfy.YdS0|ddkrD|jj}z| d¡}WntttfylYdS0|d|S)zŒ @param device: the device @type device: pyudev.Device @return: the size in logical blocks, 0 if none found @rtype: int ÚsizerZDEVTYPEÚ partitionzqueue/logical_block_sizei)Ú attributesÚasintÚKeyErrorÚUnicodeDecodeErrorÚ ValueErrorÚparent)r&r*Z sect_sizeZlogical_block_sizer r r Ú_get_size_for_dev€s r0cCs"tj ttj t|ƒ¡¡}t|ƒS)zþ @param path: The path to a block device @type path: string @return: The size in logical blocks of the device @raises: DeviceNotFoundError if corresponding device not found @raises: EnvironmentError, ValueError in some situations ) rrrrrrrrr0)rr&r r r Úget_size_for_blk_dev—sr1cCsŠdd„}| dd¡}z ||ƒWStjy„t d|¡}|r~| ¡d}|ddkrn|d  ¡rn|d d…}|| ¡ƒYS‚Yn0d S) zÄ @param name: a kernel disk name, as found in /proc/partitions @type name: string @return: The size in logical blocks of a disk-type block device. @raises: DeviceNotFoundError cSstj td|¡}t|ƒS)zp :param str name: name of block device :raises DeviceNotFoundError: if device not found Úblock)rrÚ from_namerr0)Únamer&r r r Úget_size­sz(get_size_for_disk_name..get_sizeú/ú!z^([a-z0-9_\-!]+?)(\d+)$réÿÿÿÿÚpéþÿÿÿN)ÚreplacerÚDeviceNotFoundErrorÚreÚsearchÚgroupsÚisdigitÚgroup)r4r5ÚmZdiskr r r Úget_size_for_disk_name¤s      rCc Cstztj t|¡}Wntjttfy.YdS0|jdkr>dS|j}d}z|  d¡}Wnt t tfynYn0|S)a÷ This function returns a block device's type. Example: 0 is TYPE_DISK If no match is found, None is returned. >>> from rtslib.utils import * >>> get_blockdev_type("/dev/sda") 0 >>> get_blockdev_type("/dev/sr0") 5 >>> get_blockdev_type("/dev/scd0") 5 >>> get_blockdev_type("/dev/nodevicehere") is None True @param path: path to the block device @type path: string @return: An int for the block device type, or None if not a block device. Nr2rz device/type) rrrrr<ÚEnvironmentErrorr.r r*r+r,r-)rr&r*Z disk_typer r r Úget_blockdev_typeÉs rEcCsXz>tj |¡}tj t|¡}|jdd�}dd„|j  d¡DƒWSt dƒ‚Yn0dS)a9 This function returns the SCSI ID in H:C:T:L form for the block device being mapped to the udev path specified. If no match is found, None is returned. >>> import rtslib.utils as utils >>> utils.convert_scsi_path_to_hctl('/dev/scd0') (2, 0, 0, 0) >>> utils.convert_scsi_path_to_hctl('/dev/sr0') (2, 0, 0, 0) >>> utils.convert_scsi_path_to_hctl('/dev/sda') (3, 0, 0, 0) >>> utils.convert_scsi_path_to_hctl('/dev/sda1') >>> utils.convert_scsi_path_to_hctl('/dev/sdb') (3, 0, 1, 0) >>> utils.convert_scsi_path_to_hctl('/dev/sdc') (3, 0, 2, 0) @param path: The udev path to the SCSI block device. @type path: string @return: An (host, controller, target, lun) tuple of integer values representing the SCSI ID of the device, or raise RTSLibError. Úscsi)r cSsg|] }t|ƒ‘qSr )Úint)Ú.0Údatar r r Ú óz-convert_scsi_path_to_hctl..ú:z#Could not convert scsi path to hctlN) rrrrrrrZ find_parentZsys_nameÚsplitr)rr&r/r r r Úconvert_scsi_path_to_hctlðs  rNcCsÊz$t|ƒ}t|ƒ}t|ƒ}t|ƒ}Wnty>tdƒ‚Yn0t|ƒt|ƒt|ƒt|ƒg}ztj tdd |¡¡}Wntj y’tdƒ‚Yn0tj d|d�}t dd„|Dƒd ƒ}|d krÆtdƒ‚|S) aÑ This function returns a udev path pointing to the block device being mapped to the SCSI device that has the provided H:C:T:L. >>> import rtslib.utils as utils >>> utils.convert_scsi_hctl_to_path(0,0,0,0) '' >>> utils.convert_scsi_hctl_to_path(2,0,0,0) # doctest: +ELLIPSIS '/dev/s...0' >>> utils.convert_scsi_hctl_to_path(3,0,2,0) '/dev/sdc' @param host: The SCSI host id. @type host: int @param controller: The SCSI controller id. @type controller: int @param target: The SCSI target id. @type target: int @param lun: The SCSI Logical Unit Number. @type lun: int @return: A string for the canonical path to the device, or raise RTSLibError. z?The host, controller, target and lun parameter must be integersrFrLz!Could not find path for SCSI hctlr2)r r/css|] }|jVqdS©N)Z device_node)rHÚdevr r r Ú ;rKz,convert_scsi_hctl_to_path..ÚN) rGr.rrrrr3rÚjoinr<Z list_devicesÚnext)ÚhostZ controllerÚtargetZlunZhctlZ scsi_deviceZdevicesrr r r Úconvert_scsi_hctl_to_paths,  ÿ þrWcCsî| ¡}|dkrtt ¡ƒS|dkr0tt ¡ƒS|dkr¢t ¡ d¡d dd¡}t  ¡d dd¡}d ||f}|  ¡ ¡}d tt ¡ƒd d …}d ||fS|dkrÀdt ¡j dd …S|dkrÞdt ¡j dd …St d|ƒ‚d S)a  Generates a random WWN of the specified type: - unit_serial: T10 WWN Unit Serial. - iqn: iSCSI IQN - naa: SAS NAA address @param wwn_type: The WWN address type. @type wwn_type: str @returns: A string containing the WWN. ÚfreeÚ unit_serialÚiqnÚ.rÚ_rRéz!iqn.2003-01.org.linux-iscsi.%s.%szsn.%séNz%s:%sÚnaaz naa.5001405i÷ÿÿÿÚeuiz eui.001405iöÿÿÿzUnknown WWN type: %s) ÚlowerrÚuuidZuuid4ÚsocketZ gethostnamerMr;rÚunamerÚhexr.)Úwwn_typeZ localnameZ localarchÚprefixÚserialr r r Ú generate_wwn@s"      rics$d ‡fdd„tdtˆƒdƒDƒ¡S)z5 helper function to add colons every 2 chars rLc3s|]}ˆ||d…VqdS)éNr )rHÚi©rr r rQerKzcolonize..rrj)rSÚrangeÚlenrlr rlr ÚcolonizeasrocCstt| ¡ƒ ¡}|dvrp| d¡r.|dd…}| dd¡}| dd¡}| d¡sp| d ¡sp| d ¡sp|d |}|S) zh Some wwns may have alternate text representations. Adjust to our preferred representation. )r_r`ÚibÚ0xrjNú-rRrLznaa.zeui.zib.r[)rrraÚ startswithr;)rfÚwwnr r r Ú _cleanse_wwngs    ÿ rucCsldd„dd„dd„dd„dd„dd„dœ}|D]"}t||ƒ}|||ƒ}|r.qdq.td d  |¡ƒ‚||fS) z¥ Take a WWN as given by the user and convert it to a standard text representation. Returns (normalized_wwn, wwn_type), or exception if invalid wwn. cSsdS)NTr ©rtr r r Ú‚rKznormalize_wwn..cSs(t d|¡o&t d|¡ o&t d|¡ S)Nz iqn\.[0-9]{4}-[0-1][0-9]\..*\..*ú r\)r=Úmatchr>rvr r r rwƒs  ÿcSs t d|¡S)Nz naa\.[125c-fC-F][0-9a-fA-F]{15}$©r=ryrvr r r rw‡rKcSs t d|¡S)Nzeui\.[0-9a-f]{16}$rzrvr r r rwˆrKcSs t d|¡S)Nzib\.[0-9a-f]{32}$rzrvr r r rw‰rKcSs t d|¡S)Nz3[0-9A-Fa-f]{8}(-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$rzrvr r r rwŠs)rXrZr_r`rprYzWWN not valid as: %sz, )rurrS)Z wwn_typesrtZwwn_testrfZ clean_wwnZ found_typer r r Ú normalize_wwnzs÷   r{cCsdd„tdƒ d¡DƒS)z2 List all currently loaded kernel modules cSsg|]}|r| d¡d‘qS)rxr)rM)rHÚliner r r rJœsÿz.list_loaded_kernel_modules..z /proc/modulesÚ )rrMr r r r Úlist_loaded_kernel_modules˜s ÿr~cCs |tƒvrdSz ddl}WnJtydtjd|ftjtjd�}| ¡\}}|jdkr^t|ƒ‚YdS0z|  ¡  |¡Wn"|j j yštd|ƒ‚Yn0dS)zŠ Load the specified kernel module if needed. @param module: The name of the kernel module to be loaded. @type module: str NrÚmodprobe©ÚstdoutÚstderrzCould not load module: %s) r~ÚkmodÚ ImportErrorÚ subprocessÚPopenÚPIPEÚ communicateÚ returncoderZKmodrÚerrorZ KmodError)ÚmodulerƒÚprocessÚ stdoutdataÚ stderrdatar r r rŸs"    þ  rcCsVtj d¡sRd}tj| ¡tjtjd�}| ¡\}}|jdkrRtj d¡sRt dƒ‚dS)Nz/sys/kernel/configz)mount -t configfs none /sys/kernel/configr€rzCannot mount configfs) rrÚismountr…r†rMr‡rˆr‰r)ZcmdlinerŒr�rŽr r r Úmount_configfs¸s  þ ÿr�cCs|D]}||vr||=qdSrOr )ÚdÚitemsÚitemr r r Ú dict_removeÃsr”cgs"z dVWn|yYn0dSrOr )Ú exceptionsr r r ÚignoredÈs  r–FcCsL| ¡d|j|f}z t|ƒ}Wn|s0‚YdS0|dkrDdS|SdS)Nú%s/%sÚNULLrR)Ú _check_selfrr)ÚselfÚ attributeÚignorerÚvaluer r r Ú_get_auth_attrÜs ržcCsx| ¡d|j|f}| ¡}|dkr.tdƒ‚t|ƒdkrBtdƒ‚|dkrNd}zt|d|ƒWn|sn‚Yn0dS)Nr—r˜z'NULL' is not a permitted valueéÿz'Value longer than maximum length of 255rRz%s)r™rrrrnr)ršr�r›rœrr r r Ú_set_auth_attrës r c CsZt |¡D]J\}}z| ||¡Wq tyR}z|t|ƒƒWYd}~q d}~00q dSrO)ÚsixÚ iteritemsZ set_attributerr)ÚobjZ attr_dictÚerr_funcr4r�Úer r r Úset_attributesûs r¦c CsZt |¡D]J\}}z| ||¡Wq tyR}z|t|ƒƒWYd}~q d}~00q dSrO)r¡r¢Z set_parameterrr)r£Z param_dictr¤r4r�r¥r r r Úset_parameterss r§cCsddl}| ¡dS)zRun the doctestsrN)ÚdoctestZtestmod)r¨r r r Ú_test sr©Ú__main__)F)F),rrr=r¡rcÚstatr…rbÚ contextlibrrZContextrÚ Exceptionrr r r rrr'r0r1Zget_block_sizerCrEZget_block_typerNrWrirorur{r~rr�r”r–ržr r¦r§r©rr r r r ÚsT   %% 0!