+
    sj]                          R t ^ RIt^ RIt^ RIt^ RIt^ RIt ^ RIt^ RItRt	Rt
RtRtRtR tR tR tR	 tR
 tR tRR ltR tRR ltR tR tR tR#   ] d    RtRt LAi ; i)u7  sshj.selftest — `sshj --selftest`: probe env, degrade w/ a message, never crash.

Leaf (stdlib only). Six probes per worklog/rq6-selftest-probes.md (RQ6):
tty (the grid gate: stdin-isatty, RQ8) · size (TIOCGWINSZ, 10x50 min) ·
kernel (TIOCSTI on a throwaway pty — never the real tty, spec 5.3) ·
shell (the ACTUAL shell = the parent's /proc/<pid>/comm, $SHELL fallback,
spec 5.4) · relay (sshj-relay, REQUIRED whenever TIOCSTI is refused; the
/bin/bash child sub-check rides along, spec P5 note) · python (floor 3.8).
run(ver) prints the table to stdout (2-space indent, 4-char status col,
2-space gap, 9-char name col — exactly the spec section 4 sample), one degrade message per WARN/FAIL to stderr, and returns
the exit code: 0 all OK · 1 warnings only · 2 any FAIL. No global state,
no network, no writes.
Nu`   sshj: no terminal — the grid can't open; run sshj <host> (direct mode) or use ssh -T host sshjuu   sshj: this kernel can't prefill the shell line — two-stage Tab is off; Enter still connects, Tab prints the commanduc   sshj: sshj-relay not found — two-stage Tab is off; run 'make install' or add ~/.local/bin to PATHz.sshj: no /bin/bash (relay child shell missing)c                  2    \         R J;'       d	    \        R J# N)fcntltermios     src/sshj/selftest.py_termios_okr	   (   s    44!44r   c                     \         P                  ! 4       P                  p \        P                  ! RV 4      pV'       d1   VP                  ^4      R,           VP                  ^4      ,           V 3# W 3# )uE   (major.minor, full release) — first \d+\.\d+ of os.uname().release.z(\d+)\.(\d+).)osunamereleaseresearchgroup)relms     r   _kernel_versionr   ,   sR    
((*

C
		/3'AwwqzC!''!*,c118Or   c                 ,   \        4       '       g   R#  ^ RIp V P                  4       w  r \        P
                  ! T\        P                  R4        Y3 F  p \        P                  ! T4       K  	  R#   \         d     R# i ; i  \         d     K@  i ; i  \         d8     Y3 F,  p \        P                  ! T4       K    \         d     K*  i ; i	  R# i ; i  Y3 F,  p \        P                  ! T4       K    \         d     K*  i ; i	  i ; i)u   True when TIOCSTI can stuff the input queue (kernel < 6.2).

A throwaway pty (spec 5.3) — never ioctl the user's real tty, even
though the refusal is harmless: we don't depend on refusal semantics.FN   aT)r	   ptyopenpty	Exceptionr   ioctlr   TIOCSTIr   closeOSError)r   r   sfds       r   _ttiocsti_worksr    5   s    
 =={{}
Aw- &B       &B   &B  s|   A5 &B B5BBBBC$C ,CCCCC D&C><D>D		DD	Dc            	        \         P                  ! R4      p V '       d   V # \        P                  P	                  \        P                  P                  \        P                  P                  \        P                  P                  \        4      4      4      R4      p\        P                  P                  V4      '       d.   \        P                  ! V\        P                  4      '       d   V# R# )zBsshj-relay on PATH (deployed), else the dev tree (src/sshj-relay).z
sshj-relayN)shutilwhichr   pathjoindirnameabspath__file__existsaccessX_OK)rdevs     r   _relay_pathr.   N   s    \"A
'',,
(ABCC 
ww~~cryybgg66
r   c                     \         P                  P                  4       p \         P                  P                  4       pV '       d   V'       d   R# V '       d   R# RR\        3# )u[   P1 — the grid gate: stdin must be a tty (RQ8: piped stdout with tty stdin still renders).FAILzno terminal (stdin not a tty))OKzstdin+stdout on a terminalN)WARNuL   stdout piped (stdin is a terminal) — the /dev/tty fallback covers the gridN)sysstdinisattystdout
MSG_NO_TTY)tintouts     r   	probe_ttyr:   [   sN    
))


C::D
t77
C 	C2J>>r   c                 Z   \        4       '       g   R#  \        P                  ! ^ \        P                  R	4      p \
        P                  ! RV R,          4      w  rT^ 8:  g   T^ 8:  d   R# T^
8  d   T^28  d   RRY3,          R3# RRY3,          RY3,          3#   \         d    R
u # i ; i)uP   P2 — terminal size; an unknown 0x0 (unconfigured pty) is a WARN, never a FAIL.r2   Nhh:N   Nr1   z%d rows x %d cols (min 10x50)uR   sshj: terminal is small (%dx%d) — the grid will be cramped; try a wider terminal)r2   zunknown (no termios)Ns           )r2   zunknown (not a tty)N)r2   u"   0x0 — unknown (unconfigured pty)N)r	   r   r   r   
TIOCGWINSZstructunpackr   )wrowscolss      r   
probe_sizerD   g   s    ==333KK7--y9]]42/
 qyDAIAArzdbj4|CTII3tlB#&*\23 3  3223s   AB B*)B*c                v    \        4       w  rV f   \        4       p V '       d   RVR,           R3# RVR,           R3# )uV   P3 — TIOCSTI direct stuff, or (refused) the relay route; run() finalizes against P5.Nr1   u!    — TIOCSTI works (direct stuff)r2   u    — TIOCSTI unavailable)r   r    )ttiocstikver_rels   &  r   probe_kernelrI   y   sC     "JD"$T??EE444d::r   c                    Rp  \        R\        P                  ! 4       ,          4      ;_uu_ 4       pVP                  4       P	                  4       p RRR4       T '       g   R	# T R8X  d   R
# RT R,           RT ,          3#   + '       g   i     L6; i  \
         dJ    \        P                  P                  \        P                  P                  R4      ;'       g    R4      p  Li ; i)u   P4 — the ACTUAL shell running sshj: its parent's /proc/<pid>/comm (RQ9's
truth — sshj is launched by the shell, whose $SHELL may lie; after the
widget's $() subshell or a direct type, the parent IS the shell). z/proc/%d/commNSHELLr2   bashu)    detected — the Tab widget is bash-onlyud   sshj: %s detected — the Tab widget is bash-only; type the command or use direct mode (sshj <host>))r2   z"unknown (no /proc comm, no $SHELL)uf   sshj: shell unknown — the Tab widget is bash-only; type the command or use direct mode (sshj <host>))r1   z#bash (widget: two-stage Tab active)N)
openr   getppidreadstripr   r$   basenameenvironget)shellfs     r   probe_shellrW      s     E@/BJJL011QFFHNN$E 2 @ 	@ @@EGG79>?@ @ 21 @  !8!>!>B?@s5   -B A>B >B		B B A	C%C%$C%c                @   V f   \        4       p \        4       pV'       dm   \        P                  P	                  R4      '       d8   \        P
                  ! R\        P                  4      '       d   RVR,           R3# RVR,           \        3# V '       d   R	# RR\        3# )
uR   P5 — the relay (REQUIRED whenever TIOCSTI is refused) + the /bin/bash sub-check.Nz	/bin/bashr1   z (child /bin/bash present)r2   z (child /bin/bash missing)r0   u4   not found (TIOCSTI refused — the Tab path is dead))r1   u5   not found — not needed (TIOCSTI direct stuff works)N)	r    r.   r   r$   r)   r*   r+   MSG_NO_BASHMSG_NO_RELAY)rF   relays   & r   probe_relayr\      s    "$ME77>>+&&299["''+J+J!==tCCu;;[HHRRI r   c                     \         P                  p RV P                  V P                  V P                  3,          pV P                  V P                  3\
        8  d   RVR,           RV,          3# RVR,           R3# )uB   P6 — the python floor (3.8); the only probe that FAILs below it.z%d.%d.%dr0   z (floor 3.8)z"sshj: needs Python 3.8+ (found %s)r1   N)r3   version_infomajorminormicroFLOOR)vvstrs     r   probe_pythonre      sm    A!''17733D	E!tn,0478 	8&,,r   c                Z     W! 4       3#   \          d   pT RRT: 2R33u Rp?# Rp?ii ; i)uJ   C3: a probe must never crash selftest — a broken probe degrades to WARN.r2   zprobe error: N)r   )namefnes   && r   _saferj      s;    @bd| @vA7>??@s   
 *
%**c           	     p  a \        4       o\        R\        4      \        R\        4      \        RV3R l4      \        R\        4      \        RV3R l4      \        R\
        4      .pS'       gP   V^,          ^,          w  r#pV^,          ^,          ^ ,          R	8X  d   RR	VR
,           R33V^&   MRRV\        33V^&   RV \        P                  P                  \        P                  P                  \        P                  P                  3,          .p^ p. pV F  w  pw  rpVP                  RV	P                  ^4      ,           R,           VP                  ^	4      ,           V
,           4       V	R8X  d   V^,          pMV	R8X  d   VP                  V4       V'       g   K  \        P                  P                  VR,           4       K  	  V'       d   RRP!                  V4      ,           ^rMV'       d   RV,          ^rMR^ rVP                  RV,           4       \#        RP!                  V4      4       V# )zIPrint the probe table (stdout) + degrade messages (stderr); return 0/1/2.ttysizekernelc                     < \        S 4      # r   )rI   rF   s   r   <lambda>run.<locals>.<lambda>   s
    L$:r   rU   r[   c                     < \        S 4      # r   )r\   rp   s   r   rq   rr      s
    ;x#8r   pythonr1   z, using relayNr2   z)  sshj --selftest  (v%s, python %d.%d.%d)z  r0   
zFAILED: z, zOK with warnings: %d warnzALL OKz  -- selftest: )r    rj   r:   rD   rW   re   MSG_NO_PREFILLr3   r^   r_   r`   ra   appendljuststderrwriter%   print)verrB   _k_stk_det_k_msgoutwarnsfailsrg   stdetmsgverdictcoderF   s   &             @r   runr      s    H%#&*%(:;';''89(L)+D #Awqzf71:a=D $(?!FGDG&%!@ADG6!!'')9)9)?)?""$$ %C EE $nr

4"((1+%,tzz!}<sBC<QJE6\LL3JJS4Z( !% "TYYu%55q	3e;Q !JJ 7*+	$))C.Kr   )      r   )__doc__r   r   r"   r?   r3   r   r   ImportErrorrb   r7   rv   rZ   rY   r	   r   r    r.   r:   rD   rI   rW   r\   re   rj   r   r   r   r   <module>r      s    
 	   

 	6
+A>52
	?3$;@*-@&C  EGs   A A"!A"