a hc@sddlZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl mZddlmZmZmZddlmZmZddlmZddlmZddlmZmZmZm Z dd l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,e-e.Z/e0e1d d d Z2ej3e4d ddZ5dddddZ6e1ddddZ7GdddeZ8Gddde Z9GdddZ:GdddeZ;Gd d!d!eeZGd$d%d%eeZ?dS)&N)Path)Callable GeneratorIterable)Handle PathWatch)Event)Listener) AsyncChannelChannel ChannelErrorGeneratorChannel) JsonDict JsonDocument JsonError JsonObjectget_boolget_int get_objectget_strget_str_or_intget_strvjson_merge_and_filter_patchreturncCs0tdtdtj}|r,t|ddp.dS)Nz^Umask:\s*0([0-7]*)$z/proc/self/status?)researchr read_textMintgroup)matchr&?/usr/lib/python3.9/site-packages/cockpit/channels/filesystem.pymy_umask8sr()bufrc Cs.d|jd|jd|jdd|jd|j S)Nz1:-o)st_inost_mtimest_modest_uidst_gidr)r&r&r' tag_from_stat>sr2zint | str | Path str | None)pathrcCs<ztt|WSty$YdSty6YdS0dS)Nr*)r2osstatFileNotFoundErrorOSError)r4r&r&r' tag_from_pathBs   r9fdrcCs*ztt|WSty$YdS0dSN)r2r5fstatr8)r;r&r&r' tag_from_fdKs r>c@s2eZdZdZedddddZdddd d ZdS) FsListChannelZfslist1zos.DirEntry[str]N)evententryrcCsD|rd}n |rd}n|r*d}nd}|j||j|ddS)Nlinkfile directoryZspecial)r@r4type) is_symlinkis_fileis_dir send_jsonname)selfr@rAmoder&r&r' send_entryWszFsListChannel.send_entryroptionsrc Cs t|d}|dd}|r&tdddzt|}Wntyj}ztdt|d|WYd}~nrd}~0ty}ztdt|d|WYd}~n>d}~0ty}ztd t|d|WYd}~n d}~00| |D]}| d |q|s| | dS) Nr4watchTz not-supportedz)watching is not implemented, use fswatch1message not-found access-deniedinternal-errorZpresent) rgetr r5scandirr7strPermissionErrorr8readyrMdoneclose)rKrOr4rPZscan_direrrorrAr&r&r'do_opencs$   &&(zFsListChannel.do_open)__name__ __module__ __qualname__payloadrXrMr^r&r&r&r'r?Ts r?c@s*eZdZdZeeedefdddZdS) FsReadChannelZfsread1NrNc cs~t|d}t|dd}td|zt|d}t|}|dkrX|j|krXt d|j rzt |j rz|j |jdn| |tj}|d krqtd t||j s|d d jd d }|VqWdn1s0Ydt|iWStyddiYStyB}zt d|WYd}~n@d}~0tyx}zt dt|d|WYd}~n d}~00dS)Nr4 max_read_sizeizOpening file "%s" for readingrbz too-large)Z size_hintz ...sending %d bytesignoreerrorstagr*rTrUrQ)rrloggerdebugopenr5r6filenost_sizer Z is_binaryS_ISREGr.rZread1r Z BLOCK_SIZElenreplacedecodeencoder2r7rYr8rX)rKrOr4rdZfilepr)dataexcr&r&r' do_yield_datas2     & zFsReadChannel.do_yield_data)r_r`rarbrrbytesrzr&r&r&r'rc|srcc@sJeZdZUdZded<dZded<hdZdZded<edddd Z dS) FSReplaceAttrsN int | Noneuidgid>rLuserr$rL)valuercCs0||j}|r2tddd|t|ddt|dd|_t|dd}t|dd}|durt|durttddd |dur|durtdd d t|t rzt |j |_ Wqtytd d |d dYq0n||_ t|t r&zt|j|_Wn(ty"td d |d dYn0n||_dS)Nzprotocol-errorz%"attrs" contains unsupported key(s): ,)rRunsupported_attrsrLrr$z3"group" attribute is empty while "user" is providedrQz3"user" attribute is empty while "group" is providedrSzuid not found for zgid not found for )keyssupported_attrsr joinlistrrLr isinstancerXpwdgetpwnampw_uidr~KeyErrorgrpgetgrnamgr_gidr)rKrrrr$r&r&r'__init__s6       zFSReplaceAttrs.__init__) r_r`rar~__annotations__rrrLrrr&r&r&r'r|s    r|c@sNeZdZdZdZededddZedddd dd d d Zeed ddZ dS)FsReplaceChannelZ fsreplace1attrsr3)r4rlrcCsT|dur|t|krtdttt|Wdn1sF0YdS)Nchange-conflictr*)r9r contextlibsuppressr7r5unlink)rKr4rlr&r&r'deletes  (zFsReplaceChannel.delete bytes | Noner}zFSReplaceAttrs | None)r4rlrxsizerrc stj|\}}tj|d|dd\}} dddddfdd } ddd dd fd d } z|durtd |||r|tj|d|IdH| d} |dur|tj ||IdH| t |7} | IdH}q|dur| |krtd|| |tj || IdH|tj|IdH|durN| || |t| |d} n|dkrv| || |t| |nt|tj} zt| }|t|krtd| |t|j| ||z,t| d}t|d|td||Wn2ty }ztd|WYd}~n d}~00Wt| n t| 0t| |d} Wt|| durt| n t|| durt| 0t|S)N.r*)dirprefixr#zos.stat_result | None)r;r)rcsNdur0jdur0jdur0t|jjn|durJt||j|jdSr<)r~rr5fchownr/r0)r;r)rr&r'chown_if_requiredsz8FsReplaceChannel.set_contents..chown_if_requiredr})r;rLrcs>durjdurj}n|dur.dt@}t||dS)Ni)rLr(r5fchmod)r;rLrr&r'apply_file_modes  z6FsReplaceChannel.set_contents..apply_file_modezfallocate(%s.tmp, %d)rzftruncate(%s.tmp, %d)rzsecurity.selinuxz SELinux context '%s' set on '%s'zAError getting or setting SELinux context from original file: '%s')N)N)r5r4splittempfileZmkstemprmrnZ in_threadposix_fallocaterZwritertread ftruncate fdatasyncrenamerBroO_RDONLYr6r2r S_IMODEr.getxattrsetxattrr8 exceptionr\rr9)rKr4rlrxrrdirnamebasenamer;ZtmpnamerrZwrittenZpath_fdr)Zselinux_contextryr&rr' set_contentssf       $      zFsReplaceChannel.set_contentsrNc st|dtd}t|d}t|dd}t|dd}zx|durT|||d||IdH}nD||IdH}|dur|||}n||||d|IdH}|d|iWSt y}zt d|WYd}~nd}~0t y}zt d|WYd}~nd}~0t y2}zt d|WYd}~nvd}~0t yh}zt dt|d |WYd}~n@d}~0ty}zt d t|d |WYd}~n d}~00dS) Nrr4rrlrgrSrrTrQrU)rr|rrrrZrrr[r7r FileExistsErrorrYIsADirectoryErrorrXr8)rKrOrr4rrlrxryr&r&r'run,s0    &zFsReplaceChannel.runN) r_r`rarbZ capabilitiesrXrrrrr&r&r&r'rs Urc@s~eZdZUdZdZded<dZdZee dddd Z e e d dd d d Z ddddddZ eddddZddddZdS)FsWatchChannelZfswatch1Nr3_tagFztuple[str, str | None])maskrcCsltjp tj|vr&dtj|vr dndfStj|vsDtj|vsDtj|vrHdStj|vrVdStj|vrddSdSdS)NcreatedrDrC)deletedN)zattribute-changedN)z done-hintN)ZchangedN) InotifyEventCREATEMOVED_TOZISDIR MOVED_FROMDELETEZ DELETE_SELFZATTRIBZ CLOSE_WRITE)rr&r&r'mask_to_event_and_type^s  z%FsWatchChannel.mask_to_event_and_typer)r_cookierJrcCstd|j||||\}}|rTtj|j|}t|}|j ||||dn4t|j}||j krldS||_ |j ||j|j |ddS)Nz%do_inotify_event(%s): mask %X name %s)r@r4rlrE) rmrn_pathrr5r4rrvr9rIr)rKrrrJr@type_r4rlr&r&r'do_inotify_eventks  zFsWatchChannel.do_inotify_eventr}r;errrcCsNtd|jt|||r"t|nd|_|jrJ|j|r:dnd|j|jddS)Nz&do_identity_changed(%s): fd %s, err %sr*rr)r@r4rl)rmrnrrXr>r_activerIrKr;rr&r&r'do_identity_changed{sz"FsWatchChannel.do_identity_changedrNcCs8t|d|_d|_d|_t|j||_d|_|dS)Nr4FT)rrrrr_watchrZ)rKrOr&r&r'r^s  zFsWatchChannel.do_openrcCs&|jdur|jd|_|dSr<)rr\rKr&r&r'do_closes  zFsWatchChannel.do_close)r_r`rarbrrrr staticmethodrrr#rrrr^rr&r&r&r'rSs    rc@seZdZdZdZdS)FollowFTN)r_r`raNOYESr&r&r&r'rsrc@sleZdZUdZeed<ded<eed<eed<eed<eed<eed <d Zeed <d Z d ed<d Z ded<d Z ded<ded<e e eddddZddeed dddZddded dddZd d d!d"Zeed#d$d%Zed d#d&d'Zed d(d)d*Zeed+d,d-Zed d+d.d/Zeed0d d1d2d3Zd d4d d5d6d7Zd d d8d9Zed d:d;d<Zd S)= FsInfoChannelZfsinfor4zset[str]rfnmatchtargetsfollowrP current_valueeffective_fnmatchNz Handle | Noner;zset[str] | NonependingzPathWatch | None path_watchz*Callable[[int, str, Follow], JsonDocument]getattrsz1Callable[[int, str, Follow], JsonDocument | None])rrcsttddddttdddddd ttttd d d d tjdtjdtjdtj dtj dtj dtj difddt ddddddddddfddfddd tfdd |Dtttd!d"fd#d$ }|S)%Nz str | int)r~rcSs*zt|jWSty$|YS0dSr<)rgetpwuidpw_namer)r~r&r&r'get_users z-FsInfoChannel.make_getattrs..get_user)rrcSs*zt|jWSty$|YS0dSr<)rgetgrgidgr_namer)rr&r&r' get_groups z.FsInfoChannel.make_getattrs..get_groupFfollow_symlinksz bool | None)dir_fdrJrLrrcSsNz4|rtj||||dWStjd||ddWSWntyHYdS0dS)N)rr/proc/self/fd/Tr)r5accessr8)rrJrLrr&r&r' get_accesss  z/FsInfoChannel.make_getattrs..get_accessZregrZlnkchrZblkZfifoZsockcst|jSr<)rVr6S_IFMTr.r1) stat_typesr&r'rgz-FsInfoChannel.make_getattrs..cSs t|jSr<)r6rr.r1r&r&r'rrgcSs|jSr<)rqr1r&r&r'rrgcSs|jSr<r/r1r&r&r'rrgcSs|jSr<r0r1r&r&r'rrgcSs|jSr<)r-r1r&r&r'rrgcs |jSr<rr1)rr&r'rrgcs |jSr<rr1)rr&r'rrg) rErlrLrr~rmtimerr$c3s"|]}||ddfVqdS)cSsdSr<r&)_r&r&r'rrgz7FsInfoChannel.make_getattrs...N)rV).0key)available_stat_gettersr&r' rgz.FsInfoChannel.make_getattrs..zJsonDict | None)r;rJrrcsz$|rtj||j|dnt|Wn2ty8YdStyVddDYS0fddD}d|vrtjtjkrt t"tj ||d|d<Wdn1s0Ydtj fdtj fd tjffD]&\}}||vr܈||||jd ||<q|S) N)rrcSsi|]\}}|dqSr<r&)rrJfuncr&r&r' rgzBFsInfoChannel.make_getattrs..get_attrs..csi|]\}}||qSr&r&)rrrr1r&r'rrgtarget)rzr-okzw-okzx-okr)r5r6rr=r7r8rr.S_IFLNKrrreadlinkR_OKW_OKX_OK)r;rJrresultattrr)r stat_gettersr1r' get_attrss$   0$z.FsInfoChannel.make_getattrs..get_attrs) functools lru_cacher#rXboolr6S_IFREGS_IFDIRrS_IFCHRS_IFBLKS_IFIFOS_IFSOCKr2tupler)rrr&)rrrrrrr' make_getattrss*     zFsInfoChannel.make_getattrsFreset)updatesr rcCst|rVt|jt|@rD|jt|jddddi|_|jddn|t|jt|j||rp||dS)NT)partialr )setrrIdictfromkeysupdater)rKr r r&r&r' send_updates  zFsInfoChannel.send_updatecsjdusJfdd|D}|di}t|ts:JjrH||d<jri|d<}dd|DD]F}t|trl|dkrl|d ksd |vs|sl j|t j ||<qlj d |i|d dS) Ncs i|]}|j|tjqSr&)rr;rr)rrJrr&r'rrgz0FsInfoChannel.process_update..rentriesrcSs h|]}t|tr|dqS)r)rrrVrer&r&r' rgz/FsInfoChannel.process_update..rz../infor ) r;poprrrrvaluesrX interestingrrrr)rKr r rrrrJr&rr'process_updates  zFsInfoChannel.process_updatercCs*|jdusJ|jr ||jd|_dSr<)rrrr&r&r'process_pending_updatess z%FsInfoChannel.process_pending_updates)rJrcCs|dkr dSt||jSdS)NrT)rrrKrJr&r&r'rszFsInfoChannel.interestingcCsB||sdS|jdur2td|jt|_|j|dS)Ng?)rrasyncioZget_running_loopZ call_laterrraddrr&r&r'schedule_update!s   zFsInfoChannel.schedule_update)rrcCsd|tjkrd}n*|tjtjfvr&d}n|tjkr6d}nd}|jd|t|tj|didddS) NrSrTz not-directoryrUr])problemrRerrnoTr ) r#ENOENTEPERMZEACCESENOTDIRrr5strerror errorcode)rKrr"r&r&r' report_error+s  zFsInfoChannel.report_errorr:cCsF|jr|jdsdSt|}t|jtjkrB| t j dSdS)NrFT) rPr4endswithr5r=r6rr.rr)r#r&)rKr;r)r&r&r'flag_onlydir_error9s  z FsInfoChannel.flag_onlydir_errorcs~|rdS|_dh}jr^z$|tdjj_Wnty\d_Yn0jfdd|DdddS)Nrrcsh|]}|r|qSr&)rrrr&r'rVrgz5FsInfoChannel.report_initial_state..Tr ) r+r;rrr5listdirrr8r)rKr;rr&rr'report_initial_stateGs    z"FsInfoChannel.report_initial_stater)rcookierawnamercCsXtd||||pdjdd}|||rT|tjtjBtjBtjBBrT|ddS)Nzdo_inotify_event(%r, %r, %r)rgsurrogateescaperjr) rmrnrvr!rrrrr)rKrr.r/rJr&r&r'rXs zFsInfoChannel.do_inotify_eventr}rcCsPtd|||jdur"|j|durB|dus6J||n ||dS)Nzdo_identity_changed(%r, %r))rmrnrclearr-r)rr&r&r'rcs    z!FsInfoChannel.do_identity_changedcCs$|jdusJ|j|dSr<)rr\rr&r&r'rps zFsInfoChannel.do_closerNc Csht|d|_tj|js$t|dtt|d}||ddh|_t|dd|vrXdnd|_ d|v|_ t |d d d |_ t |d d d |_ |j r|j st|d|j r|j st|di|_||j sVz&t|j|j rtjn tjtjB}Wn>ty0}z$|jsJ||jWYd}~nd}~00|||||nt|j||_dS)Nr4z"path" must be an absolute pathrrrr*rrT)defaultrPFz>"watch: true" and "follow: false" are (currently) incompatiblezB`targets: "stat"` and `follow: false` are (currently) incompatible)rr4r5isabsrrrr rrrrrrPrrZrroO_PATH O_NOFOLLOWr8r#r)r-r\r[rr)rKrOrr;ryr&r&r'r^vs4       & "  zFsInfoChannel.do_open)r_r`rarbrXrrrrr;rrrrr rrrrr!r#r)rr+r-rrrrrr^r&r&r&r'rs6     ?   r)@rrenumr#rrrZloggingr5rrr6rpathlibrtypingrrrZcockpit._vendor.systemd_ctypesrrZ&cockpit._vendor.systemd_ctypes.inotifyrrZ(cockpit._vendor.systemd_ctypes.pathwatchr ZPathWatchListenerZchannelr r r rZjsonutilrrrrrrrrrrrZ getLoggerr_rmrr#r( stat_resultrXr2r9r>r?rcr|rrEnumrrr&r&r&r'sB   4   (((?