PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/golang/1.22.0/src/os/exec
Viewing File: /opt/golang/1.22.0/src/os/exec/exec.go
// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package exec runs external commands. It wraps os.StartProcess to make it // easier to remap stdin and stdout, connect I/O with pipes, and do other // adjustments. // // Unlike the "system" library call from C and other languages, the // os/exec package intentionally does not invoke the system shell and // does not expand any glob patterns or handle other expansions, // pipelines, or redirections typically done by shells. The package // behaves more like C's "exec" family of functions. To expand glob // patterns, either call the shell directly, taking care to escape any // dangerous input, or use the path/filepath package's Glob function. // To expand environment variables, use package os's ExpandEnv. // // Note that the examples in this package assume a Unix system. // They may not run on Windows, and they do not run in the Go Playground // used by golang.org and godoc.org. // // # Executables in the current directory // // The functions Command and LookPath look for a program // in the directories listed in the current path, following the // conventions of the host operating system. // Operating systems have for decades included the current // directory in this search, sometimes implicitly and sometimes // configured explicitly that way by default. // Modern practice is that including the current directory // is usually unexpected and often leads to security problems. // // To avoid those security problems, as of Go 1.19, this package will not resolve a program // using an implicit or explicit path entry relative to the current directory. // That is, if you run exec.LookPath("go"), it will not successfully return // ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. // Instead, if the usual path algorithms would result in that answer, // these functions return an error err satisfying errors.Is(err, ErrDot). // // For example, consider these two program snippets: // // path, err := exec.LookPath("prog") // if err != nil { // log.Fatal(err) // } // use(path) // // and // // cmd := exec.Command("prog") // if err := cmd.Run(); err != nil { // log.Fatal(err) // } // // These will not find and run ./prog or .\prog.exe, // no matter how the current path is configured. // // Code that always wants to run a program from the current directory // can be rewritten to say "./prog" instead of "prog". // // Code that insists on including results from relative path entries // can instead override the error using an errors.Is check: // // path, err := exec.LookPath("prog") // if errors.Is(err, exec.ErrDot) { // err = nil // } // if err != nil { // log.Fatal(err) // } // use(path) // // and // // cmd := exec.Command("prog") // if errors.Is(cmd.Err, exec.ErrDot) { // cmd.Err = nil // } // if err := cmd.Run(); err != nil { // log.Fatal(err) // } // // Setting the environment variable GODEBUG=execerrdot=0 // disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19 // behavior for programs that are unable to apply more targeted fixes. // A future version of Go may remove support for this variable. // // Before adding such overrides, make sure you understand the // security implications of doing so. // See https://go.dev/blog/path-security for more information. package exec import ( "bytes" "context" "errors" "internal/godebug" "internal/syscall/execenv" "io" "os" "path/filepath" "runtime" "strconv" "strings" "syscall" "time" ) // Error is returned by LookPath when it fails to classify a file as an // executable. type Error struct { // Name is the file name for which the error occurred. Name string // Err is the underlying error. Err error } func (e *Error) Error() string { return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error() } func (e *Error) Unwrap() error { return e.Err } // ErrWaitDelay is returned by (*Cmd).Wait if the process exits with a // successful status code but its output pipes are not closed before the // command's WaitDelay expires. var ErrWaitDelay = errors.New("exec: WaitDelay expired before I/O complete") // wrappedError wraps an error without relying on fmt.Errorf. type wrappedError struct { prefix string err error } func (w wrappedError) Error() string { return w.prefix + ": " + w.err.Error() } func (w wrappedError) Unwrap() error { return w.err } // Cmd represents an external command being prepared or run. // // A Cmd cannot be reused after calling its Run, Output or CombinedOutput // methods. type Cmd struct { // Path is the path of the command to run. // // This is the only field that must be set to a non-zero // value. If Path is relative, it is evaluated relative // to Dir. Path string // Args holds command line arguments, including the command as Args[0]. // If the Args field is empty or nil, Run uses {Path}. // // In typical use, both Path and Args are set by calling Command. Args []string // Env specifies the environment of the process. // Each entry is of the form "key=value". // If Env is nil, the new process uses the current process's // environment. // If Env contains duplicate environment keys, only the last // value in the slice for each duplicate key is used. // As a special case on Windows, SYSTEMROOT is always added if // missing and not explicitly set to the empty string. Env []string // Dir specifies the working directory of the command. // If Dir is the empty string, Run runs the command in the // calling process's current directory. Dir string // Stdin specifies the process's standard input. // // If Stdin is nil, the process reads from the null device (os.DevNull). // // If Stdin is an *os.File, the process's standard input is connected // directly to that file. // // Otherwise, during the execution of the command a separate // goroutine reads from Stdin and delivers that data to the command // over a pipe. In this case, Wait does not complete until the goroutine // stops copying, either because it has reached the end of Stdin // (EOF or a read error), or because writing to the pipe returned an error, // or because a nonzero WaitDelay was set and expired. Stdin io.Reader // Stdout and Stderr specify the process's standard output and error. // // If either is nil, Run connects the corresponding file descriptor // to the null device (os.DevNull). // // If either is an *os.File, the corresponding output from the process // is connected directly to that file. // // Otherwise, during the execution of the command a separate goroutine // reads from the process over a pipe and delivers that data to the // corresponding Writer. In this case, Wait does not complete until the // goroutine reaches EOF or encounters an error or a nonzero WaitDelay // expires. // // If Stdout and Stderr are the same writer, and have a type that can // be compared with ==, at most one goroutine at a time will call Write. Stdout io.Writer Stderr io.Writer // ExtraFiles specifies additional open files to be inherited by the // new process. It does not include standard input, standard output, or // standard error. If non-nil, entry i becomes file descriptor 3+i. // // ExtraFiles is not supported on Windows. ExtraFiles []*os.File // SysProcAttr holds optional, operating system-specific attributes. // Run passes it to os.StartProcess as the os.ProcAttr's Sys field. SysProcAttr *syscall.SysProcAttr // Process is the underlying process, once started. Process *os.Process // ProcessState contains information about an exited process. // If the process was started successfully, Wait or Run will // populate its ProcessState when the command completes. ProcessState *os.ProcessState // ctx is the context passed to CommandContext, if any. ctx context.Context Err error // LookPath error, if any. // If Cancel is non-nil, the command must have been created with // CommandContext and Cancel will be called when the command's // Context is done. By default, CommandContext sets Cancel to // call the Kill method on the command's Process. // // Typically a custom Cancel will send a signal to the command's // Process, but it may instead take other actions to initiate cancellation, // such as closing a stdin or stdout pipe or sending a shutdown request on a // network socket. // // If the command exits with a success status after Cancel is // called, and Cancel does not return an error equivalent to // os.ErrProcessDone, then Wait and similar methods will return a non-nil // error: either an error wrapping the one returned by Cancel, // or the error from the Context. // (If the command exits with a non-success status, or Cancel // returns an error that wraps os.ErrProcessDone, Wait and similar methods // continue to return the command's usual exit status.) // // If Cancel is set to nil, nothing will happen immediately when the command's // Context is done, but a nonzero WaitDelay will still take effect. That may // be useful, for example, to work around deadlocks in commands that do not // support shutdown signals but are expected to always finish quickly. // // Cancel will not be called if Start returns a non-nil error. Cancel func() error // If WaitDelay is non-zero, it bounds the time spent waiting on two sources // of unexpected delay in Wait: a child process that fails to exit after the // associated Context is canceled, and a child process that exits but leaves // its I/O pipes unclosed. // // The WaitDelay timer starts when either the associated Context is done or a // call to Wait observes that the child process has exited, whichever occurs // first. When the delay has elapsed, the command shuts down the child process // and/or its I/O pipes. // // If the child process has failed to exit — perhaps because it ignored or // failed to receive a shutdown signal from a Cancel function, or because no // Cancel function was set — then it will be terminated using os.Process.Kill. // // Then, if the I/O pipes communicating with the child process are still open, // those pipes are closed in order to unblock any goroutines currently blocked // on Read or Write calls. // // If pipes are closed due to WaitDelay, no Cancel call has occurred, // and the command has otherwise exited with a successful status, Wait and // similar methods will return ErrWaitDelay instead of nil. // // If WaitDelay is zero (the default), I/O pipes will be read until EOF, // which might not occur until orphaned subprocesses of the command have // also closed their descriptors for the pipes. WaitDelay time.Duration // childIOFiles holds closers for any of the child process's // stdin, stdout, and/or stderr files that were opened by the Cmd itself // (not supplied by the caller). These should be closed as soon as they // are inherited by the child process. childIOFiles []io.Closer // parentIOPipes holds closers for the parent's end of any pipes // connected to the child's stdin, stdout, and/or stderr streams // that were opened by the Cmd itself (not supplied by the caller). // These should be closed after Wait sees the command and copying // goroutines exit, or after WaitDelay has expired. parentIOPipes []io.Closer // goroutine holds a set of closures to execute to copy data // to and/or from the command's I/O pipes. goroutine []func() error // If goroutineErr is non-nil, it receives the first error from a copying // goroutine once all such goroutines have completed. // goroutineErr is set to nil once its error has been received. goroutineErr <-chan error // If ctxResult is non-nil, it receives the result of watchCtx exactly once. ctxResult <-chan ctxResult // The stack saved when the Command was created, if GODEBUG contains // execwait=2. Used for debugging leaks. createdByStack []byte // For a security release long ago, we created x/sys/execabs, // which manipulated the unexported lookPathErr error field // in this struct. For Go 1.19 we exported the field as Err error, // above, but we have to keep lookPathErr around for use by // old programs building against new toolchains. // The String and Start methods look for an error in lookPathErr // in preference to Err, to preserve the errors that execabs sets. // // In general we don't guarantee misuse of reflect like this, // but the misuse of reflect was by us, the best of various bad // options to fix the security problem, and people depend on // those old copies of execabs continuing to work. // The result is that we have to leave this variable around for the // rest of time, a compatibility scar. // // See https://go.dev/blog/path-security // and https://go.dev/issue/43724 for more context. lookPathErr error } // A ctxResult reports the result of watching the Context associated with a // running command (and sending corresponding signals if needed). type ctxResult struct { err error // If timer is non-nil, it expires after WaitDelay has elapsed after // the Context is done. // // (If timer is nil, that means that the Context was not done before the // command completed, or no WaitDelay was set, or the WaitDelay already // expired and its effect was already applied.) timer *time.Timer } var execwait = godebug.New("#execwait") var execerrdot = godebug.New("execerrdot") // Command returns the Cmd struct to execute the named program with // the given arguments. // // It sets only the Path and Args in the returned structure. // // If name contains no path separators, Command uses LookPath to // resolve name to a complete path if possible. Otherwise it uses name // directly as Path. // // The returned Cmd's Args field is constructed from the command name // followed by the elements of arg, so arg should not include the // command name itself. For example, Command("echo", "hello"). // Args[0] is always name, not the possibly resolved Path. // // On Windows, processes receive the whole command line as a single string // and do their own parsing. Command combines and quotes Args into a command // line string with an algorithm compatible with applications using // CommandLineToArgvW (which is the most common way). Notable exceptions are // msiexec.exe and cmd.exe (and thus, all batch files), which have a different // unquoting algorithm. In these or other similar cases, you can do the // quoting yourself and provide the full command line in SysProcAttr.CmdLine, // leaving Args empty. func Command(name string, arg ...string) *Cmd { cmd := &Cmd{ Path: name, Args: append([]string{name}, arg...), } if v := execwait.Value(); v != "" { if v == "2" { // Obtain the caller stack. (This is equivalent to runtime/debug.Stack, // copied to avoid importing the whole package.) stack := make([]byte, 1024) for { n := runtime.Stack(stack, false) if n < len(stack) { stack = stack[:n] break } stack = make([]byte, 2*len(stack)) } if i := bytes.Index(stack, []byte("\nos/exec.Command(")); i >= 0 { stack = stack[i+1:] } cmd.createdByStack = stack } runtime.SetFinalizer(cmd, func(c *Cmd) { if c.Process != nil && c.ProcessState == nil { debugHint := "" if c.createdByStack == nil { debugHint = " (set GODEBUG=execwait=2 to capture stacks for debugging)" } else { os.Stderr.WriteString("GODEBUG=execwait=2 detected a leaked exec.Cmd created by:\n") os.Stderr.Write(c.createdByStack) os.Stderr.WriteString("\n") debugHint = "" } panic("exec: Cmd started a Process but leaked without a call to Wait" + debugHint) } }) } if filepath.Base(name) == name { lp, err := LookPath(name) if lp != "" { // Update cmd.Path even if err is non-nil. // If err is ErrDot (especially on Windows), lp may include a resolved // extension (like .exe or .bat) that should be preserved. cmd.Path = lp } if err != nil { cmd.Err = err } } else if runtime.GOOS == "windows" && filepath.IsAbs(name) { // We may need to add a filename extension from PATHEXT // or verify an extension that is already present. // Since the path is absolute, its extension should be unambiguous // and independent of cmd.Dir, and we can go ahead and update cmd.Path to // reflect it. // // Note that we cannot add an extension here for relative paths, because // cmd.Dir may be set after we return from this function and that may cause // the command to resolve to a different extension. lp, err := lookExtensions(name, "") if lp != "" { cmd.Path = lp } if err != nil { cmd.Err = err } } return cmd } // CommandContext is like Command but includes a context. // // The provided context is used to interrupt the process // (by calling cmd.Cancel or os.Process.Kill) // if the context becomes done before the command completes on its own. // // CommandContext sets the command's Cancel function to invoke the Kill method // on its Process, and leaves its WaitDelay unset. The caller may change the // cancellation behavior by modifying those fields before starting the command. func CommandContext(ctx context.Context, name string, arg ...string) *Cmd { if ctx == nil { panic("nil Context") } cmd := Command(name, arg...) cmd.ctx = ctx cmd.Cancel = func() error { return cmd.Process.Kill() } return cmd } // String returns a human-readable description of c. // It is intended only for debugging. // In particular, it is not suitable for use as input to a shell. // The output of String may vary across Go releases. func (c *Cmd) String() string { if c.Err != nil || c.lookPathErr != nil { // failed to resolve path; report the original requested path (plus args) return strings.Join(c.Args, " ") } // report the exact executable path (plus args) b := new(strings.Builder) b.WriteString(c.Path) for _, a := range c.Args[1:] { b.WriteByte(' ') b.WriteString(a) } return b.String() } // interfaceEqual protects against panics from doing equality tests on // two interfaces with non-comparable underlying types. func interfaceEqual(a, b any) bool { defer func() { recover() }() return a == b } func (c *Cmd) argv() []string { if len(c.Args) > 0 { return c.Args } return []string{c.Path} } func (c *Cmd) childStdin() (*os.File, error) { if c.Stdin == nil { f, err := os.Open(os.DevNull) if err != nil { return nil, err } c.childIOFiles = append(c.childIOFiles, f) return f, nil } if f, ok := c.Stdin.(*os.File); ok { return f, nil } pr, pw, err := os.Pipe() if err != nil { return nil, err } c.childIOFiles = append(c.childIOFiles, pr) c.parentIOPipes = append(c.parentIOPipes, pw) c.goroutine = append(c.goroutine, func() error { _, err := io.Copy(pw, c.Stdin) if skipStdinCopyError(err) { err = nil } if err1 := pw.Close(); err == nil { err = err1 } return err }) return pr, nil } func (c *Cmd) childStdout() (*os.File, error) { return c.writerDescriptor(c.Stdout) } func (c *Cmd) childStderr(childStdout *os.File) (*os.File, error) { if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) { return childStdout, nil } return c.writerDescriptor(c.Stderr) } // writerDescriptor returns an os.File to which the child process // can write to send data to w. // // If w is nil, writerDescriptor returns a File that writes to os.DevNull. func (c *Cmd) writerDescriptor(w io.Writer) (*os.File, error) { if w == nil { f, err := os.OpenFile(os.DevNull, os.O_WRONLY, 0) if err != nil { return nil, err } c.childIOFiles = append(c.childIOFiles, f) return f, nil } if f, ok := w.(*os.File); ok { return f, nil } pr, pw, err := os.Pipe() if err != nil { return nil, err } c.childIOFiles = append(c.childIOFiles, pw) c.parentIOPipes = append(c.parentIOPipes, pr) c.goroutine = append(c.goroutine, func() error { _, err := io.Copy(w, pr) pr.Close() // in case io.Copy stopped due to write error return err }) return pw, nil } func closeDescriptors(closers []io.Closer) { for _, fd := range closers { fd.Close() } } // Run starts the specified command and waits for it to complete. // // The returned error is nil if the command runs, has no problems // copying stdin, stdout, and stderr, and exits with a zero exit // status. // // If the command starts but does not complete successfully, the error is of // type *ExitError. Other error types may be returned for other situations. // // If the calling goroutine has locked the operating system thread // with runtime.LockOSThread and modified any inheritable OS-level // thread state (for example, Linux or Plan 9 name spaces), the new // process will inherit the caller's thread state. func (c *Cmd) Run() error { if err := c.Start(); err != nil { return err } return c.Wait() } // Start starts the specified command but does not wait for it to complete. // // If Start returns successfully, the c.Process field will be set. // // After a successful call to Start the Wait method must be called in // order to release associated system resources. func (c *Cmd) Start() error { // Check for doubled Start calls before we defer failure cleanup. If the prior // call to Start succeeded, we don't want to spuriously close its pipes. if c.Process != nil { return errors.New("exec: already started") } started := false defer func() { closeDescriptors(c.childIOFiles) c.childIOFiles = nil if !started { closeDescriptors(c.parentIOPipes) c.parentIOPipes = nil } }() if c.Path == "" && c.Err == nil && c.lookPathErr == nil { c.Err = errors.New("exec: no command") } if c.Err != nil || c.lookPathErr != nil { if c.lookPathErr != nil { return c.lookPathErr } return c.Err } lp := c.Path if runtime.GOOS == "windows" && !filepath.IsAbs(c.Path) { // If c.Path is relative, we had to wait until now // to resolve it in case c.Dir was changed. // (If it is absolute, we already resolved its extension in Command // and shouldn't need to do so again.) // // Unfortunately, we cannot write the result back to c.Path because programs // may assume that they can call Start concurrently with reading the path. // (It is safe and non-racy to do so on Unix platforms, and users might not // test with the race detector on all platforms; // see https://go.dev/issue/62596.) // // So we will pass the fully resolved path to os.StartProcess, but leave // c.Path as is: missing a bit of logging information seems less harmful // than triggering a surprising data race, and if the user really cares // about that bit of logging they can always use LookPath to resolve it. var err error lp, err = lookExtensions(c.Path, c.Dir) if err != nil { return err } } if c.Cancel != nil && c.ctx == nil { return errors.New("exec: command with a non-nil Cancel was not created with CommandContext") } if c.ctx != nil { select { case <-c.ctx.Done(): return c.ctx.Err() default: } } childFiles := make([]*os.File, 0, 3+len(c.ExtraFiles)) stdin, err := c.childStdin() if err != nil { return err } childFiles = append(childFiles, stdin) stdout, err := c.childStdout() if err != nil { return err } childFiles = append(childFiles, stdout) stderr, err := c.childStderr(stdout) if err != nil { return err } childFiles = append(childFiles, stderr) childFiles = append(childFiles, c.ExtraFiles...) env, err := c.environ() if err != nil { return err } c.Process, err = os.StartProcess(lp, c.argv(), &os.ProcAttr{ Dir: c.Dir, Files: childFiles, Env: env, Sys: c.SysProcAttr, }) if err != nil { return err } started = true // Don't allocate the goroutineErr channel unless there are goroutines to start. if len(c.goroutine) > 0 { goroutineErr := make(chan error, 1) c.goroutineErr = goroutineErr type goroutineStatus struct { running int firstErr error } statusc := make(chan goroutineStatus, 1) statusc <- goroutineStatus{running: len(c.goroutine)} for _, fn := range c.goroutine { go func(fn func() error) { err := fn() status := <-statusc if status.firstErr == nil { status.firstErr = err } status.running-- if status.running == 0 { goroutineErr <- status.firstErr } else { statusc <- status } }(fn) } c.goroutine = nil // Allow the goroutines' closures to be GC'd when they complete. } // If we have anything to do when the command's Context expires, // start a goroutine to watch for cancellation. // // (Even if the command was created by CommandContext, a helper library may // have explicitly set its Cancel field back to nil, indicating that it should // be allowed to continue running after cancellation after all.) if (c.Cancel != nil || c.WaitDelay != 0) && c.ctx != nil && c.ctx.Done() != nil { resultc := make(chan ctxResult) c.ctxResult = resultc go c.watchCtx(resultc) } return nil } // watchCtx watches c.ctx until it is able to send a result to resultc. // // If c.ctx is done before a result can be sent, watchCtx calls c.Cancel, // and/or kills cmd.Process it after c.WaitDelay has elapsed. // // watchCtx manipulates c.goroutineErr, so its result must be received before // c.awaitGoroutines is called. func (c *Cmd) watchCtx(resultc chan<- ctxResult) { select { case resultc <- ctxResult{}: return case <-c.ctx.Done(): } var err error if c.Cancel != nil { if interruptErr := c.Cancel(); interruptErr == nil { // We appear to have successfully interrupted the command, so any // program behavior from this point may be due to ctx even if the // command exits with code 0. err = c.ctx.Err() } else if errors.Is(interruptErr, os.ErrProcessDone) { // The process already finished: we just didn't notice it yet. // (Perhaps c.Wait hadn't been called, or perhaps it happened to race with // c.ctx being cancelled.) Don't inject a needless error. } else { err = wrappedError{ prefix: "exec: canceling Cmd", err: interruptErr, } } } if c.WaitDelay == 0 { resultc <- ctxResult{err: err} return } timer := time.NewTimer(c.WaitDelay) select { case resultc <- ctxResult{err: err, timer: timer}: // c.Process.Wait returned and we've handed the timer off to c.Wait. // It will take care of goroutine shutdown from here. return case <-timer.C: } killed := false if killErr := c.Process.Kill(); killErr == nil { // We appear to have killed the process. c.Process.Wait should return a // non-nil error to c.Wait unless the Kill signal races with a successful // exit, and if that does happen we shouldn't report a spurious error, // so don't set err to anything here. killed = true } else if !errors.Is(killErr, os.ErrProcessDone) { err = wrappedError{ prefix: "exec: killing Cmd", err: killErr, } } if c.goroutineErr != nil { select { case goroutineErr := <-c.goroutineErr: // Forward goroutineErr only if we don't have reason to believe it was // caused by a call to Cancel or Kill above. if err == nil && !killed { err = goroutineErr } default: // Close the child process's I/O pipes, in case it abandoned some // subprocess that inherited them and is still holding them open // (see https://go.dev/issue/23019). // // We close the goroutine pipes only after we have sent any signals we're // going to send to the process (via Signal or Kill above): if we send // SIGKILL to the process, we would prefer for it to die of SIGKILL, not // SIGPIPE. (However, this may still cause any orphaned subprocesses to // terminate with SIGPIPE.) closeDescriptors(c.parentIOPipes) // Wait for the copying goroutines to finish, but report ErrWaitDelay for // the error: any other error here could result from closing the pipes. _ = <-c.goroutineErr if err == nil { err = ErrWaitDelay } } // Since we have already received the only result from c.goroutineErr, // set it to nil to prevent awaitGoroutines from blocking on it. c.goroutineErr = nil } resultc <- ctxResult{err: err} } // An ExitError reports an unsuccessful exit by a command. type ExitError struct { *os.ProcessState // Stderr holds a subset of the standard error output from the // Cmd.Output method if standard error was not otherwise being // collected. // // If the error output is long, Stderr may contain only a prefix // and suffix of the output, with the middle replaced with // text about the number of omitted bytes. // // Stderr is provided for debugging, for inclusion in error messages. // Users with other needs should redirect Cmd.Stderr as needed. Stderr []byte } func (e *ExitError) Error() string { return e.ProcessState.String() } // Wait waits for the command to exit and waits for any copying to // stdin or copying from stdout or stderr to complete. // // The command must have been started by Start. // // The returned error is nil if the command runs, has no problems // copying stdin, stdout, and stderr, and exits with a zero exit // status. // // If the command fails to run or doesn't complete successfully, the // error is of type *ExitError. Other error types may be // returned for I/O problems. // // If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits // for the respective I/O loop copying to or from the process to complete. // // Wait releases any resources associated with the Cmd. func (c *Cmd) Wait() error { if c.Process == nil { return errors.New("exec: not started") } if c.ProcessState != nil { return errors.New("exec: Wait was already called") } state, err := c.Process.Wait() if err == nil && !state.Success() { err = &ExitError{ProcessState: state} } c.ProcessState = state var timer *time.Timer if c.ctxResult != nil { watch := <-c.ctxResult timer = watch.timer // If c.Process.Wait returned an error, prefer that. // Otherwise, report any error from the watchCtx goroutine, // such as a Context cancellation or a WaitDelay overrun. if err == nil && watch.err != nil { err = watch.err } } if goroutineErr := c.awaitGoroutines(timer); err == nil { // Report an error from the copying goroutines only if the program otherwise // exited normally on its own. Otherwise, the copying error may be due to the // abnormal termination. err = goroutineErr } closeDescriptors(c.parentIOPipes) c.parentIOPipes = nil return err } // awaitGoroutines waits for the results of the goroutines copying data to or // from the command's I/O pipes. // // If c.WaitDelay elapses before the goroutines complete, awaitGoroutines // forcibly closes their pipes and returns ErrWaitDelay. // // If timer is non-nil, it must send to timer.C at the end of c.WaitDelay. func (c *Cmd) awaitGoroutines(timer *time.Timer) error { defer func() { if timer != nil { timer.Stop() } c.goroutineErr = nil }() if c.goroutineErr == nil { return nil // No running goroutines to await. } if timer == nil { if c.WaitDelay == 0 { return <-c.goroutineErr } select { case err := <-c.goroutineErr: // Avoid the overhead of starting a timer. return err default: } // No existing timer was started: either there is no Context associated with // the command, or c.Process.Wait completed before the Context was done. timer = time.NewTimer(c.WaitDelay) } select { case <-timer.C: closeDescriptors(c.parentIOPipes) // Wait for the copying goroutines to finish, but ignore any error // (since it was probably caused by closing the pipes). _ = <-c.goroutineErr return ErrWaitDelay case err := <-c.goroutineErr: return err } } // Output runs the command and returns its standard output. // Any returned error will usually be of type *ExitError. // If c.Stderr was nil, Output populates ExitError.Stderr. func (c *Cmd) Output() ([]byte, error) { if c.Stdout != nil { return nil, errors.New("exec: Stdout already set") } var stdout bytes.Buffer c.Stdout = &stdout captureErr := c.Stderr == nil if captureErr { c.Stderr = &prefixSuffixSaver{N: 32 << 10} } err := c.Run() if err != nil && captureErr { if ee, ok := err.(*ExitError); ok { ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes() } } return stdout.Bytes(), err } // CombinedOutput runs the command and returns its combined standard // output and standard error. func (c *Cmd) CombinedOutput() ([]byte, error) { if c.Stdout != nil { return nil, errors.New("exec: Stdout already set") } if c.Stderr != nil { return nil, errors.New("exec: Stderr already set") } var b bytes.Buffer c.Stdout = &b c.Stderr = &b err := c.Run() return b.Bytes(), err } // StdinPipe returns a pipe that will be connected to the command's // standard input when the command starts. // The pipe will be closed automatically after Wait sees the command exit. // A caller need only call Close to force the pipe to close sooner. // For example, if the command being run will not exit until standard input // is closed, the caller must close the pipe. func (c *Cmd) StdinPipe() (io.WriteCloser, error) { if c.Stdin != nil { return nil, errors.New("exec: Stdin already set") } if c.Process != nil { return nil, errors.New("exec: StdinPipe after process started") } pr, pw, err := os.Pipe() if err != nil { return nil, err } c.Stdin = pr c.childIOFiles = append(c.childIOFiles, pr) c.parentIOPipes = append(c.parentIOPipes, pw) return pw, nil } // StdoutPipe returns a pipe that will be connected to the command's // standard output when the command starts. // // Wait will close the pipe after seeing the command exit, so most callers // need not close the pipe themselves. It is thus incorrect to call Wait // before all reads from the pipe have completed. // For the same reason, it is incorrect to call Run when using StdoutPipe. // See the example for idiomatic usage. func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { if c.Stdout != nil { return nil, errors.New("exec: Stdout already set") } if c.Process != nil { return nil, errors.New("exec: StdoutPipe after process started") } pr, pw, err := os.Pipe() if err != nil { return nil, err } c.Stdout = pw c.childIOFiles = append(c.childIOFiles, pw) c.parentIOPipes = append(c.parentIOPipes, pr) return pr, nil } // StderrPipe returns a pipe that will be connected to the command's // standard error when the command starts. // // Wait will close the pipe after seeing the command exit, so most callers // need not close the pipe themselves. It is thus incorrect to call Wait // before all reads from the pipe have completed. // For the same reason, it is incorrect to use Run when using StderrPipe. // See the StdoutPipe example for idiomatic usage. func (c *Cmd) StderrPipe() (io.ReadCloser, error) { if c.Stderr != nil { return nil, errors.New("exec: Stderr already set") } if c.Process != nil { return nil, errors.New("exec: StderrPipe after process started") } pr, pw, err := os.Pipe() if err != nil { return nil, err } c.Stderr = pw c.childIOFiles = append(c.childIOFiles, pw) c.parentIOPipes = append(c.parentIOPipes, pr) return pr, nil } // prefixSuffixSaver is an io.Writer which retains the first N bytes // and the last N bytes written to it. The Bytes() methods reconstructs // it with a pretty error message. type prefixSuffixSaver struct { N int // max size of prefix or suffix prefix []byte suffix []byte // ring buffer once len(suffix) == N suffixOff int // offset to write into suffix skipped int64 // TODO(bradfitz): we could keep one large []byte and use part of it for // the prefix, reserve space for the '... Omitting N bytes ...' message, // then the ring buffer suffix, and just rearrange the ring buffer // suffix when Bytes() is called, but it doesn't seem worth it for // now just for error messages. It's only ~64KB anyway. } func (w *prefixSuffixSaver) Write(p []byte) (n int, err error) { lenp := len(p) p = w.fill(&w.prefix, p) // Only keep the last w.N bytes of suffix data. if overage := len(p) - w.N; overage > 0 { p = p[overage:] w.skipped += int64(overage) } p = w.fill(&w.suffix, p) // w.suffix is full now if p is non-empty. Overwrite it in a circle. for len(p) > 0 { // 0, 1, or 2 iterations. n := copy(w.suffix[w.suffixOff:], p) p = p[n:] w.skipped += int64(n) w.suffixOff += n if w.suffixOff == w.N { w.suffixOff = 0 } } return lenp, nil } // fill appends up to len(p) bytes of p to *dst, such that *dst does not // grow larger than w.N. It returns the un-appended suffix of p. func (w *prefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) { if remain := w.N - len(*dst); remain > 0 { add := min(len(p), remain) *dst = append(*dst, p[:add]...) p = p[add:] } return p } func (w *prefixSuffixSaver) Bytes() []byte { if w.suffix == nil { return w.prefix } if w.skipped == 0 { return append(w.prefix, w.suffix...) } var buf bytes.Buffer buf.Grow(len(w.prefix) + len(w.suffix) + 50) buf.Write(w.prefix) buf.WriteString("\n... omitting ") buf.WriteString(strconv.FormatInt(w.skipped, 10)) buf.WriteString(" bytes ...\n") buf.Write(w.suffix[w.suffixOff:]) buf.Write(w.suffix[:w.suffixOff]) return buf.Bytes() } // environ returns a best-effort copy of the environment in which the command // would be run as it is currently configured. If an error occurs in computing // the environment, it is returned alongside the best-effort copy. func (c *Cmd) environ() ([]string, error) { var err error env := c.Env if env == nil { env, err = execenv.Default(c.SysProcAttr) if err != nil { env = os.Environ() // Note that the non-nil err is preserved despite env being overridden. } if c.Dir != "" { switch runtime.GOOS { case "windows", "plan9": // Windows and Plan 9 do not use the PWD variable, so we don't need to // keep it accurate. default: // On POSIX platforms, PWD represents “an absolute pathname of the // current working directory.” Since we are changing the working // directory for the command, we should also update PWD to reflect that. // // Unfortunately, we didn't always do that, so (as proposed in // https://go.dev/issue/50599) to avoid unintended collateral damage we // only implicitly update PWD when Env is nil. That way, we're much // less likely to override an intentional change to the variable. if pwd, absErr := filepath.Abs(c.Dir); absErr == nil { env = append(env, "PWD="+pwd) } else if err == nil { err = absErr } } } } env, dedupErr := dedupEnv(env) if err == nil { err = dedupErr } return addCriticalEnv(env), err } // Environ returns a copy of the environment in which the command would be run // as it is currently configured. func (c *Cmd) Environ() []string { // Intentionally ignore errors: environ returns a best-effort environment no matter what. env, _ := c.environ() return env } // dedupEnv returns a copy of env with any duplicates removed, in favor of // later values. // Items not of the normal environment "key=value" form are preserved unchanged. // Except on Plan 9, items containing NUL characters are removed, and // an error is returned along with the remaining values. func dedupEnv(env []string) ([]string, error) { return dedupEnvCase(runtime.GOOS == "windows", runtime.GOOS == "plan9", env) } // dedupEnvCase is dedupEnv with a case option for testing. // If caseInsensitive is true, the case of keys is ignored. // If nulOK is false, items containing NUL characters are allowed. func dedupEnvCase(caseInsensitive, nulOK bool, env []string) ([]string, error) { // Construct the output in reverse order, to preserve the // last occurrence of each key. var err error out := make([]string, 0, len(env)) saw := make(map[string]bool, len(env)) for n := len(env); n > 0; n-- { kv := env[n-1] // Reject NUL in environment variables to prevent security issues (#56284); // except on Plan 9, which uses NUL as os.PathListSeparator (#56544). if !nulOK && strings.IndexByte(kv, 0) != -1 { err = errors.New("exec: environment variable contains NUL") continue } i := strings.Index(kv, "=") if i == 0 { // We observe in practice keys with a single leading "=" on Windows. // TODO(#49886): Should we consume only the first leading "=" as part // of the key, or parse through arbitrarily many of them until a non-"="? i = strings.Index(kv[1:], "=") + 1 } if i < 0 { if kv != "" { // The entry is not of the form "key=value" (as it is required to be). // Leave it as-is for now. // TODO(#52436): should we strip or reject these bogus entries? out = append(out, kv) } continue } k := kv[:i] if caseInsensitive { k = strings.ToLower(k) } if saw[k] { continue } saw[k] = true out = append(out, kv) } // Now reverse the slice to restore the original order. for i := 0; i < len(out)/2; i++ { j := len(out) - i - 1 out[i], out[j] = out[j], out[i] } return out, err } // addCriticalEnv adds any critical environment variables that are required // (or at least almost always required) on the operating system. // Currently this is only used for Windows. func addCriticalEnv(env []string) []string { if runtime.GOOS != "windows" { return env } for _, kv := range env { k, _, ok := strings.Cut(kv, "=") if !ok { continue } if strings.EqualFold(k, "SYSTEMROOT") { // We already have it. return env } } return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) } // ErrDot indicates that a path lookup resolved to an executable // in the current directory due to ‘.’ being in the path, either // implicitly or explicitly. See the package documentation for details. // // Note that functions in this package do not return ErrDot directly. // Code should use errors.Is(err, ErrDot), not err == ErrDot, // to test whether a returned error err is due to this condition. var ErrDot = errors.New("cannot run executable found relative to current directory")