hA@X #AX # T LX # NX # "PX #bX #qdX #NgX # hX #!"#$jX #%&@lX #'(lX #X #)*+,-.X #/01234AZ #5PX #6X #7 )X #89:;<=>@nX #D~X #EF*X #GHIJKLMOX #S~ Y #TUVY #WY #X Y #YY #Z[\i Y #]^_`1 Y #abc#Y #defg Y #hijkr#Y #lmnopql (Y #rst -Y #uvwxyzN7Y #{|}~=Y #&AY #0IY #OY # SY # WY #[Y #$_Y #cY #>hY #:lY #pY #otY #2zY #Y #Y #'Y #>eY #    Y #!Y #"#$%&eY #'O Y #()*+IY #,-./01P Y #234Y #56789:;Y #<cY #=>Y #?@ Y #ABC Y #DEF$OY #GHIJKLMOXY #\Y #]^Y #_`Z #aZ #bcdefg...bincommands...sttysusumtailtartee time touch tr true uniqwc0  ܋@ã PSQP+& PtP+P, PtP+P~u j+P$ #$ @F7$ F7-$ $ ;F|ո& P tP+P, PtP+P+PV>* F+PF% PPF%PPF% PPF%PuPF%Pd` Pa) Pi PL( Ps P7, Pw{ P"- Pb P }+>~t^" ^, PN+ Pvt &*  Pvt &*  Pvt &*  Pvyt &* f Pv_t * L PvEt * 2 Pv+t *  Pvt *  Pvt *  Pvt &* Pvt-^) ^( ^, ^- $ Pvu̸ PvtuŸ Pvcu PvRt+*  ) @( , - . / 0  P'v Px+9^?u^?u ]+^?t^?t^^;uFF+~ } F@P ~u PFP P++PPPPPvP+P"F: F6 F-t= v* ^G*䙉FVG*䙉FVVF F V< > ^G@ B 6PPFFI^*䙉FVG*䙉FVG*䙉FVG*䙉FVG*䙉FމVG*䙉FډV܋VFv^ ֋v^ ֋v^+ ֣< > VF޹v܋^+ 6PPF> < *+ҋ^G> < +*+ҋ^G@ G6PPF> < *+ҋ^> < *+ҋ^G> < *+ҋ^G> < +*+ҋ^GB @ *+ҋ^GB @ *+ҋ^G5FJ ' 6 L FFK%PGP2=9?ƺ 0‹ ^FFPG=to=%u+G=0}=ct=su^FFF FPT^FFuGF+FH+ЉV~FNt P -L PL PPS+H> s  F j*FFF^?u+FPvP;++PPvPvvPP+F6 F 8 F : F< F> F@ vvT+v }>6 F8 F : < ~^ FF OuvvPF4 2 PvFu>4 |4 4 أJ V++FG?uD:[UWV+;& r4 6 8 <  2 PPf^_] U싆 ]6 ; B F J O U V W Z tabscbreakraw-nlecho-tabsnl-echo kill = erase = int = quit = %s %s -tabs-raw-cbreak-echo-nltabsrawcbreakechonlkilleraseintquitdefaultunknown mode: ^%cDEL%csOrrrrrrrStack overflow 0 # ܋@ã PSQP<T F ~~^ Wu% P W  P P\?uPu P FPtP+PSF%FFP tP+P9PFP+P FFVJ‹68 PF FFP tP+PtFP8Pt tP& P.t t \ ?tD Fv P PC  F^GtGuGt PFP^7 F^GA^GGH؊F^GG=|%Guww7 F^GGF~t7~~ ^G;Ft~} ^O^O} ^G+H0 +FNjGC|^uG^G+™V+s}v+^t+V׋޹ӋڈF|ЋǙFǙF؊Ft+V׋ڈG8FG^?u^t+F^Gt+FFt+F$AFNj؊V׋ڈGO}FFFNu+ƅ^+ǺVƋ؀?t +^F|ր^0^9~^^Z~^G |^\G]i\ + PFPvK u FF^F?u^7FPv +I Pvvp 0 dždžFF?t?udž‰V;r$F9rH؋dž@+Љ‰^F?u;|dž`+Љ‰^F?t F9rݸ ;|+J™鉆+PPv+PvWP;P+P뎸ZFFFF+PFPv+PPvP;P+PIY++PPPPPvP+P)9+>z|+P+RP6z+PjPz|z+>z| 6zz|+>z} }+bxv.|PvP6z|~vvvxvxv? uv|xxv\+xx?:ux>+^u+-x~x6x6xxxx~뮸Ftv7u~tF+gf]Ft ؋G;Fu~tF{+6+FG= t= t= t= t= t=-uGF ƺ vG-0F= r~t ++PPPPPvPP+PPPPPPP+PF"FFF-t= v*^G*䙉FVG*䙉FVVF F V^G6PPFFA^*䙉FVG*䙉FVG*䙉FVG*䙉FVG*䙉FމVG*䙉FډV܋VFv^ ֋v^ ֋v^+ ֣VF޹v܋^+ 6PPF*+ҋ^G+*+ҋ^GG6PPF*+ҋ^*+ҋ^G*+ҋ^G+*+ҋ^G*+ҋ^G*+ҋ^G5F'.FVFF PPFt6+vvPP8+PPvPvvPPF++PPPPPv.P+P++PPPPPvP+P+iF;u G?u+{N+*FFF^?u+FPvP;++PPvPvvPP+FF F FFFvvT+v }>FF ~^ FF OuvvPFPvFu>| أV++FG?uD:[UWV+;&rPPf^_] U싆 ]/bin/shrootUnknown id: Password: Sorry No shell B */etc/passwd7  6 6 6 6 6 6 6 q Stack overflow 0T܋@ãPSQP\F^?u}Fv^?-u^uF+P^7\F~u^7PL(~~^+Pv_~t vF^?u6+sP<v3~t v$P~ >dždžPPv~Ldž;}֋t+‰؊*䉆뺃}#~tv+PP5JPP>+PPP#~t vPPOFFF]~u~u.F+ҹ 0F^+^_Ë؈F+ҹ F ~t0 V^+^_ӋڈFF;F|FFFPPc++PPPPPvP+P++PPPPPvPP+{vvPP ^ FFK%PGP2=9?ƺ 0‹ ^FFPG=to=%u+G=0}=ct=su^FFF FPT^FFuGF+FH+ЉV~FNt Pꡊ- P PP{+p>s FR+PPvPvvPP]Fj*FFF^?u+FPvP;++PPvPvvPP+FF F FFFvvT+v }>FF ~^ FF OuvvPFPvFu>| أV++FG?uD:[UWV+;&rPPf^_] U싆 ]-can't open sum: read error on read error %s %sStack overflow 0 n6܋@ãPSQP *P6@ NF~F~uv6>+P^F؀?-t؀?+uqF^?0|6?91^7F~<^?9 F^?0}^?ct׀?lt?tPP6BFNF~}P6BP7~uv6>GP^7Fu^7 P6B8Pvvvp+PF^? t? t? tF?+t ?-uFFF$^?9$F -0FF^?0}ԋFn eF~~o>~tMvF=t= uFF;F|ߋF;F}vsF=u6@PvR=tFF;F|빋F؉FFFF&mFF;Fu;FrFF>~t~ uFF;F~;FF>~uF F;FsF^? uF;FrFFvF=t:^;FssFnF6@^PF;FsFF;FuI + v5 + +ヿ>t>G| + FPvv^G@tS + FPv6@@G@tSt +u + G}F;>uLJ>}v7^7^G tt w v +렸 F+(|"P=wuKNPvdF|2gGヿ>u͋^=auNPvR F}$+=ruN+Pv0 F}ܸP++RPvP PFtG؋FFGP^GuO^O ^GGF>FG  ^GuGu+0^~ww7 F^;GuGGGF ^O ^Gt`^Gto[Gt PFP P^w^7 ^GuO몋^O렋F*o ^GG^GuGGH؊+ ^tG t w^gFGuO^GGG v=Du =Ou$=Xu'=cu*v%P<vGP,L=9~-0nF܋F F܉F\G=0}d=9~\F 0‰FԃDFVF FPvvvUvFPPFPvvFPDFV+뱃DFV}+҉FVF뜃DFV}+҉FVF{TDdTD뻃TDЃDFvFP(DFvP)PFPvvv3 G=tt=%tFFFF G=-uFG=0uF0G=0|v=.u=du=ou=suq=uu=xuF~u~u ^ 0G~ u~}VF؃FVF+FNjG |+~ uN+Ҹ RPvvFFNj؋FFNj؊FV+Ҹ RPVF+FVRPlFV~u-VF%+ҍV׋ڈVFFV~u-VF%+ҍV׋ڈVFFVG~t<~t3FEDFƋ؀?u~u FƋ %FƋ؀? } FƋ؀0 FƋ؀7FN}~t FNj-GEFƋ؊^ F N}^ 7F F~~F ;F~FFFF~8NvF PoF;FFNtv^FPH^?uۃ~})~ 0u#v.P'FFvF PF9F|LF^GtGuGt PFP^7F^GA^GGH؊F^GG=|%Guww7F^GGF~t7~~ ^G;Ft~} ^O^O^G++{vvPP+_+PPPPPvP+Po+?+PPPPPvPPN^F.VF..F .PPFt&..+hF%-;>hr W}+>h>f%=uhhոF%F>fuqPfhWƩt%GFu Fu+;Fr)FF;s؉7F E vz95uvu+F-F%F%+FF Fu Fu+;Fr#FF;s؉7 F+vFtvPv%F+N^g}"FNt GFXָ+PPvPPPP+P Fu .j+!jFFjFPuF"F+PvvPPPBP+Pø.W +&3&u=u_+[vvPP~>+PPvPvvPPIFV++FG?u;++PPvPvvPP+F.F .F .F.F.F.vvT+v }>.F.F ..~^ FF OuvvPF..PvFu>.|. .أ.V++FG?uD:[UWV+;&lr....n.PPf^_] U싆 ]UW+VF^ Ny ؃ׅy كSt؃_]UW+VF^ Ny ؃ׅyكӋt؃_]u؋+ʋ+UWV+u&GW݊*ɋ*ɊĊ*RPQ;r WWRP+_+ƃ^+X+y Mϋ_t͊ߊ+^_]tail: unknown option %c Usage: tail [+/-[number][lc]] [files] rtail: can't open %s &&B** *4.Stack overflow  q#@أPSQ<P U~tv2Pv*P1P 1P^P ^]UPP~} 1PP^^^GF^?t;^0P#<#:>1PPy^^ZF뽠:0P<0[à>0=t 1PPA^^><t^PwR ^^P^1Pw| ^^P8>8}^w4P^^><t,FF9F}F^7^Fd1P^1P ^]UPP@P68$>@u1P+PP^^Fve[9t 1PBPn^^PX]UPP uF@>:t:vw^ t&FF^?tFFHv^cv^Zv^P1P>1uPbP1P0 PP^^RP1PPGPpP1Py1P^K]UP PP^^RP1PPFvNX tP8P68 ]UP>1u>vPz ^^ }vPP1PvPP1P]øPv0^^F~}vP1P]ø PP^^RPv68v- v ^PP^^RPv1Pz^]UF ^ SP1PP FvvP1P0vNX tiP8Pv F ^ -u!tC ~Pv F89^uPv8PvF^ N )щ^ N 댉]U FFFF9F}W^^0=0|B^^0=72F^F^^^0-0FVFVF롋FV]UPPg F~} 1PP\^^~u 1PvPP1PP6^^1P ^F~tF9Fu]UFF~s ^ FF@~@svvF[0[É^F]UvF[?t^/t1PPX]UvPPpPLp]UPF^?tF~u8vF[?/t^?/t ~tF^?/uF^@^?t(~8u 1P P^^vF[vFЋ^/F^]U0FPv^^ }vP1P]1Pv^^FЃ~}v,P1P^]ÍFPv^P^^P@P68 Ftvv68vv^P F@u}v0^ }v<P1Phv^PFPvPFPvPFPvn=u~tFP^ڸPP^1PI^TP^v^]UPF@vF[0^F t^G@tFH/^GG^G%PzPP^w~PP^w PP^wwPP^wwPP PPP]UPF@~@s ^F]UP@P68X6nnX=}P@P68868^]Uvvv9Ft 1PP]^^]UvvvJ9Ft 1PP6^^n]U~u6nPP]Ë^?tBvF[1PnP6[XX>uиPnPP붉]UF~ }?Fv[%0vBF^F^FF~ } +FƋ^B`F`]Ul^^~t1PPXF t^^FF^?u^?%tFvF[0P{^Fw^RP^^FFF0=}XFF0@F^w7^^FF2^RP^^F^?0uFFFZvF[0^F tFF,vF[vF^~tv^]Uv1P PP\]UvvPPA]UvvPP&]U@PFPvM]UP^^vF[?t^7FPv]U@Pvv]UdždžFF[?t[?tdžƍv9rPrdž9}q)؉vF[0 t'[^9rӸP녋dž9}p)؉vF[0 t&[^9rӸPc놋)H1PPv1Pv~^P;P1PPX]UPPFFFF1PFPv1PPv=^P;P1PR]U1PPPPPvP1P4]U1PPPPPPP1P]U1PPPPPvPP]U1PvvPv^Pv^P PP]UvvPP]UP1PPvPvvPPFF]UP1PvvPPvH^PPP\FF]UP1PPPPPPP1P9FHvF]U1PPvPvvPP]U^H^ J^ L^N^P^Rvvd^^]UPPv ^F^H^J^ LFN~ vNX tv F [vFvv^^]UP^FDPva^^F~tv>F}FۉBP6FX]UPFvF[0 tFF@]ù UF^ ]íI|9Эuu_9tt uu Zu1RPUW)V F^Ny ؃ׅy كt؃_]uÉ)щ)UWV)u&GW߈(ɉ͈(ɈԈ(RPQ9r WWRP)_)ǃ։^)ƃX)y M_t݈lj)^_]ø *ASPPRU^^`^b^f\PP\ ]Usage: tar [cxt] tarfile [files].ctx ID Ls d s9 %s %s Cannot open Tar: header checksum error.%s linked to %s %d tape blocks Cannot link %s to %s Linked %s to %s Cannot create %s %s, %d tape blocks Cannot fork()./bin/mkdirmkdirCannot find mkdir.%s%sPathname too longCannot find %s Cannot open %s Cannot chdir to %s .. Tar: unknown file type. Not added. %I %I %I %L %L %ITar: read error.Tar: write error.Error: Division by 0 Illegal EM instruct'n Err in EM case instr Variable out of range Err in EM set instr Floating pt not impl. Heap overflow 0R^| ܋@ãPSQP DFF&F!~~?^?-u5^G=au FFN=it̸PPodžt~~uP^7㉇}FP^7㉇})Pk^7`PVPNF|~tPPdž$~tP++RP;|ҸPP+P&~/dž;}PdžY;|+P"+vvPP++PPPPPvP+P+a+PPPPPvPPp@FFVFLNF HPPFtHNL+vvPPJ"+PPvPvvPPFFH㋇ZFFHFZFF~t~uFP0P+PF}FPSQRVWU܋KۋZ6DPXD]_^ZY[X ϸ*FFF^?u+FPvP;++PPvPvvPP+FFF HF JFLFNFPvvT+v }>FFHF JL~^ FF OuvvPFDBPvFu>D|D DأzV++FG?uD:[UWV+;& rDFHLBPPf^_] U싆 ]Usage: tee [-i] [-a] [files]. Cannot open output file: Stack overflow 0   ܋@ã PSQP,~u +PF ^G FP`F؅}& P2Pt~uBPPPPFPqFP;FuFPFt 3 PFP=+Ҹ<RPVҋF+FVRP>RPS PEVF+FVRPY P-VF+FVRP_ PFڹP  F ^Ƈ F~|KRPvvFKRPFRP)FV+ҸRPvvF+ҸRPFRP~)FV+Ҹ<RPvvF+Ҹ<RPFRPU)FV+ҸRPvv_Fv~t Pv^ :~u> t Pv? :~u> t Pv ! 0F0#  P7[F 0FF0V> u ~0uF ^FF^FF~~ D+m P\n PRt PH+G ؋U㉇& u& P~ P PP+~ GF=u> GF=u6 PM+U PFPvK{;FF^F?u^7FPvN+ Pvv6dždžFF?t?udž‰V;r$F9rH؋dž@+Љ‰^F?u;|dž`+Љ‰^F?t F9rݸ;|+J™鉆+PPv+PvP;P+PO뎸 FFFF+PFPv+PPvP;P+P++PPPPPvP+P++PPPPPPP+PFH㋇ FFHF F ~t~uFz 0P+PF}FPSQRVWU܋Kۋ 6 PX ]_^ZY[X ϸ+PPPPPP PP!F> |t أ  FV~t^WVF+PPPPPP+PPF^ W GW GW  G WFV+PPPPPPP+PhF^ Fj*FFF^?u+FPvP;++PPvPvvPP+F F F F F F vvT+v }> F F ~^ FF OuvvPF PvFu> | أ V++FG?uD:[UWV+;& r    PPf^_] U싆 ]UFfȋFf ȋFf]UW+VF^ Ny ؃ׅy كt؃_]u؋+ʋ+UWV+u&GW݊*ɋ*ɊĊ*RPQ;r WWRP+_+ƃ^+X+y Mϋ_t͊ߊ+^_] . e Cannot fork Command terminated abnormally. real user sys /bin/sh/bin//usr/bin//bin/shCannot execute /bin/sh Stack overflow 0DL,D܋@ãDPSQPF~uP&K+PFF؋FFPn~"HPv]PFF;F}F؋?-uFF؋ftՋFF؋ctsF븸0+PvuWFPv*F%F=t[++RP;FVF̉V΋VFFЉVҍFPvtt$ă>FtPvdF|P++_PPT+gvzP+Qvv!PPt+5vvPPX++PPPPPvP+P)9++PPPPPvPP (FFK%PGP2=9?ƺ 0‹ ^FFPG=to=%u+G=0}=ct=su^FFF FPT^FFuGF+FH+ЉV~FNt P(-PPP)+>((s (F( +PvvPPvPPPF+PPPPPP PPF>|tأ*FV~t^WVF+?v^WWGFPP:++PPvPvvPP+FF F FFFvvT+v }>FF ~^ FF OuvvPFPvFu>| أ*V++FG?uD:[UWV+;&~rPPf^_] U싆 ]touch: cannot touch Usage: touch [-c] file... %sStack overflow 0R$ 4܋@ãPSQP6F~~oFF؋?-u^FF؋@E=dt3=st5&PPPPx*=cu G=uFF^ÈƇƇF~~ߋFF؃?u PFFF7>t  PFF؃?tPFF7FF؃?tP PC *ƇG=u *ƇG=uFF;FuQP P+PpF36PP;t PPP+P *F؊*F>t tz>tF;Fu ^t^FF*>t?6PP;t PPPPt%<u *؊FF*F*ڈG=uGFF=0|6=71GV-0FF~} =0|=7~׋FFm=tjFaF[FFF-MGGFG?-u؋GF F*FFF;F~G=\u[=[tGF=uF~ *;tG=u=u*䍖VڈFF~ύFPvO+i+PPPPPvP+PyH+PPvPvvPPSF` ~FGuF:++PPvPvvPP+FF F "F$F&F(vvT+v }>F F "$~^ FF OuvvPFPvFu>| أ2V++FG?uD:[UWV+;&r $PPf^_] U싆 ]Usage: tr [-cds] [string1 [string2]]. Bad write Bad write Stack overflow 0\R2\܋@ã\PSQDP vv-FuhPT6P FFP6&^0|^^9S^@P dNF~^?-t ^?+t^?+u^@PM f뽋^uF뫋^@F,=ut4=du`^ ^`F^?ui=cub~uF&~u 6mP^F7N~uF 6doP^F7N6+PN b"dFE^? t? u F^?u^?uE^? t? t F^?u^?t%N~šfFFN~~^?uF+vzPvpPu++{>btvvqPE'>^t~t >`t~t vxPr2P6}+OF;v6~FFF66*tFP6(v61+{Pp FFF;F}36SF~^FF~ uˋ^FF+GFPvv^G@tS\+FPv6G@tSt0+ +!G}F;uLJ}v7^7b^G tt w9 v0 +렸 F+(|"P=wuKNPvdF|2gGヿu͋^=auNPv F}$+=ruN+Pv F}ܸP++RPv PMFtG؋FFGP(^GuO^O ^GGFF  ^GuGu+0^~ww7W F^;GuGGGFr ^O$ ^Gt`^Gto[Gt PFP P^w^7- ^GuO몋^O렋F* ^GG^GuGGH؊+ ^tG t w^gFGuO^GGG > v=Du =Ou$=Xu'=cu*v%P<vGP,L=9~-0nF܋F F܉F\G=0}d=9~\F 0‰FԃDFVF FPvvvUvFP( PFPvvFPDFV+뱃DFV}+҉FVF뜃DFV}+҉FVF{TDdTD뻃TDЃDFvFP(DFvPuPFPvvv3 G=tt=%tFFFF G=-uFG=0uF0G=0|v=.u=du=ou=suq=uu=xuf & F~u~u ^ 0G~ u~}VF؃FVF+FNjG |+~ uN+Ҹ RPvv` FFNj؋FFNj؊FV+Ҹ RPVF+FVRPFV~u-VF%+ҍV׋ڈVFFV~u-VF%+ҍV׋ڈVFFVG~t<~t3FEDFƋ؀?u~u FƋ %FƋ؀? } FƋ؀0 FƋ؀7FN}~t FNj-GEFƋ؊^ F N}^ sF F~~F ;F~FFFF~8NvF PoF;FFNtv^FPH^?uۃ~})~ 0u#v.P'FFvF PF9F| F^GtGuGt PFP^7F^GA^GGH؊F^GG=|%Guww7PF^GGF~t7~~ ^G;Ft~} ^O^OC^G++vvPPB++PPPPPvP+P+FG= t= t= t= t= t=-uGF ƺ vG-0F= r~t+M+PPPPPvPP\l,F*VF**F *PPFt4**+F%-;>r W}+>>%=uոF%F>uqPWƩt%GFu Fu+;Fr)FF;s؉7F E vzG5uvu+F-F%F%+FF Fu Fu+;Fr#FF;s؉7 F+vFtvPv%F+\^g"FNt GFf&ָ+PPvPPPP+P.Fu *+/FFFPuF"F+PvvPPPBP+Pø*W +&3&u=u_+ivvPP+M>*|>*"~ PUv]PvP"PPP*-P*PPPP FF^F?uF+PPvPvvPPF+F;u G?u+N++G+FG?uk*FFF^?u+FPvP;++PPvPvvPP+F*F *F *F*F*F*vvT+v }>*F*F **~^ FF OuvvPF**PvFu>*|* *أ*V++FG?uD:[UWV+;&r*****PPf^_] U싆 ]UW+VF^ Ny ؃ׅy كSt؃_]UW+VF^ Ny ؃ׅyكӋt؃_]u؋+ʋ+UWV+u&GW݊*ɋ*ɊĊ*RPQ;r WWRP+_+ƃ^+X+y Mϋ_t͊ߊ+^_]uniqrw%4d %s%sUsage: uniq [-udc] [+n] [-n] [input [output]] ""B&&*>FPjz*6L^j|*7M\hvError 0Not ownerNo such file or directoryNo such processInterrupted system callI/O errorNo such device or addressArg list too longExec format errorBad file numberNo childrenNo more processesNot enough corePermission deniedBad addressBlock device requiredMount device busyFile existsCross-device linkNo such deviceNot a directoryIs a directoryInvalid argumentFile table overflowToo many open filesNot a typewriterText file busyFile too largeNo space left on deviceIllegal seekRead-only file systemToo many linksBroken pipeMath argumentResult too largeInvalid errno : Stack overflow  ]@أPSQP U FHFF^GF~~JvF[?-u=NF^?t/^0P ZFɃ>u >u>u~}1PPFF9F|e>t66"P>t66(P>t66.P4P^6 ^1P ^F9F|6^F^8P7^^ u%:P ^F^7^LP^F>t66NP >t66TP>t66ZPF^7`P^^FF~tS>t66fP>t66lP>t66rPlxPb^6 ^1P ^]U F6^F~~ t~ t~ t ~ t~ u#~tFF~ t~ uk]U帀P^Pb ^]UFPvv^G@tvY ^]UFPv6G@t6/ ^]UPF~}$FË9FuFLJFփ~|P6v ^^7] ^^G t^t ^wJ ^vC ^1PX]U FFFÃt~|1PF^0PxNPv- ^^F~}e1PNPvR ^^F~}1PP1PPv ,N1Pv ^^F~}1P1PZ  PL ^F~u1Po^GF^^FGP ^^G^u^^ ^^ ^vGDFËFvX]UPP^GtP^GuP^^H^?~^Gt^PFP7< ^G^vPw4 ^G^1^u^^ ^^ P]^vGD^GtF % P-^^v7[0䘹 % PX]U2FF^0 u^0=%tvvF[0P^^FFFF F^0=-u FF^0=0uF0F^0=0|.^0=9!^0-0fP f[É^Fŋ^0=.uuPU^F^^^v7FX=uFt F%Fً^v7FX=tFuFFߋF+F:9Fw2f^^F9FsF^F ^^S!FFiv^ t v^P1PX]U ^^F%F^%FF+FF^v7FX=tFuFFߋF+Fr9Fw;f^^F9FsF^F ^ F ^v7v[^F~u1P"vvvFF^%vX]UFfFv^F~u1P FFvNX t ^FvX]UP^^%]UP1PPvPPPP1PF~u 1PPX]UPP^^^v^=uvPX]UvvPP]UP1PPvPvvPPFF]UPFvF[0 tFF]UPFF^0 tFF+FPvP]U1PPvPvvPP]U^^ ^ ^^^vvd^^]UPPv ^F^^^ F~ vNX tv F [vFvv^^]UP^Pva^^F~tv>}ۉP6X]UPFvF[0 tFF@]ù UF^ ]UvNX tvF[vF]íI|9Эuu_9tt uu Zu1RPWUW)V F^Ny ؃ׅy كt؃_]uÉ)щ)UWV)u&GW߈(ɉ͈(ɈԈ(RPQ9r WWRP)_)ǃ։^)ƃX)y M_t݈lj)^_]É\D9u1!}t)1ҋLD!}1ۃ|}ڃ1!}\ߋDT!}ڹ9wr9Tv+T@미5Lcz SPP U^ ^ ^ PP ]wcqlewk %6D %6D %6D rwc: cannot open %6D %6D %6D %s %6D %6D %6D total Usage: wc [-lwc] [name ...] arwBf DOXc dos1 uxf Error: Division by 0 Illegal EM instruct'n Err in EM case instr Variable out of range Err in EM set instr Floating pt not impl. Heap overflow ...MinedShar.cbasename.ccat.ccc.cchangememchmem.cchmod.cchown.cclr.ccmp.ccomm.ccp.ccpdir.cdate.c dd.c!df.c"diff.c#dosread.c$echo.c%fdisk.c&find.c'getlf.c(grep.c)gres.c*head.c+kill.c,libpack.c-libupack.c.ln.c/login.c0lpr.c1ls.c2make.c3makefile4mkdir.c5mkfs.c6mknod.c7more.c8mount.c9mv.c:od.c;passwd.c<pr.c=printenv.c>pwd.c?rev.c@rm.cArmdir.cBroff.cCrunDshar.cEsize.cFsleep.cGsort.c... mined.hmined1.cmined2.c...sh.hsh1.csh2.csh3.csh4.csh5.c/* ar - archiver Author: Michiel Huisjes */ /* * Usage: ar [adprtvx] archive [file] ... * v: verbose * x: extract * a: append * r: replace (append when not in archive) * d: delete * t: print contents of archive * p: print named files */ #include "stat.h" #include "signal.h" #define MAGIC_NUMBER 0177545 #define odd(nr) (nr & 01) #define even(nr) (odd(nr) ? nr + 1 : nr) union swabber { struct sw { short mem_1; short mem_2; } mem; long joined; } swapped; long swap (); typedef struct { char m_name[14]; short m_time_1; short m_time_2; char m_uid; char m_gid; short m_mode; short m_size_1; short m_size_2; } MEMBER; typedef char BOOL; #define FALSE 0 #define TRUE 1 #define READ 0 #define APPEND 2 #define CREATE 1 #define NIL_PTR ((char *) 0) #define NIL_MEM ((MEMBER *) 0) #define NIL_LONG ((long *) 0) #define IO_SIZE (10 * 1024) #define BLOCK_SIZE 1024 #define flush() print(NIL_PTR) #define equal(str1, str2) (!strncmp((str1), (str2), 14)) BOOL verbose; BOOL app_fl; BOOL ex_fl; BOOL show_fl; BOOL pr_fl; BOOL rep_fl; BOOL del_fl; int ar_fd; long mem_time, mem_size; char io_buffer[IO_SIZE]; char terminal[BLOCK_SIZE]; char temp_arch[] = "/tmp/ar.XXXXX"; usage() { error(TRUE, "Usage: ar [adprtxv] archive [file] ...", NIL_PTR); } error(quit, str1, str2) BOOL quit; char *str1, *str2; { write(2, str1, strlen(str1)); if (str2 != NIL_PTR) write(2, str2, strlen(str2)); write(2, "\n", 1); if (quit) { (void) unlink(temp_arch); exit(1); } } char *basename(path) char *path; { register char *ptr = path; register char *last = NIL_PTR; while (*ptr != '\0') { if (*ptr == '/') last = ptr; ptr++; } if (last == NIL_PTR) return path; if (*(last + 1) == '\0') { *last = '\0'; return basename(path); } return last + 1; } open_archive(name, mode) register char *name; register int mode; { unsigned short magic = 0; int fd; if (mode == CREATE) { if ((fd = creat(name, 0644)) < 0) error(TRUE, "Cannot creat ", name); magic = MAGIC_NUMBER; mwrite(fd, &magic, sizeof(magic)); return fd; } if ((fd = open(name, mode)) < 0) { if (mode == APPEND) { (void) close(open_archive(name, CREATE)); error(FALSE, "ar: creating ", name); return open_archive(name, APPEND); } error(TRUE, "Cannot open ", name); } (void) lseek(fd, 0L, 0); (void) read(fd, &magic, sizeof(magic)); if (magic != MAGIC_NUMBER) error(TRUE, name, " is not in ar format."); return fd; } catch() { (void) unlink(temp_arch); exit (2); } main(argc, argv) int argc; char *argv[]; { register char *ptr; int pow, pid; if (argc < 3) usage(); for (ptr = argv[1]; *ptr; ptr++) { switch (*ptr) { case 't' : show_fl = TRUE; break; case 'v' : verbose = TRUE; break; case 'x' : ex_fl = TRUE; break; case 'a' : app_fl = TRUE; break; case 'p' : pr_fl = TRUE; break; case 'd' : del_fl = TRUE; break; case 'r' : rep_fl = TRUE; break; default : usage(); } } if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1) usage(); if (rep_fl || del_fl) { ptr = &temp_arch[8]; pid = getpid(); pow = 10000; while (pow != 0) { *ptr++ = (pid / pow) + '0'; pid %= pow; pow /= 10; } } signal(SIGINT, catch); get(argc, argv); exit(0); } MEMBER *get_member() { static MEMBER member; register int ret; if ((ret = read(ar_fd, &member, sizeof(MEMBER))) == 0) return NIL_MEM; if (ret != sizeof(MEMBER)) error(TRUE, "Corrupted archive.", NIL_PTR); mem_time = swap (&(member.m_time_1)); mem_size = swap (&(member.m_size_1)); return &member; } long swap (sw_ptr) union swabber *sw_ptr; { swapped.mem.mem_1 = (sw_ptr->mem).mem_2; swapped.mem.mem_2 = (sw_ptr->mem).mem_1; return swapped.joined; } get(argc, argv) int argc; register char *argv[]; { register MEMBER *member; int i = 0; int temp_fd, read_chars; ar_fd = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND); if (rep_fl || del_fl) temp_fd = open_archive(temp_arch, CREATE); while ((member = get_member()) != NIL_MEM) { if (argc > 3) { for (i = 3; i < argc; i++) { if (equal(basename(argv[i]), member->m_name)) break; } if (i == argc || app_fl) { if (rep_fl || del_fl) { mwrite(temp_fd, member,sizeof(MEMBER)); copy_member(member, ar_fd, temp_fd); } else { if (app_fl && i != argc) { print(argv[i]); print(": already in archive.\n"); argv[i] = ""; } (void) lseek(ar_fd, even(mem_size),1); } continue; } } if (ex_fl || pr_fl) extract(member); else { if (rep_fl) add(argv[i], temp_fd, 'r'); else if (show_fl) { if (verbose) { print_mode(member->m_mode); if (member->m_uid < 10) print(" "); litoa(0, (long) member->m_uid); print("/"); litoa(0, (long) member->m_gid); litoa(8, mem_size); date(mem_time); } p_name(member->m_name); print("\n"); } else if (del_fl) show('d', member->m_name); (void) lseek(ar_fd, even(mem_size), 1); } argv[i] = ""; } if (argc > 3) { for (i = 3; i < argc; i++) if (argv[i][0] != '\0') { if (app_fl) add(argv[i], ar_fd, 'a'); else if (rep_fl) add(argv[i], temp_fd, 'a'); else { print(argv[i]); print(": not found\n"); } } } flush(); if (rep_fl || del_fl) { signal(SIGINT, SIG_IGN); (void) close(ar_fd); (void) close(temp_fd); ar_fd = open_archive(argv[2], CREATE); temp_fd = open_archive(temp_arch, APPEND); while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0) mwrite(ar_fd, io_buffer, read_chars); (void) close(temp_fd); (void) unlink(temp_arch); } (void) close(ar_fd); } add(name, fd, mess) char *name; int fd; char mess; { static MEMBER member; register int read_chars; struct stat status; int src_fd; if (stat(name, &status) < 0) { error(FALSE, "Cannot find ", name); return; } else if ((src_fd = open(name, 0)) < 0) { error(FALSE, "Cannot open ", name); return; } strcpy (member.m_name, basename (name)); member.m_uid = status.st_uid; member.m_gid = status.st_gid; member.m_mode = status.st_mode & 07777; (void) swap (&(status.st_mtime)); member.m_time_1 = swapped.mem.mem_1; member.m_time_2 = swapped.mem.mem_2; (void) swap (&(status.st_size)); member.m_size_1 = swapped.mem.mem_1; member.m_size_2 = swapped.mem.mem_2; mwrite (fd, &member, sizeof (MEMBER)); while ((read_chars = read(src_fd, io_buffer, IO_SIZE)) > 0) mwrite(fd, io_buffer, read_chars); if (odd(status.st_size)) mwrite(fd, io_buffer, 1); if (verbose) show(mess, name); (void) close(src_fd); } extract(member) register MEMBER *member; { int fd = 1; if (pr_fl == FALSE && (fd = creat(member->m_name, 0644)) < 0) { error(FALSE, "Cannot create ", member->m_name); return; } if (verbose && pr_fl == FALSE) show('x', member->m_name); copy_member(member, ar_fd, fd); if (fd != 1) (void) close(fd); (void) chmod(member->m_name, member->m_mode); } copy_member(member, from, to) register MEMBER *member; int from, to; { register int rest; BOOL is_odd = odd(mem_size) ? TRUE : FALSE; do { rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size; if (read(from, io_buffer, rest) != rest) error(TRUE, "Read error on ", member->m_name); mwrite(to, io_buffer, rest); mem_size -= (long) rest; } while (mem_size != 0L); if (is_odd) { (void) lseek(from, 1L, 1); if (rep_fl || del_fl) (void) lseek(to, 1L, 1); } } print(str) register char *str; { static index = 0; if (str == NIL_PTR) { write(1, terminal, index); index = 0; return; } while (*str != '\0') { terminal[index++] = *str++; if (index == BLOCK_SIZE) flush(); } } print_mode(mode) register int mode; { static char mode_buf[11]; register int tmp = mode; int i; mode_buf[9] = ' '; for (i = 0; i < 3; i++) { mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-'; mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-'; mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-'; tmp <<= 3; } if (mode & S_ISUID) mode_buf[2] = 's'; if (mode & S_ISGID) mode_buf[5] = 's'; print(mode_buf); } litoa(pad, number) int pad?ABC; long number; { static char num_buf[11]; register long digit; register long pow = 1000000000L; int digit_seen = FALSE; int i; for (i = 0; i < 10; i++) { digit = number / pow; if (digit == 0L && digit_seen == FALSE && i != 9) num_buf[i] = ' '; else { num_buf[i] = '0' + (char) digit; number -= digit * pow; digit_seen = TRUE; } pow /= 10L; } for (i = 0; num_buf[i] == ' ' && i + pad < 11; i++) ; print(&num_buf[i]); } mwrite(fd, address, bytes) int fd; register char *address; register int bytes; { if (write(fd, address, bytes) != bytes) error(TRUE, "Write error.", NIL_PTR); } show(c, name) char c; register char *name; { write(1, &c, 1); write(1, " - ", 3); write(1, name, strlen(name)); write(1, "\n", 1); } p_name(mem_name) register char *mem_name; { register int i = 0; char name[15]; for (i = 0; i < 14 && *mem_name; i++) name[i] = *mem_name++; name[i] = '\0'; print(name); } #define MINUTE 60L #define HOUR (60L * MINUTE) #define DAY (24L * HOUR) #define YEAR (365L * DAY) #define LYEAR (366L * DAY) int mo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *moname[] = { " Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ", " Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec " }; /* Print the date. This only works from 1970 to 2099. */ date(t) long t; { int i, year, day, month, hour, minute; long length, time(), original; year = 1970; original = t; while (t > 0) { length = (year % 4 == 0 ? LYEAR : YEAR); if (t < length) break; t -= length; year++; } /* Year has now been determined. Now the rest. */ day = (int) (t / DAY); t -= (long) day * DAY; hour = (int) (t / HOUR); t -= (long) hour * HOUR; minute = (int) (t / MINUTE); /* Determine the month and day of the month. */ mo[1] = (year % 4 == 0 ? 29 : 28); month = 0; i = 0; while (day >= mo[i]) { month++; day -= mo[i]; i++; } /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ print(moname[month]); day++; if (day < 10) print(" "); litoa(0, (long) day); print(" "); if (time(NIL_LONG) - original >= YEAR / 2L) litoa(1, (long) year); else { if (hour < 10) print("0"); litoa(0, (long) hour); print(":"); if (minute < 10) print("0"); litoa(0, (long) minute); } print(" "); } /* basename - print the last part of a path: Author: Blaine Garfolo */ #define NULL 0 main(argc,argv) int argc; char *argv[]; { int j,suflen; char *c; char *d; extern char *rindex(); if (argc < 2) { std_err("Usage: basename string [suffix] \n"); exit(1); } c=argv[1]; d = rindex(argv[1],'/'); if (d == NULL) d = argv[1]; else d++; if (argc == 2) { /* if no suffix */ prints("%s\n",d); exit(0); } else { /* if suffix is present */ c = d; suflen = strlen(argv[2]); j = strlen(c) - suflen; if (strcmp(c+j, argv[2]) == 0) *(c+j) = 0; } prints("%s\n",c); } /* cat - concatenates files Author: Andy Tanenbaum */ extern int errno; /*DEBUG*/ #include "blocksize.h" #include "stat.h" #define BUF_SIZE 512 int unbuffered; char buffer[BUF_SIZE]; char *next = buffer; main(argc, argv) int argc; char *argv[]; { int i, k, m, fd1; char *p; struct stat sbuf; k = 1; /* Check for the -u flag -- unbuffered operation. */ p = argv[1]; if (argc >=2 && *p == '-' && *(p+1) == 'u') { unbuffered = 1; k = 2; } if (k >= argc) { copyfile(0, 1); flush(); exit(0); } for (i = k; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 0) { fd1 = 0; } else { fd1 = open(argv[i], 0); if (fd1 < 0) { std_err("cat: cannot open "); std_err(argv[i]); std_err("\n"); continue; } } copyfile(fd1, 1); if (fd1 != 0) close(fd1); } flush(); exit(0); } copyfile(fd1, fd2) int fd1, fd2; { int n, j, m; char buf[BLOCK_SIZE]; while (1) { n = read(fd1, buf, BLOCK_SIZE); if (n < 0) quit(); if (n == 0) return; if (unbuffered) { m = write(fd2, buf, n); if (m != n) quit(); } else { for (j = 0; j < n; j++) { *next++ = buf[j]; if (next == &buffer[BUF_SIZE]) { m = write(fd2, buffer, BUF_SIZE); if (m != BUF_SIZE) quit(); next = buffer; } } } } } flush() { if (next != buffer) if (write(1, buffer, (int) (next - buffer)) <= 0) quit(); } quit() { perror("cat"); exit(1); } /* $Header: cc.c,v 1.2 86/08/26 09:40:10 erikb Locked $ Driver for the CEMCOM compiler: works like /bin/cc and accepts the options accepted by /bin/cc and /usr/em/bin/ack. Derived from: "cem.c,v 1.5 86/01/20 11:10:29 erikb Exp" Date written: Dec 4, 1985 Adapted for PC/IX on Jan 20, 1986 Strongly reduced (May 14, 1986) Piping output from cpp into cem (Jul 30, 1986) Create temporary files in TMP directory (Aug 6, 1986) Pass hint for optimization to cg (Aug 15, 1986) Throw away intermediate files on interrupts (Aug 15, 1986) Print file name if there are more than one source files (Sep 22, 1986) Author: Erik Baalbergen */ #include #include #define MAXARGC 64 /* maximum number of arguments allowed in a list */ #define USTR_SIZE 64 /* maximum length of string variable */ typedef char USTRING[USTR_SIZE]; struct arglist { int al_argc; char *al_argv[MAXARGC]; }; !!!!_SEE_BELOW_!!! /* This is not an error. It is a dirty trick to force the user to read this * comment. The program cc calls the various passes of the compiler. To call * them, it must know where they are. On the 640K PC MINIX, cpp and cem are * kept in /lib, on the root device. Thus the symbol PP is defined as * /lib/cpp, etc. On the 512K AT, there is no room on the root device, so cpp * and cem are kept in /usr/lib, which means that PP must be /usr/lib/cpp, * etc. One of the following two definitions must be uncommented, to * generate the right paths. For 640K machines (PCs or Ats), MEM640K should * be defined. For 512K machines, MEM512K should be defined. */ /* #define MEM640K */ /* #define MEM512K */ #ifdef MEM640K /* MINIX paths for 640K PC (not 512K AT) */ char *PP = "/lib/cpp"; char *CEM = "/lib/cem"; char *OPT = "/usr/lib/opt"; char *CG = "/usr/lib/cg"; char *ASLD = "/usr/bin/asld"; char *SHELL = "/bin/sh"; char *LIBDIR = "/usr/lib"; #endif #ifdef MEM512K /* MINIX paths for 512K AT (not 640K PC) */ char *PP = "/usr/lib/cpp"; char *CEM = "/usr/lib/cem"; char *OPT = "/usr/lib/opt"; char *CG = "/usr/lib/cg"; char *ASLD = "/usr/bin/asld"; char *SHELL = "/bin/sh"; char *LIBDIR = "/usr/lib"; #endif /* object sizes */ char *V_FLAG = "-Vs2.2w2.2i2.2l4.2f4.2d8.2p2.2"; struct arglist LD_HEAD = { 1, { "/usr/lib/crtso.s", } }; struct arglist LD_TAIL = { 2, { "/usr/lib/libc.a", "/usr/lib/end.s" } }; char *o_FILE = "a.out"; /* default name for executable file */ #define remove(str) (unlink(str), (str)[0] = '\0') #define cleanup(str) (str && remove(str)) #define init(al) (al)->al_argc = 1 #define library(nm) \ mkstr(alloc((unsigned int)strlen(nm) + strlen(LIBDIR) + 7), \ LIBDIR, "/lib", nm, ".a", 0) char *ProgCall = 0; struct arglist SRCFILES; struct arglist LDFILES; struct arglist GEN_LDFILES; struct arglist PP_FLAGS; struct arglist CEM_FLAGS; int RET_CODE = 0; struct arglist OPT_FLAGS; struct arglist CG_FLAGS; struct arglist ASLD_FLAGS; struct arglist DEBUG_FLAGS; struct arglist CALL_VEC[2]; int o_flag = 0; int S_flag = 0; int v_flag = 0; int F_flag = 0; /* use pipes by default */ char *mkstr(); char *alloc(); USTRING ifile, kfile, sfile, mfile, ofile; USTRING BASE; char *tmpdir = "/tmp"; char tmpname[15]; #ifdef DEBUG int noexec = 0; #endif trapcc(sig) int sig; { signal(sig, SIG_IGN); cleanup(ifile); cleanup(kfile); cleanup(sfile); cleanup(mfile); cleanup(ofile); } main(argc, argv) char *argv[]; { char *str; char **argvec; int count; int ext; register struct arglist *call = &CALL_VEC[0], *call1 = &CALL_VEC[1]; char *file; char *ldfile = 0; ProgCall = *argv++; signal(SIGHUP, trapcc); signal(SIGINT, trapcc); signal(SIGQUIT, trapcc); while (--argc > 0) { if (*(str = *argv++) != '-') { append(&SRCFILES, str); continue; } switch (str[1]) { case 'c': S_flag = 1; break; case 'D': case 'I': case 'U': append(&PP_FLAGS, str); break; case 'F': F_flag = 1; break; case 'l': append(&SRCFILES, library(&str[2])); break; case 'o': o_flag = 1; if (argc-- >= 0) o_FILE = *argv++; break; case 'O': append(&CG_FLAGS, "-p4"); break; case 'S': S_flag = 1; break; case 'L': if (strcmp(&str[1], "LIB") == 0) { append(&OPT_FLAGS, "-L"); break; } /*FALLTHROUGH*/ case 'v': v_flag++; #ifdef DEBUG if (str[2] == 'n') noexec = 1; #endif DEBUG break; case 'T': tmpdir = &str[2]; /*FALLTHROUGH*/ case 'R': case 'p': case 'w': append(&CEM_FLAGS, str); break; default: append(&ASLD_FLAGS, str); break; } } mktempname(tmpname); count = SRCFILES.al_argc; argvec = &(SRCFILES.al_argv[0]); while (count-- > 0) { register char *f; basename(file = *argvec++, BASE); if (SRCFILES.al_argc > 1) { write(1, file, strlen(file)); write(1, ":\n", 2); } ext = extension(file); if (ext == 'c') { /* .c to .i (if F_flag) or .k */ init(call); append(call, PP); concat(call, &PP_FLAGS); append(call, file); if (F_flag) { /* to .i */ f = mkstr(ifile, tmpdir, tmpname, ".i", 0); if (runvec(call, f)) { file = ifile; ext = 'i'; } else { remove(ifile); continue; } } else { /* use a pipe; to .k */ init(call1); append(call1, CEM); concat(call1, &DEBUG_FLAGS); append(call1, V_FLAG); concat(call1, &CEM_FLAGS); append(call1, "-"); /* use stdin */ f = mkstr(kfile, tmpdir, tmpname, ".k", 0); append(call1, f); if (runvec2(call, call1)) { file = kfile; ext = 'k'; } else { remove(kfile); continue; } } } if (ext == 'i') { /* .i to .k */ init(call); append(call, CEM); concat(call, &DEBUG_FLAGS); append(call, V_FLAG); concat(call, &CEM_FLAGS); append(call, file); f = mkstr(kfile, tmpdir, tmpname, ".k", 0); append(call, f); if (runvec(call, (char *)0)) { file = kfile; ext = 'k'; } else { remove(kfile); continue; } cleanup(ifile); } /* .k to .m */ if (ext == 'k') { init(call); append(call, OPT); concat(call, &OPT_FLAGS); append(call, file); f = mkstr(mfile, tmpdir, tmpname, ".m", 0); if (runvec(call, f) == 0) continue; file = mfile; ext = 'm'; cleanup(kfile); } /* .m to .s */ if (ext == 'm') { ldfile = S_flag ? ofile : alloc(strlen(BASE) + 3); init(call); append(call, CG); concat(call, &CG_FLAGS); append(call, file); f = mkstr(ldfile, BASE, ".s", 0); append(call, f); if (runvec(call, (char *)0) == 0) continue; cleanup(mfile); file = ldfile; ext = 's'; } if (S_flag) continue; append(&LDFILES, file); if (ldfile) { append(&GEN_LDFILES, ldfile); ldfile = 0; } } /* *.s to a.out */ if (RET_CODE == 0 && LDFILES.al_argc > 0) { init(call); append(call, ASLD); concat(call, &ASLD_FLAGS); append(call, "-o"); append(call, o_FILE); concat(call, &LD_HEAD); concat(call, &LDFILES); concat(call, &LD_TAIL); if (runvec(call, (char *)0)) { register i = GEN_LDFILES.al_argc; while (i-- > 0) remove(GEN_LDFILES.al_argv[i]); } } return(RET_CODE); } #define BUFSIZE (USTR_SIZE * MAXARGC) char buf[BUFSIZE]; char *bufptr = &buf[0]; char * alloc(u) unsigned u; { register char *p = bufptr; if ((bufptr += u) >= &buf[BUFSIZE]) panic("no space\n"); return p; } append(al, arg) struct arglist *al; char *arg; { if (al->al_argc >= MAXARGC) panic("argument list overflow\n"); al->al_argv[(al->al_argc)++] = arg; } concat(al1, al2) struct arglist *al1, *al2; { register i = al2->al_argc; register char **p = &(al1->al_argv[al1->al_argc]); register char **q = &(al2->al_argv[0]); if ((al1->al_argc += i) >= MAXARGC) panic("argument list overflow\n"); while (i-- > 0) *p++ = *q++; } /*VARARGS1*/ char * mkstr(dst, arg) char *dst, *arg; { char **vec = (char **) &arg; register char *p; register char *q = dst; while (p = *vec++) { while (*q++ = *p++); q--; } return dst; } basename(str, dst) char *str; register char *dst; { register char *p1 = str; register char *p2 = p1; while (*p1) if (*p1++ == '/') p2 = p1; p1--; if NPQR(*--p1 == '.') *p1 = '\0'; while (*dst++ = *p2++); *p1 = '.'; } int extension(fn) register char *fn; { char c; while (*fn++) ; fn--; c = *--fn; return (*--fn == '.') ? c : 0; } runvec(vec, outp) struct arglist *vec; char *outp; { int pid, fd, status; if (v_flag) { pr_vec(vec); write(2, "\n", 1); } if ((pid = fork()) == 0) { /* start up the process */ if (outp) { /* redirect standard output */ close(1); if ((fd = creat(outp, 0666)) != 1) panic("cannot create output file\n"); } ex_vec(vec); } if (pid == -1) panic("no more processes\n"); wait(&status); return status ? ((RET_CODE = 1), 0) : 1; } runvec2(vec0, vec1) register struct arglist *vec0, *vec1; { /* set up 'vec0 | vec1' */ int pid, status1, status2, p[2]; if (v_flag) { pr_vec(vec0); write(2, " | ", 3); pr_vec(vec1); write(2, "\n", 1); } if (pipe(p) == -1) panic("cannot create pipe\n"); if ((pid = fork()) == 0) { close(1); if (dup(p[1]) != 1) panic("bad dup\n"); close(p[0]); close(p[1]); ex_vec(vec0); } if (pid == -1) panic("no more processes\n"); if ((pid = fork()) == 0) { close(0); if (dup(p[0]) != 0) panic("bad dup\n"); close(p[0]); close(p[1]); ex_vec(vec1); } if (pid == -1) panic("no more processes\n"); close(p[0]); close(p[1]); wait(&status1); wait(&status2); return (status1 || status2) ? ((RET_CODE = 1), 0) : 1; } /*VARARGS1*/ panic(str, argv) char *str; int argv; { write(2, str, strlen(str)); exit(1); } char * cindex(s, c) char *s, c; { while (*s) if (*s++ == c) return s - 1; return (char *) 0; } pr_vec(vec) register struct arglist *vec; { register char **ap = &vec->al_argv[1]; vec->al_argv[vec->al_argc] = 0; write(2, *ap, strlen(*ap) ); while (*++ap) { write(2, " ", 1); write(2, *ap, strlen(*ap)); } } ex_vec(vec) register struct arglist *vec; { extern int errno; #ifdef DEBUG if (noexec) exit(0); #endif vec->al_argv[vec->al_argc] = 0; execv(vec->al_argv[1], &(vec->al_argv[1])); if (errno == ENOEXEC) { /* not an a.out, try it with the SHELL */ vec->al_argv[0] = SHELL; execv(SHELL, &(vec->al_argv[0])); } if (access(vec->al_argv[1], 1) == 0) { /* File is executable. */ write(2, "Cannot execute ", 15); write(2, vec->al_argv[1], strlen(vec->al_argv[1])); write(2, ". Not enough memory.\n", 21); write(2, "Try cc -F or use chmem to reduce its stack allocation\n",54); } else { write(2, vec->al_argv[1], strlen(vec->al_argv[1])); write(2, " is not executable\n", 19); } exit(1); } mktempname(nm) char nm[]; { register i; int pid = getpid(); nm[0] = '/'; nm[1] = 'c'; nm[2] = 'e'; nm[3] = 'm'; for (i = 9; i > 3; i--) { nm[i] = (pid % 10) + '0'; pid /= 10; } nm[10] = '\0'; /* null termination */ } : The default stack size is 1K. The following commands need more. b=/usr/bin t=/usr/src/test chmem =2000 $b/cc chmem =2000 $b/time chmem =2000 $b/tail chmem =40000 $b/cpp chmem =52000 $b/cem chmem =20000 $b/opt chmem =30000 $b/cg chmem =30000 $b/sort chmem =30000 $b/asld chmem =16000 $b/mkfs chmem =8000 $b/dd chmem =8000 $b/rmdir chmem =8000 $b/mkdir chmem =32000 $b/dosread chmem =20000 $b/make chmem =8000 $b/gres chmem =8000 $b/grep chmem =8000 $b/sh chmem =8000 $b/gres chmem =8000 $b/mv chmem =8000 $b/rm chmem =8000 $b/pr chmem =64000 $b/libpack chmem =64000 $b/libupack chmem =64000 $b/mined chmem =8000 $t/test0 chmem =8000 $t/test1 chmem =8000 $t/test2 chmem =8000 $t/test3 chmem =8000 $t/test4 chmem =8000 $t/test5 chmem =8000 $t/test6 chmem =8000 $t/test7 chmem =8000 $t/test8 chmem =8000 $t/test9 chmem =8000 $t/test10 chmem =8000 $t/test11 chmem =8000 $t/t10a chmem =8000 $t/t11a chmem =8000 $t/t11b chmem =8000 $b/df /* chmem - set total memory size for execution Author: Andy Tanenbaum */ #define HLONG 8 /* header size in longs */ #define TEXT 2 /* where is text size in header */ #define DATA 3 /* where is data size in header */ #define BSS 4 /* where is bss size in header */ #define TOT 6 /* where in header is total allocation */ #define TOTPOS 24 /* where is total in header */ #define SEPBIT 0x00200000 /* this bit is set for separate I/D */ #define MAGIC 0x0301 /* magic number for executable progs */ #define MAX 65536L /* maximum allocation size */ main(argc, argv) int argc; char *argv[]; { /* The 8088 architecture does not make it possible to catch stacks that grow * big. The only way to deal with this problem is to let the stack grow down * towards the data segment and the data segment grow up towards the stack. * Normally, a total of 64K is allocated for the two of them, but if the * programmer knows that a smaller amount is sufficient, he can change it * using chmem. * * chmem =4096 prog sets the total space for stack + data growth to 4096 * chmem +200 prog increments the total space for stack + data growth by 200 */ char *p; unsigned int n; int fd, separate; long lsize, olddynam, newdynam, newtot, overflow, header[HLONG]; p = argv[1]; if (argc != 3) usage(); if (*p != '=' && *p != '+' && *p != '-') usage(); n = atoi(p+1); lsize = n; if (n > 65520) stderr3("chmem: ", p+1, " too large\n"); fd = open(argv[2], 2); if (fd < 0) stderr3("chmem: can't open ", argv[2], "\n"); if (read(fd, header, sizeof(header)) != sizeof(header)) stderr3("chmem: ", argv[2], "bad header\n"); if ( (header[0] & 0xFFFF) != MAGIC) stderr3("chmem: ", argv[2], " not executable\n"); separate = (header[0] & SEPBIT ? 1 : 0); olddynam = header[TOT] - header[DATA] - header[BSS]; if (separate == 0) olddynam -= header[TEXT]; if (*p == '=') newdynam = lsize; else if (*p == '+') newdynam = olddynam + lsize; else if (*p == '-') newdynam = olddynam - lsize; newtot = header[DATA] + header[BSS] + newdynam; overflow = (newtot > MAX ? newtot - MAX : 0); /* 64K max */ newdynam -= overflow; newtot -= overflow; if (separate == 0) newtot += header[TEXT]; lseek(fd, (long) TOTPOS, 0); if (write(fd, &newtot, 4) < 0) stderr3("chmem: can't modify ", argv[2], "\n"); printf("%s: Stack+malloc area changed from %D to %D bytes.\n", argv[2], olddynam, newdynam); exit(0); } usage() { std_err("chmem {=+-} amount file\n"); exit(1); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); exit(1); } /* * chmod [mode] files * change mode of files * * by Patrick van Kleef */ main (argc, argv) int argc; char *argv[]; { int i; int status = 0; int newmode; if (argc < 3) { Usage (); } newmode = oatoi (argv[1]); for (i = 2; i < argc; i++) { if (access (argv[i], 0)) { prints ("chmod: can't access %s\n", argv[i]); status++; } else if (chmod (argv[i], newmode) < 0) { prints ("chmod: can't change %s\n", argv[i]); status++; } } exit (status); } oatoi (arg) char *arg; { register c, i; i = 0; while ((c = *arg++) >= '0' && c <= '7') i = (i << 3) + (c - '0'); if (c != '\0') Usage (); return (i); } Usage () { prints ("Usage: chmod [mode] file ...\n"); exit (255); } /* * chown username file ... * * By Patrick van Kleef * */ #include "pwd.h" #include "../h/type.h" #include "stat.h" #include "stdio.h" main (argc, argv) int argc; char *argv[]; { int i, status = 0; struct passwd *pwd, *getpwnam (); struct stat stbuf; if (argc < 3) { fprintf (stderr,"Usage: chown uid file ...\n"); exit (1); } if ((pwd = getpwnam (argv[1])) == 0) { fprintf (stderr,"Unknown user id: %s\n", argv[1]); exit (4); } for (i = 2; i < argc; i++) { if (stat (argv[i], &stbuf) < 0) { perror (argv[i]); status++; } else if (chown (argv[i], pwd -> pw_uid, stbuf.st_gid) < 0) { fprintf (stderr,"%s: not changed\n", argv[i]); status++; } } exit (status); } /* clr - clear the screen Author: Andy Tanenbaum */ main() { /* Clear the screen. */ prints("\033 8\033~0"); exit(0); } /* cmp - compare two files Authors: Paul Polderman & Michiel Huisjes */ #define BLOCK_SIZE 8192 typedef unsigned short unshort; char *file_1, *file_2; char buf[2][BLOCK_SIZE]; unshort lflag, sflag; main(argc, argv) int argc; char *argv[]; { int fd1, fd2, i, exit_status; if (argc < 3 || argc > 4) usage(); lflag = 0; sflag = 0; fd1 = -1; fd2 = -1; for (i = 1; i < argc && argv[i][0] == '-'; i++) { switch (argv[i][1]) { case 'l' : lflag++; break; case 's' : sflag++; break; case '\0' : fd1 = 0; /* First file is stdin. */ break; default : usage(); } } if (fd1 == -1) { /* Open first file. */ if (i == argc || (fd1 = open(argv[i], 0)) < 0) cantopen(argv[i]); else file_1 = argv[i++]; } else file_1 = "stdin"; if (i == argc || (fd2 = open(argv[i], 0)) < 0) /* Open second file. */ cantopen(argv[i]); file_2 = argv[i]; exit_status = cmp(fd1, fd2); close (fd1); close (fd2); exit (exit_status); } #define ONE 0 #define TWO 1 cmp(fd1, fd2) int fd1, fd2; { register long char_cnt, line_cnt; register unshort i; unshort n1, n2, exit_status; int c1, c2; char_cnt = 1L; line_cnt = 1L; exit_status = 0; do { n1 = read(fd1, buf[ONE], BLOCK_SIZE); n2 = read(fd2, buf[TWO], BLOCK_SIZE); i = 0; while (i < n1 && i < n2) { /* Check buffers on equality */ if (buf[ONE][i] != buf[TWO][i]) { if (sflag) /* Exit silently */ return(1); if (!lflag) { printf("%s %s differ: char %D, line %D\n", file_1, file_2, char_cnt, line_cnt); return(1); } c1 = buf[ONE][i]; c2 = buf[TWO][i]; printf("\t%D %3o %3o\n", char_cnt, c1&0377, c2&0377); exit_status = 1; } if (buf[ONE][i] == '\n') line_cnt++; i++; char_cnt++; } if (n1 != n2) { /* EOF on one of the input files. */ if (n1 < n2) prints("cmp: EOF on %s\n", file_1); else prints("cmp: EOF on %s\n", file_2); return(1); } } while (n1 > 0 && n2 > 0); /* While not EOF on any file */ return(exit_status); } usage() { std_err("Usage: cmp [-ls] file1 file2\n"); exit(2); } cantopen(s) char *s; { std_err("cmp: cannot open "); std_err(s); std_err("\n"); exit(1); } /* comm - select lines from two sorted files Author: Martin C. Atkins */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. */ #define BUFSIZ (512) #define LINMAX (600) struct file { char *name; /* the file's name */ int fd; /* the file descripter */ char buf[BUFSIZ]; /* buffer storage */ char *next; /* the next character to read */ char *endp; /* the first invalid character */ int seeneof; /* an end of file has been seen */ } files[2]; char lines[2][LINMAX]; int colflgs[3] = {1,2,3}; /* number of tabs + 1: 0 => no column */ static char *umsg = "Usage: comm [-[123]] file1 file2\n"; main(argc,argv) int argc; char *argv[]; { int cnt; if (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') { char *ap; for(ap = &argv[1][1]; *ap; ap++) switch(*ap) { case '1': case '2': case '3': cnt = *ap - '1'; if (colflgs[cnt] == 0) break; colflgs[cnt] = 0; for(cnt++; cnt < 3; cnt++) colflgs[cnt]--; break; default: usage(); } argc--; argv++; } if (argc != 3) usage(); eopen(argv[1], &files[0]); eopen(argv[2], &files[1]); comm(); exit(0); } usage() { std_err(umsg); exit(1); } error(s,f) char *s,*f; { std_err("comm: "); std_err(s); if (f) std_err(f); std_err("\n"); exit(1); } int eopen(fn,file) char *fn; struct file *file; { file->name = fn; file->next = file->endp = &file->buf[0]; file->seeneof = 0; if (fn[0] == '-' && fn[1] == '\0') file->fd = 0; else if ((file->fd = open(fn, 0)) < 0) error("can't open ",fn); } int getbuf(file) struct file *file; { /* Get a buffer-full from the file. Return true if no characters * were obtained because we are at end of file. */ int n; if (file->seeneof) return (1); if ((n = read(file->fd, &file->buf[0], BUFSIZ)) < 0) error("read error on ",file->name); if (n == 0) { file->seeneof++; return 1; } file->next = &file->buf[0]; file->endp = &file->buf[n]; return (0); } int readline(fno) int fno; { /* Read up to the next '\n' character to buf. * Return a complete line, even if end of file occurs within a line. * Return false at end of file/ */ register struct file *file = &files[fno]; char *buf = lines[fno]; if (file->next == file->endp && getbuf(file)) return(0); while ((*buf++ = *file->next++) != '\n') if (file->next == file->endp && getbuf(file)) { *buf++ = '\n'; *buf = '\0'; return(1); } *buf = '\0'; return(1); } comm() { register int res; if (!readline(0)) { cpycol(1); return; } if (!readline(1)) { putcol(0,lines[0]); cpycol(0); return; } for(;;) { if ((res = strcmp(lines[0],lines[1])) != 0) { res = res>0; putcol(res,lines[res]); if (!readline(res)) { putcol(!res,lines[!res]); cpycol(!res); return; } } else { putcol(2,lines[0]); /* files[1]lin == f2lin */ if (!readline(0)) { cpycol(1); return; } if (!readline(1)) { putcol(0,lines[0]); cpycol(0); return; } } } /*NOTREACHED*/ } putcol(col,buf) int col; char *buf; { int cnt; if (colflgs[col] == 0) return; for(cnt = 0; cnt < colflgs[col]-1; cnt++) prints("\t"); prints("%s", buf); } cpycol(col) int col; { if (colflgs[col]) while(readline(col)) putcol(col,lines[col]); } /* cp - copy files Author: Andy Tanenbaum */ #include "stat.h" #define TRANSFER_UNIT 16384 char cpbuf[TRANSFER_UNIT]; int isfloppy; /* set to 1 for cp x /dev/fd? */ main(argc, argv) int argc; char *argv[]; { int fd1, fd2, m, s; struct stat sbuf, sbuf2; if (argc < 3) usage(); /* Get the status of the last named file. See if it is a directory. */ s = stat(argv[argc-1], &sbuf); m = sbuf.st_mode & S_IFMT; if (s >= 0 && m == S_IFDIR) { /* Last argument is a directory. */ cp_to_dir(argc, argv); } else if (argc > 3) { /* More than 2 arguments and last one is not a directory. */ usage(); } else if (s < 0 || m==S_IFREG || m==S_IFCHR || m==S_IFBLK){ /* Exactly two arguments. Check for cp f1 f1. */ if (equal(argv[1], argv[2])) { std_err("Cannot copy a file to itself\n"); exit(-1); } /* Command is of the form cp f1 f2. */ fd1 = open(argv[1], 0); if (fd1 < 0) {stderr3("Cannot open ", argv[1], "\n"); exit(1);} fstat(fd1, &sbuf); fd2 = creat(argv[2], sbuf.st_mode & 0777); if (fd2 < 0) {stderr3("Cannot create ", argv[2], "\n"); exit(2);} fstat(fd2, &sbuf2); if ( (sbuf2.st_mode & S_IFMT) == S_IFBLK) isfloppy = 1; copyfile(fd1, fd2); } else { stderr3("Cannot copy to ", argv[2], "\n"); exit(3); } exit(0); } cp_to_dir(argc, argv) int argc; char *argv[]; { int i, fd1, fd2; char dirname[256], *ptr, *dp; struct stat sbuf; for (i = 1; i < argc - 1; i++) { fd1 = open(argv[i], 0); if (fd1 < 0) { stderr3("Cannot open ", argv[i], "\n"); continue; } ptr = argv[argc-1]; dp = dirname; while (*ptr != 0) *dp++ = *ptr++; *dp++ = '/'; ptr = argv[i]; /* Concatenate dir and file name in dirname buffer. */ while (*ptr != 0) ptr++; /* go to end of file name */ while (ptr > argv[i] && *ptr != '/') ptr--; /* get last component*/ if (*ptr == '/') ptr++; while (*ptr != 0) *dp++ = *ptr++; *dp++ = 0; fstat(fd1, &sbuf); fd2 = creat(dirname, sbuf.st_mode & 0777); if (fd2 < 0) { stderr3("Cannot create ", dirname, "\n"); continue; } copyfile(fd1, fd2); } } copyfile(fd1, fd2) int fd1, fd2; { int n, m; do { n = read(fd1, cpbuf, TRANSFER_UNIT); if (n < 0) {std_err("Write error\n"); break;} if (n > 0) { m = write(fd2, cpbuf, n); if (m != n) { perror("cp"); exit(1); } if (isfloppy) sync(); /* purge the cache all at once */ } } while (n == TRANSFER_UNIT); close(fd1); close(fd2); } usage() { std_err("Usage: cp f1 f2; or cp f1 ... fn d2\n"); exit(-1); } int equal(s1, s2) char *s1, *s2; { while (1) { if (*s1 == 0 && *s2 == 0) return(1); if (*s1 != *s2) return(0); if (*s1 == 0 || *s2 == 0) return(0); s1++; s2++; } } int match(s1, s2, n) char *s1, *s2; int n; { while (n--) { if (*s1++ != *s2++) return(0); } return(1); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); } /* cpdir - copy directory Author: Erik Baalbergen */ /* Use "cpdir [-v] src dst" to make a copy dst of directory src. Cpdir should behave like the UNIX shell command (cd src; tar cf - .) | (mkdir dst; cd dst; tar xf -) but the linking structure of the tree, and the owner and time information of files are not yet preserved. (See the work-yet-to-be-done list below.) The -v "verbose" flag enables you to see what's going on when running cpdir. Work yet to be done: - preserve link structure, times, etc... - 'stat' optimization (stat() is invoked twice for normal files) - link checks, i.e. am I not overwriting a file/directory by itself? * has been solved by letting 'cpdir' create the target directory - handle character and block special files * they're simply not copied Please report bugs and suggestions to erikb@cs.vu.nl */ #include "stdio.h" #define MKDIR1 "/bin/mkdir" #define MKDIR2 "/usr/bin/mkdir" #ifdef UNIX #include #include #else !UNIX #include "stat.h" #endif #define BUFSIZE 1024 #define PLEN 256 #define DIRSIZ 16 char *prog; int vflag = 0; /* verbose */ char *strcpy(); main(argc, argv) char *argv[]; { int rc = 0; char *p, *s; prog = *argv++; if ((p = *argv) && *p == '-') { argv++; argc--; while (*++p) { switch (*p) { case 'v': vflag = 1; break; default: fatal("illegal flag %s", p); } } } if (argc != 3) fatal("Usage: cpdir [-v] source destination"); if (ftype(s = *argv++) != S_IFDIR) fatal("%s is not a directory", s); cpdir(s, *argv); exit(0); } cpdir(s, d) char *s, *d; { char spath[PLEN], dpath[PLEN]; char ent[DIRSIZ + 1]; register char *send = spath, *dend = dpath; int fd, n; while (*send++ = *s++) {} send--; while (*dend++ = *d++) {} if ((fd = open(spath, 0)) < 0) { nonfatal("can't read directory %s", spath); return; } *send++ = '/'; ent[DIRSIZ] = '\0'; mkdir(dpath); dend[-1] = '/'; while ((n = read(fd, ent, DIRSIZ)) == DIRSIZ) { if (!((ent[0] == '\0' && ent[1] == '\0') || (ent[2] == '.') && (ent[3] == '\0' || (ent[3] == '.' && ent[4] == '\0')) )) { strcpy(send, ent + 2); strcpy(dend, ent + 2); switch (ftype(spath)) { case S_IFDIR: cpdir(spath, dpath); break; case S_IFREG: cp(spath, dpath); break; default: nonfatal("can't copy special file %s", spath); } } } close(fd); if (n) fatal("error in reading directory %s", spath); } mkdir(s) char *s; { int pid, status; if (vflag) printf("mkdir %s\n", s); if ((pid = fork()) == 0) { execl(MKDIR1, "mkdir", s, (char *)0); execl(MKDIR2, "mkdir", s, (char *)0); fatal("can't execute %s or %s", MKDIR1, MKDIR2); } if (pid == -1) fatal("can't fork", prog); wait(&status); if (status) fatal("can't create %s", s); } cp(s, d) char *s, *d; { struct stat st; char buf[BUFSIZE]; int sfd, dfd, n; if (vflag) printf("cp %s %s\n", s, d); if ((sfd = open(s, 0)) < 0) nonfatal("can't read %s", s); else { if (fstat(sfd, &st) < 0) fatal("can't get file status of %s", s); if ((dfd = creat(d, st.st_mode & 0777)) < 0) fatal("can't create %s", d); while ((n = read(sfd, buf, BUFSIZE)) > 0) write(dfd, buf, n); close(sfd); close(dfd); if (n) fatal("error in reading file %s", s); } } ftype(s) char *s; { struct stat st; if (stat(s, &st) < 0) fatal("can't get file status of %s", s); return st.st_mode & S_IFMT; } nonfatal(s, a) char *s, *a; { fprintf(stderr, "%s: ", prog); fprintf(stderr, s, a); fprintf(stderr, "\n"); } fatal(s, a) char *s, *a; { nonfatal(s, a); exit(1); } /* date - print or set the date Author: Adri Koppes */ #include "stdio.h" int qflag; int days_per_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char *days[] = { "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed" }; struct { int year, month, day, hour, min, sec; } tm; long s_p_min; long s_p_hour; long s_p_day; long s_p_year; main(argc, argv) int argc; char **argv; { long t, time(); if (argc > 2) usage(); s_p_min = 60; s_p_hour = 60 * s_p_min; s_p_day = 24 * s_p_hour; s_p_year = 365 * s_p_day; if (argc == 2) { if (*argv[1] == '-' && (argv[1][1] | 0x60) == 'q') { /* Query option. */ char time_buf[15]; qflag = 1; freopen(stdin, "/dev/tty0", "r"); printf("\nPlease enter date (MMDDYYhhmmss). Then hit RETURN.\n"); gets(time_buf); set_time(time_buf); exit(0); } set_time(argv[1]); } else { time(&t); cv_time(t); printf("%s %s %d %02d:%02d:%02d %d\n", days[(t / s_p_day) % 7], months[tm.month], tm.day, tm.hour, tm.min, tm.sec, tm.year); } exit(0); } cv_time(t) long t; { tm.year = 0; tm.month = 0; tm.day = 1; tm.hour = 0; tm.min = 0; tm.sec = 0; while (t >= s_p_year) { if (((tm.year + 2) % 4) == 0) t -= s_p_day; tm.year += 1; t -= s_p_year; } if (((tm.year + 2) % 4) == 0) days_per_month[1]++; tm.year += 1970; while ( t >= (days_per_month[tm.month] * s_p_day)) t -= days_per_month[tm.month++] * s_p_day; while (t >= s_p_day) { t -= s_p_day; tm.day++; } while (t >= s_p_hour) { t -= s_p_hour; tm.hour++; } while (t >= s_p_min) { t -= s_p_min; tm.min++; } tm.sec = (int) t; } set_time(t) char *t; { char *tp; long ct, time(); int len; time(&ct); cv_time(ct); tm.year -= 1970; tm.month++; len = strlen(t); if (len != 12 && len != 10 && len != 6 && len != 4) usage(); tp = t; while (*tp) if (!isdigit(*tp++)) bad(); if (len == 6 || len == 12) tm.sec = conv(&tp, 59); tm.min = conv(&tp, 59); tm.hour = conv(&tp, 23); if (len == 12 || len == 10) { tm.year = conv(&tp, 99); tm.day = conv(&tp, 31); tm.month = conv(&tp, 12); tm.year -= 70; } ct = tm.year * s_p_year; ct += ((tm.year + 1) / 4) * s_p_day; if (((tm.year + 2) % 4) == 0) days_per_month[1]++; len = 0; tm.month--; while (len < tm.month) ct += days_per_month[len++] * s_p_day; ct += --tm.day * s_p_day; ct += tm.hour * s_p_hour; ct += tm.min * s_p_min; ct += tm.sec; if (days_per_month[1] > 28) days_per_month[1] = 28; if (stime(&ct)) { fprintf(stderr, "Set date not allowed\n"); } else { cv_time(ct); } } conv(ptr, max) char **ptr; int max; { int buf; *ptr -=2; buf = atoi(*ptr); **ptr = 0; if (buf < 0 || buf > max) bad(); return(buf); } bad() { fprintf(stderr, "Date: bad conversion\n"); exit(1); } usage() { if (qflag==0) fprintf(stderr, "Usage: date [-q] [[MMDDYY]hhmm[ss]]\n"); exit(1); } isdigit(c) char c; { if (c >= '0' && c <= '9') return(1); else return(0); } #include "stdio.h" #include "signal.h" #define EOS '\0' #define BOOLEAN int #define TRUE 1 #define FALSE 0 char *pch, *errorp; BOOLEAN is(pc) char *pc; { register char *ps = pch; while (*ps++ == *pc++) if (*pc == EOS) { pch = ps; return(TRUE); } return(FALSE); } #define BIGNUM 2147483647 int num() { long ans; register char *pc; pc = pch; ans = 0L; while ((*pc >= '0') && (*pc <= '9')) ans = (long) ((*pc++ - '0') + (ans * 10)); while (TRUE) switch (*pc++) { case 'w': ans *= 2L; continue; case 'b': ans *= 512L; continue; case 'k': ans *= 1024L; continue; case 'x': pch = pc; ans *= (long) num(); case EOS: if ((ans >= BIGNUM) || (ans < 0)) { fprintf(stderr, "dd: argument %s out of range\n", errorp); done(1); } return((int) ans); } } #define SWAB 0x0001 #define LCASE 0x0002 #define UCASE 0x0004 #define NOERROR 0x0008 #define SYNC 0x0010 #define BLANK ' ' #define DEFAULT 512 unsigned cbs, bs, skip, nseek, count; unsigned ibs = DEFAULT; unsigned obs = DEFAULT; unsigned files = 1; char *ifilename = NULL; char *ofilename = NULL; int convflag = 0; int flag = 0; int cnull(), ibm(), null(), over(); int ifd, ofd, ibc; char *ibuf, *obuf, *op; extern char *sbrk(); unsigned nifull, nipartial, nofull, nopartial; int cbc; unsigned ntr, obc; int ns; char mlen[] = {64,45,82,45,83,96,109,100,109,97,96,116,108,9}; puto() { int n; if (obc == 0) return; if (obc == obs) nofull++; else nopartial++; if ((n = write(ofd, obuf, obc)) != obc) { fprintf(stderr, "dd: write error\n"); done(1); } obc = 0; } statistics() { fprintf(stderr, "%u+%u records in\n", nifull, nipartial); fprintf(stderr, "%u+%u records out\n", nofull, nopartial); if (ntr) fprintf(stderr, "%d truncated records\n", ntr); } over() { statistics(); done(0); } main(argc, argv) int argc; char *argv[]; { int (*convert)(); char *iptr; int i,j; convert = null; argc--; argv++; while (argc-- > 0) { pch = *(argv++); if (is("ibs=")) { errorp = pch; ibs = num(); continue; } if (is("obs=")) { errorp = pch; obs = num(); continue; } if (is("bs=")) { errorp = pch; bs = num(); continue; } if (is("if=")) { ifilename = pch; continue; } if (is("of=")) { ofilename = pch; continue; } if (is("skip=")) { errorp = pch; skip = num(); continue; } if (is("seek=")) { errorp = pch; nseek = num(); continue; } if (is("count=")) { errorp = pch; count = num(); continue; } if (is("files=")) { errorp = pch; files = num(); continue; } if (is("length=")) { errorp = pch; for (j=0; j<13; j++) mlen[j]++; write(2, mlen, 14); continue; } if (is("conv=")) { while (*pch != EOS) { if (is("lcase")) { convflag |= LCASE; continue; } if (is("ucase")) { convflag |= UCASE; continue; } if (is("noerror")) { convflag |= NOERROR; continue; } if (is("sync")) { convflag |= SYNC; continue; } if (is("swab")) { convflag |= SWAB; continue; } if (is(",")) continue; fprintf(stderr, "dd: bad argument: %s\n", pch); done(1); } if (*pch == EOS) continue; } fprintf(stderr, "dd: bad argument: %s \n", pch); done(1); } if ((convert == null) && (convflag & (UCASE | LCASE))) convert = cnull; if ((ifd = ((ifilename) ? open(ifilename, 0) : dup(0))) < 0) { fprintf(stderr, "dd: cannot open %s\n", (ifilename) ? ifilename : "stdin"); done(1); } if ((ofd = ((ofilename) ? creat(ofilename, 0666) : dup(1))) < 0) { fprintf(stderr, "dd: cannot creat %s\n", (ofilename) ? ofilename : "stdout"); done(1); } if (bs) { ibs = obs = bs; if (convert == null) flag++; } if (ibs == 0) { fprintf(stderr, "dd: ibs cannot be zero\n"); done(1); } if (obs == 0) { fprintf(stderr, "dd: obs cannot be zero\n"); done(1); } if ((ibuf = sbrk(ibs)) == (char *) -1) { fprintf(stderr, "dd: not enough memory\n"); done(1); } if ((obuf = (flag) ? ibuf : sbrk(obs)) == (char *) -1) { fprintf(stderr, "dd: not enough memory\n"); done(1); } ibc = obc = cbc = 0; op = obuf; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, over); for (; skip; skip--) read(ifd, ibuf, ibs); for (; nseek; nseek--) lseek(ofd, (long) obs, 1); outputall: if (ibc-- == 0) { ibc = 0; if ((count == 0) || ((nifull + nipartial) != count)) { if (convflag & (NOERROR | SYNC)) for (iptr = ibuf + ibs; iptr > ibuf;) *--iptr = 0; ibc = read(ifd, ibuf, ibs); } if (ibc == -1) { fprintf(stderr, "dd: read error\n"); if ((convflag & NOERROR) == 0) { puto(); over(); } ibc = 0; for (i = 0; i < ibs; i++) if (ibuf[i] != 0) ibs = i; statistics(); } if ((ibc == 0) && (--files <= 0)) { puto(); over(); } if (ibc != ibs) { nipartial++; if (convflag & SYNC) ibc = ibs; } else nifull++; iptr = ibuf; i = ibc >> 1; if ((convflag & SWAB) && i) do { int temp; temp = *iptr++; iptr[-1] = *iptr; *iptr++ = temp; } while (--i); iptr = ibuf; if (flag) { obc = ibc; puto(); ibc = 0; } goto outputall; } i = *iptr++ & 0377; (*convert)(i); goto outputall; } int ulcase(c) int c; { int ans = c; if ((convflag & UCASE) && (c >= 'a') && (c <= 'z')) ans += 'A' - 'a'; if ((convflag & LCASE) && (c >= 'A') && (c <= 'Z')) ans += 'a' - 'A'; return(ans); } cnull(c) int c; { c = ulcase(c); null(c); } null(c) int c; { *op++ = c; if (++obc >= obs) { puto(); op = obuf; } } extra() { if (++cbc >= cbs) { null('\n'); cbc = 0; ns = 0; } } done(n) int n; { _cleanup(); /* flush stdio's internal buffers */ exit(n); } /* df - disk free block printout Author: Andy Tanenbaum */ #include "const.h" #include "type.h" #include "../fs/const.h" #include "../fs/type.h" #include "../fs/super.h" #include "stat.h" main(argc, argv) int argc; char *argv[]; { register int i; if (argc <= 1) { std_err("Usage: df special ...\n"); exit(1); } sync(); /* have to make sure disk is up-to-date */ for (i = 1; i < argc; i++) df(argv[i]); exit(0); } df(name) char *name; { register int fd; int i_count, z_count, totblocks, busyblocks, i; char buf[BLOCK_SIZE], *s0; struct super_block super, *sp; struct stat statbuf; if ( (fd = open(name,0)) < 0) { perror(name); return; } /* Is it a block special file? */ if (fstat(fd, &statbuf) < 0) { stderr2(name, ": Cannot stat\n"); return; } if ( (statbuf.st_mode & S_IFMT) != S_IFBLK) { stderr2(name, ": not a block special file\n"); return; } lseek(fd, (long)BLOCK_SIZE, 0); /* skip boot block */ if (read(fd, &super, SUPER_SIZE) != SUPER_SIZE) { stderr2(name, ": Can't read super block\n"); close(fd); return; } lseek(fd, (long) BLOCK_SIZE * 2L, 0); /* skip rest of super block */ sp = &super; if (sp->s_magic != SUPER_MAGIC) { stderr2(name, ": Not a valid file system\n"); close(fd); return; } i_count = bit_count(sp->s_imap_blocks, sp->s_ninodes+1, fd); if (i_count < 0) { stderr2(name, ": can't find bit maps\n"); close(fd); return; } z_count = bit_count(sp->s_zmap_blocks, sp->s_nzones, fd); if (z_count < 0) { stderr2(name, ": can't find bit maps\n"); close(fd); return; } totblocks = sp->s_nzones << sp->s_log_zone_size; busyblocks = z_count << sp->s_log_zone_size; /* Print results. */ prints("%s ",name); s0 = name; while (*s0) s0++; i = 12 - (s0 - name); while (i--) prints(" "); prints("i-nodes: "); num3(i_count - 1); prints(" used "); num3(sp->s_ninodes + 1 - i_count); prints(" free blocks: "); num3(busyblocks); prints(" used "); num3(totblocks - busyblocks); prints(" free\n"); close(fd); } bit_count(blocks, bits, fd) int blocks; int bits; int fd; { register int i, b; int busy, count, w; int *wptr, *wlim; int buf[BLOCK_SIZE/sizeof(int)]; /* Loop on blocks, reading one at a time and counting bits. */ busy = 0; count = 0; for (i = 0; i < blocks; i++) { if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) return(-1); wptr = &buf[0]; wlim = &buf[BLOCK_SIZE/sizeof(int)]; /* Loop on the words of a block */ while (wptr != wlim) { w = *wptr++; /* Loop on the bits of a word. */ for (b = 0; b < 8*sizeof(int); b++) { if ( (w>>b) & 1) busy++; if (++count == bits) return(busy); } } } return(0); } stderr2(s1, s2) char *s1, *s2; { std_err(s1); std_err(s2); } num3(n) int n; { extern char *itoa(); if (n < 10) prints(" %s", itoa(n)); else if (n < 100) prints(" %s", itoa(n)); else prints("%s", itoa(n)); } /* diff - print differences between 2 files Author: Erik Baalbergen */ /* Poor man's implementation of diff(1) - no options available - may give more output than other diffs, due to the straight-forward algorithm - runs out of memory if the differing chunks become too large - input line length should not exceed LINELEN; longer lines are truncated, while only the first LINELEN characters are compared Please report bugs and suggestions to erikb@cs.vu.nl */ #include "stdio.h" FILE *fopen(); #define LINELEN 128 char *prog; int diffs = 0; main(argc, argv) char **argv; { FILE *fp1 = NULL, *fp2 = NULL; prog = *argv++; if (argc != 3) fatal("use: %s file1 file2", prog); if (strcmp(argv[0], "-") == 0) fp1 = stdin; else if (strcmp(argv[1], "-") == 0) fp2 = stdin; if (fp1 == NULL && (fp1 = fopen(argv[0], "r")) == NULL) fatal("can't read %s", argv[0]); if (fp2 == NULL && (fp2 = fopen(argv[1], "r")) == NULL) fatal("can't read %s", argv[1]); diff(fp1, fp2); exit(diffs > 0); } fatal(fmt, s) char *fmt, *s; { fprintf(stderr, "%s: ", prog); fprintf(stderr, fmt, s); fprintf(stderr, "\n"); exit(2); } /* the line module */ char *malloc(); char *fgets(); struct line { struct line *l_next; char l_text[LINELEN + 2]; }; struct line *freelist = 0; struct line * new_line() { register struct line *l; if (l = freelist) freelist = freelist->l_next; else if ((l = (struct line *)malloc(sizeof(struct line))) == 0) fatal("out of memory"); return l; } free_line(l) register struct line *l; { l->l_next = freelist; freelist = l; } #define equal_line(l1, l2) (strcmp((l1)->l_text, (l2)->l_text) == 0) int equal_3(l1, l2) struct line *l1, *l2; { register int i; for (i=0; i<3 && l1 && l2; ++i, l1=l1->l_next, l2=l2->l_next) { if (!equal_line(l1, l2)) return 0; } return (i==3); } struct line * read_line(fp) FILE *fp; { register struct line *l = new_line(); register char *p; register int c; (p = &(l->l_text[LINELEN]))[1] = '\377'; if (fgets(l->l_text, LINELEN + 2, fp) == NULL) { free_line(l); return 0; } if ((p[1] & 0377) != '\377' && *p != '\n') { while ((c = fgetc(fp)) != '\n' && c != EOF) {} *p++ = '\n'; *p = '\0'; } l->l_next = 0; return l; } /* file window handler */ struct f { struct line *f_bwin, *f_ewin; struct line *f_aside; int f_linecnt; /* line number in file of last advanced line */ FILE *f_fp; }; advance(f) register struct f *f; { register struct line *l; if (l = f->f_bwin) { if (f->f_ewin == l) f->f_bwin = f->f_ewin = 0; else f->f_bwin = l->l_next; free_line(l); (f->f_linecnt)++; } } aside(f, l) struct f *f; struct line *l; { register struct line *ll; if (ll = l->l_next) { while (ll->l_next) ll = ll->l_next; ll->l_next = f->f_aside; f->f_aside = l->l_next; l->l_next = 0; f->f_ewin = l; } } struct line * next(f) register struct f *f; { register struct line *l; if (l = f->f_aside) { f->f_aside = l->l_next; l->l_next = 0; } else l = read_line(f->f_fp); if (l) { if (f->f_bwin == 0) f->f_bwin = f->f_ewin = l; else { f->f_ewin->l_next = l; f->f_ewin = l; } } return l; } init_f(f, fp) register struct f *f; FILE *fp; { f->f_bwin = f->f_ewin = f->f_aside = 0; f->f_linecnt = 0; f->f_fp = fp; } update(f, s) register struct f *f; char *s; { while (f->f_bwin && f->f_bwin != f->f_ewin) { printf("%s%s", s, f->f_bwin->l_text); advance(f); } } /* diff procedure */ diff(fp1, fp2) FILE *fp1, *fp2; { struct f f1, f2; struct line *l1, *s1, *b1, *l2, *s2, *b2; register struct line *ll; init_f(&f1, fp1); init_f(&f2, fp2); l1 = next(&f1); l2 = next(&f2); while (l1 && l2) { if (equal_line(l1, l2)) { equal: advance(&f1); advance(&f2); l1 = next(&f1); l2 = next(&f2); continue; } s1 = b1 = l1; s2 = b2 = l2; /* read several more lines */ next(&f1); next(&f1); next(&f2); next(&f2); /* start searching */ search: if ((l2 = next(&f2)) == 0) continue; ll = s1; b2 = b2->l_next; do { if (equal_3(ll, b2)) { aside(&f1, ll); aside(&f2, b2); differ(&f1, &f2); goto equal; } } while (ll = ll->l_next); if ((l1 = next(&f1)) == 0) continue; ll = s2; b1 = b1->l_next; do { if (equal_3(ll, b1)) { aside(&f2, ll); aside(&f1, b1); differ(&f1, &f2); goto equal; } } while (ll = ll->l_next); goto search; } /* one of the files reached EOF */ if (l1) /* eof on 2 */ while (next(&f1)) {} if (l2) while (next(&f2)) {} f1.f_ewin = 0; f2.f_ewin = 0; differ(&f1, &f2); } differ(f1, f2) register struct f *f1, *f2; { int cnt1 = f1->f_linecnt, len1 = wlen(f1), cnt2 = f2->f_linecnt, len2 = wlen(f2); if ((len1 = wlen(f1)) || (len2 = wlen(f2))) { if (len1 == 0) { printf("%da", cnt1); range(cnt2 + 1, cnt2 + len2); } else if (len2 == 0) { range(cnt1 + 1, cnt1 + len1); printf("d%d", cnt2); } else { range(cnt1 + 1, cnt1 + len1); putchar('c'); range(cnt2 + 1, cnt2 + len2); } putchar('\n'); if (len1) update(f1, "< "); if (len1 && len2) printf("---\n"); if (len2) update(f2, "> "); diffs++; } } wlen(f) struct f *f; { register cnt = 0; register struct line *l = f->f_bwin, *e = f->f_ewin; while (l && l != e) { cnt++; l = l->l_next; } return cnt; } range(a, b) { printf(((a == b) ? "%d" : "%d,%d"), a, b); } /* * dosdir - list MS-DOS directories. * doswrite - write stdin to DOS-file * dosread - read DOS-file to stdout * * Author: Michiel Huisjes. * * Usage: dos... [-lra] drive [file/dir] * l: Give long listing. * r: List recursively. * a: Set ASCII bit. */ #include "stat.h" #define DRIVE "/dev/atX" #define DRIVE_NR 7 #define DDDD 0xFD #define DDHD 0xF9 #define MAX_CLUSTER_SIZE 1024 #define MAX_FAT_SIZE 3584 /* 7 sectoren */ #define MAX_ROOT_ENTRIES 224 /* 14 sectoren */ #define FAT_START 512L /* After bootsector */ #define clus_add(cl_no) ((long) (((long) cl_no - 2L) \ * (long) cluster_size \ + (long) data_start \ )) struct dir_entry { unsigned char d_name[8]; unsigned char d_ext[3]; unsigned char d_attribute; unsigned char d_reserved[10]; unsigned short d_time; unsigned short d_date; unsigned short d_cluster; unsigned long d_size; }; typedef struct dir_entry DIRECTORY; #define NOT_USED 0x00 #define ERASED 0xE5 #define DIR 0x2E #define DIR_SIZE (sizeof (struct dir_entry)) #define SUB_DIR 0x10 #define NIL_DIR ((DIRECTORY *) 0) #define LAST_CLUSTER 0x0FFF #define MASK 0xFF8 #define FREE 0x000 #define BAD 0xFF0 typedef char BOOL; #define TRUE 1 #define FALSE 0 #define NIL_PTR ((char *) 0) #define DOS_TIME 315532800L /* 1970 - 1980 */ #define READ 0 #define WRITE 1 #define disk_read(s, a, b) disk_io(READ, s, a, b) #define disk_write(s, a, b) disk_io(WRITE, s, a, b) #define FIND 3 #define LABEL 4 #define ENTRY 5 #define find_entry(d, e, p) directory(d, e, FIND, p) #define list_dir(d, e, f) (void) directory(d, e, f, NIL_PTR) #define label() directory(root, root_entries, LABEL, NIL_PTR) #define new_entry(d, e) directory(d, e, ENTRY, NIL_PTR) #define is_dir(d) ((d)->d_attribute & SUB_DIR) #define EOF 0400 #define EOF_MARK '\032' #define STD_OUT 1 #define flush() print(STD_OUT, NIL_PTR, 0) short disk; unsigned char fat[MAX_FAT_SIZE]; DIRECTORY root[MAX_ROOT_ENTRIES]; DIRECTORY save_entry; char null[MAX_CLUSTER_SIZE], device[] = DRIVE, path[128]; long mark; short total_clusters, cluster_size, fat_size, root_entries, data_start, sub_entries; BOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir; DIRECTORY *directory(), *read_cluster(); unsigned short free_cluster(), next_cluster(); char *make_name(), *num_out(), *slash(), *brk(); long lseek(), time(); leave(nr) short nr; { (void) umount(device); exit(nr); } usage(prog_name) register char *prog_name; { print_string(TRUE, "Usage: %s [%s\n", prog_name, dos_dir ? "-lr] drive [dir]" : "-a] drive file"); exit(1); } main(argc, argv) int argc; register char *argv[]; { register char *arg_ptr = slash(argv[0]); DIRECTORY *entry; short index = 1; char dev_nr = '0'; unsigned char fat_check; if (!strcmp(arg_ptr, "dosdir")) dos_dir = TRUE; else if (!strcmp(arg_ptr, "dosread")) dos_read = TRUE; else if (!strcmp(arg_ptr, "doswrite")) dos_write = TRUE; else { print_string(TRUE, "Program should be named dosread, doswrite or dosdir.\n"); exit(1); } if (argc == 1) usage(argv[0]); if (argv[1][0] == '-') { for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) { if (*arg_ptr == 'l' && dos_dir) Lflag = TRUE; else if (*arg_ptr == 'r' && dos_dir) Rflag = TRUE; else if (*arg_ptr == 'a' && !dos_dir) Aflag = TRUE; else usage(argv[0]); } index++; } if (index == argc) usage(argv[0]); if ((dev_nr = *argv[index++]) < '0' || dev_nr > '9') usage(argv[0]); device[DRIVE_NR] = dev_nr; if ((disk = open(device, 2)) < 0) { print_string(TRUE, "Cannot open %s\n", device); exit(1); } disk_read(FAT_START, fat, MAX_FAT_SIZE); if (fat[0] == DDDD) { /* Double-sided double-density 9 s/t */ total_clusters = 355; /* 720 - 7 - 2 - 2 - 1 */ cluster_size = 1024; /* 2 sectors per cluster */ fat_size = 1024; /* 2 sectors */ data_start = 6144; /* Starts on sector #12 */ root_entries = 112; sub_entries = 32; /* 1024 / 32 */ } else if (fat[0] == DDHD) { /* Double-sided high-density 15 s/t */ total_clusters = 2372; /* 2400 - 14 - 7 - 7 - 1 */ cluster_size = 512; /* 1 sector per cluster */ fat_size = 3584; /* 7 sectors */ data_start = 14848; /* Starts on sector #29 */ root_entries = 224; sub_entries = 16; /* 512 / 32 */ } else { print_string(TRUE, "Diskette is not DOS 2.0 360K or 1.2M\n"); leave(1); } disk_read(FAT_START + (long) fat_size, &fat_check, sizeof(fat_check)); if (fat_check != fat[0]) { print_string(TRUE, "Disk type in FAT copy differs from disk type in FAT original.\n"); leave(1); } disk_read(FAT_START + 2L * (long) fat_size, root, DIR_SIZE * root_entries); if (dos_dir) { entry = label(); print_string(FALSE, "Volume in drive %c ", dev_nr); if (entry == NIL_DIR) print(STD_OUT, "has no label.\n\n", 0); else print_string(FALSE, "is %S\n\n", entry->d_name); } if (argv[index] == NIL_PTR) { if (!dos_dir) usage(argv[0]); print(STD_OUT, "Root directory:\n", 0); list_dir(root, root_entries, FALSE); free_blocks(); flush(); leave(0); } for (arg_ptr = argv[index]; *arg_ptr; arg_ptr++) if (*arg_ptr == '\\') *arg_ptr = '/'; else if (*arg_ptr >= 'a' && *arg_ptr <= 'z') *arg_ptr += ('A' - 'a'); if (*--arg_ptr == '/') *arg_ptr = '\0'; /* skip trailing '/' */ add_path(argv[index], FALSE); add_path("/", FALSE); if (dos_dir) print_string(FALSE, "Directory %s:\n", path); entry = find_entry(root, root_entries, argv[index]); if (dos_dir) { list_dir(entry, sub_entries, FALSE); free_blocks(); } else if (dos_read) extract(entry); else { if (entry != NIL_DIR) { flush(); if (is_dir(entry)) print_string(TRUE, "%s is a directory.\n", path); else print_string(TRUE, "%s already exists.\n", argv[index]); leave(1); } add_path(NIL_PTR, TRUE); if (*path) make_file(find_entry(root, root_entries, path), sub_entries, slash(argv[index])); else make_file(root, root_entries, argv[index]); } (void) close(disk); flush(); leave(0); } DIRECTORY *directory(dir, entries, function, pathname) DIRECTORY *dir; short entries; BOOL function; register char *pathname; { register DIRECTORY *dir_ptr = dir; DIRECTORY *mem = NIL_DIR; unsigned short cl_no = dir->d_cluster; unsigned short type, last; char file_name[14]; char *name; int i = 0; if (function == FIND) { while (*pathname != '/' && *pathname && i < 12) file_name[i++] = *pathname++; while (*pathname != '/' && *pathname) pathname++; file_name[i] = '\0'; } do { if (entries != root_entries) { mem = dir_ptr = read_cluster(cl_no); last = cl_no; cl_no = next_cluster(cl_no); } for (i = 0; i < entries; i++, dir_ptr++) { type = dir_ptr->d_name[0] & 0x0FF; if (function == ENTRY) { if (type == NOT_USED || type == ERASED) { mark = lseek(disk, 0L, 1) - (long) cluster_size + (long) i * (long) DIR_SIZE; if (!mem) mark += (long) cluster_size - (long) (root_entries * sizeof (DIRECTORY)); return dir_ptr; } continue; } if (type == NOT_USED) break; if (dir_ptr->d_attribute & 0x08) { if (function == LABEL) return dir_ptr; continue; } if (type == DIR || type == ERASED || function == LABEL) continue; type = is_dir(dir_ptr); name = make_name(dir_ptr, (function == FIND) ? FALSE : type); if (function == FIND) { if (strcmp(file_name, name) != 0) continue; if (!type) { if (dos_dir || *pathname) { flush(); print_string(TRUE, "Not a directory: %s\n", file_name); leave(1); } } else if (*pathname == '\0' && dos_read) { flush(); print_string(TRUE, "%s is a directory.\n", path); leave(1); } if (*pathname) { dir_ptr = find_entry(dir_ptr, sub_entries, pathname + 1); } if (mem) { if (dir_ptr) { bcopy(dir_ptr, &save_entry, DIR_SIZE); dir_ptr = &save_entry; } (void) brk(mem); } return dir_ptr; } else { if (function == FALSE) show(dir_ptr, name); else if (type) { /* Recursive */ print_string(FALSE, "Directory %s%s:\n", path, name); add_path(name, FALSE); list_dir(dir_ptr, sub_entries, FALSE); add_path(NIL_PTR, FALSE); } } } if (mem) (void) brk(mem); } while (cl_no != LAST_CLUSTER && mem); switch (function) { case FIND: if (dos_write && *pathname == '\0') return NIL_DIR; flush(); print_string(TRUE, "Cannot find `%s'.\n", file_name); leave(1); case LABEL: return NIL_DIR; case ENTRY: if (!mem) { flush(); print_string(TRUE, "No entries left in root directory.\n"); leave(1); } cl_no = free_cluster(TRUE); link_fat(last, cl_no); link_fat(cl_no, LAST_CLUSTER); disk_write(clus_add(cl_no), null, cluster_size); return new_entry(dir, entries); case FALSE: if (Rflag) { print(STD_OUT, "\n", 0); list_dir(dir, entries, TRUE); } } } extract(entry) register DIRECTORY *entry; { register unsigned short cl_no = entry->d_cluster; char buffer[MAX_CLUSTER_SIZE]; short rest; if (entry->d_size == 0) /* Empty file */ return; if (Aflag) entry->d_size--; do { disk_read(clus_add(cl_no), buffer, cluster_size); rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size; print(STD_OUT, buffer, rest); entry->d_size -= (long) rest; cl_no = next_cluster(cl_no); if (cl_no == BAD) { flush(); print_string(TRUE, "Reserved cluster value encountered.\n"); leave(1); } } while (entry->d_size && cl_no != LAST_CLUSTER); if (cl_no != LAST_CLUSTER) print_string(TRUE, "Too many clusters allocated for file.\n"); else if (entry->d_size != 0) print_string(TRUE, "Premature EOF: %L bytes left.\n", entry->d_size); } print(fd, buffer, bytes) short fd; register char *buffer; register short bytes; { static short index; static BOOL lf_pending = FALSE; static char output[MAX_CLUSTER_SIZE + 1]; if (buffer == NIL_PTR) { if (dos_read && Aflag && lf_pending) { output[index++] = '\r'; lf_pending = FALSE; } if (write(fd, output, index) != index) bad(); index = 0; return; } if (bytes == 0) bytes = strlen(buffer); while (bytes--) { if (index >= MAX_CLUSTER_SIZE) { if (write(fd, output, index) != index) bad (); index = 0; } if (dos_read && Aflag) { if (*buffer == '\r') { if (lf_pending) output[index++] = *buffer++; else { lf_pending = TRUE; buffer++; } } else if (*buffer == '\n') { output[index++] = *buffer++; lf_pending = FALSE; } else if (lf_pending) { output[index++] = '\r'; output[index++] = *buffer++; } else if ((output[index++] = *buffer++) == EOF_MARK) { if (lf_pending) { output[index - 1] = '\r'; output[index++] = EOF_MARK; lf_pending = FALSE; } return; } } else output[index++] = *buffer++; } } make_file(dir_ptr, entries, name) DIRECTORY *dir_ptr; int entries; char *name; { register DIRECTORY *entry = new_entry(dir_ptr, entries); register char *ptr; char buffer[MAX_CLUSTER_SIZE]; unsigned short cl_no, next; short i, r; long size = 0L; bcopy(" ",&entry->d_name[0],11); /* clear entry */ for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++) entry->d_name[i] = *ptr++; while (*ptr != '.' && *ptr) ptr++; if (*ptr == '.') ptr++; for (i=0;i < 3 && *ptr; i++) entry->d_ext[i] = *ptr++; for (i = 0; i < 10; i++) entry->d_reserved[i] = '\0'; entry->d_attribute = '\0'; entry->d_cluster = 0; while ((r = fill(buffer)) > 0) { if ((next = free_cluster(FALSE)) > total_clusters) { print_string(TRUE, "Diskette full. File truncated.\n"); break; } disk_write(clus_add(next), buffer, r); if (entry->d_cluster == 0) cl_no = entry->d_cluster = next; else { link_fat(cl_no, next); cl_no = next; } size += r; } if (entry->d_cluster != 0) link_fat(cl_no, LAST_CLUSTER); entry->d_size = Aflag ? (size - 1) : size; /* Strip added ^Z */ fill_date(entry); disk_write(mark, entry, DIR_SIZE); disk_write(FAT_START, fat, fat_size); disk_write(FAT_START + (long) fat_size, fat, fat_size); } #define SEC_MIN 60L #define SEC_HOUR (60L * SEC_MIN) #define SEC_DAY (24L * SEC_HOUR) #define SEC_YEAR (365L * SEC_DAY) #define SEC_LYEAR (366L * SEC_DAY) short mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; fill_date(entry) DIRECTORY *entry; { register long cur_time = time((long *) 0) - DOS_TIME; unsigned short year = 0, month = 1, day, hour, minutes, seconds; int i; long tmp; if (cur_time < 0) /* Date not set on booting ... */ cur_time = 0; for (;;) { tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR; if (cur_time < tmp) break; cur_time -= tmp; year++; } day = (unsigned short) (cur_time / SEC_DAY); cur_time -= (long) day *SEC_DAY; hour = (unsigned short) (cur_time / SEC_HOUR); cur_time -= (long) hour *SEC_HOUR; minutes = (unsigned short) (cur_time / SEC_MIN); cur_time -= (long) minutes *SEC_MIN; seconds = (unsigned short) cur_time; mon_len[1] = (year % 4 == 0) ? 29 : 28; i = 0; while (day >= mon_len[i]) { month++; day -= mon_len[i++]; } day++; entry->d_date = (year << 9) | (month << 5) | day; entry->d_time = (hour << 11) | (minutes << 5) | seconds; } char *make_name(dir_ptr, dir_fl) register DIRECTORY *dir_ptr; short dir_fl; { static char name_buf[14]; register char *ptr = name_buf; short i; for (i = 0; i < 8; i++) *ptr++ = dir_ptr->d_name[i]; while (*--ptr == ' '); ptr++; if (dir_ptr->d_ext[0] != ' ') { *ptr++ = '.'; for (i = 0; i < 3; i++) *ptr++ = dir_ptr->d_ext[i]; while (*--ptr == ' '); ptr++; } if (dir_fl) *ptr++ = '/'; *ptr = '\0'; return name_buf; } fill(buffer) register char *buffer; { static BOOL eof_mark = FALSE; char *last = &buffer[cluster_size]; char *begin = buffer; register short c; if (eof_mark) return 0; while (buffer < last) { if ((c = get_char()) == EOF) { eof_mark = TRUE; if (Aflag) *buffer++ = EOF_MARK; break; } *buffer++ = c; } return (int) (buffer - begin); } get_char() { static short read_chars, index; static char input[MAX_CLUSTER_SIZE]; static BOOL new_line = FALSE; if (new_line == TRUE) { new_line = FALSE; return '\n'; } if (index == read_chars) { if ((read_chars = read(0, input, cluster_size)) == 0) return EOF; index = 0; } if (Aflag && input[index] == '\n') { new_line = TRUE; index++; return '\r'; } return input[index++]; } #define HOUR 0xF800 /* Upper 5 bits */ #define MIN 0x07E0 /* Middle 6 bits */ #define YEAR 0xFE00 /* Upper 7 bits */ #define MONTH 0x01E0 /* Mid 4 bits */ #define DAY 0x01F /* Lowest 5 bits */ char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; modes(mode) register unsigned char mode; { print_string(FALSE, "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-', (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-', (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-'); } show(dir_ptr, name) DIRECTORY *dir_ptr; char *name; { register unsigned short e_date = dir_ptr->d_date; register unsigned short e_time = dir_ptr->d_time; unsigned short next; char bname[20]; short i = 0; while (*name && *name != '/') bname[i++] = *name++; bname[i] = '\0'; if (!Lflag) { print_string(FALSE, "%s\n", bname); return; } modes(dir_ptr->d_attribute); print_string(FALSE, "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t"); i = 1; if (is_dir(dir_ptr)) { next = dir_ptr->d_cluster; while ((next = next_cluster(next)) != LAST_CLUSTER) i++; print_string(FALSE, "%L", (long) i * (long) cluster_size); } else print_string(FALSE, "%L", dir_ptr->d_size); print_string(FALSE, "\t%N:%N %P %s %d\n", ((e_time & HOUR) >> 11), ((e_time & MIN) >> 5), (e_date & DAY), month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980); } free_blocks() { register unsigned short cl_no; register short free = 0; short bad = 0; for (cl_no = 2; cl_no <= total_clusters; cl_no++) { switch (next_cluster(cl_no)) { case FREE: free++; break; case BAD: bad++; } } print_string(FALSE, "Free space: %L bytes.\n", (long) free * (long) cluster_size); if (bad) print_string(FALSE, "Bad sectors: %L bytes.\n", (long) bad * (long) cluster_size); } char *num_out(number) register long number; { static char num_buf[13]; char temp[13]; register short i = 0; short j; if (number == 0) temp[i++] = '0'; while (number) { temp[i++] = (char) (number % 10L + '0'); number /= 10L; } for (j = 0; j < 11; j++) num_buf[j] = temp[i - j - 1]; num_buf[i] = '\0'; return num_buf; } /* VARARGS */ print_string(err_fl, fmt, args) BOOL err_fl; char *fmt; int args; { char buf[200]; register char *buf_ptr = buf; char *scan_ptr; register int *arg_ptr = &args; short i; while (*fmt) { if (*fmt == '%') { fmt++; if (*fmt == 'c') { *buf_ptr++ = (char) *arg_ptr++; fmt++; continue; } if (*fmt == 'S') { scan_ptr = (char *) *arg_ptr; for (i = 0; i < 11; i++) *buf_ptr++ = *scan_ptr++; fmt++; continue; } if (*fmt == 's') scan_ptr = (char *) *arg_ptr; else if (*fmt == 'L') { scan_ptr = num_out(*((long *) arg_ptr)); arg_ptr++; } else { scan_ptr = num_out((long) *arg_ptr); if (*fmt == 'P' && *arg_ptr < 10) *buf_ptr++ = ' '; else if (*fmt == 'N' && *arg_ptr < 10) *buf_ptr++ = '0'; } while (*buf_ptr++ = *scan_ptr++); buf_ptr--; arg_ptr++; fmt++; } else *buf_ptr++ = *fmt++; } *buf_ptr = '\0'; if (err_fl) { flush(); write(2, buf, (int) (buf_ptr - buf)); } else print(STD_OUT, buf, 0); } DIRECTORY *read_cluster(cluster) register unsigned short cluster; { register DIRECTORY *sub_dir; extern char *sbrk(); if ((sub_dir = (DIRECTORY *) sbrk(cluster_size)) < 0) { print_string(TRUE, "Cannot set break!\n"); leave(1); } disk_read(clus_add(cluster), sub_dir, cluster_size); return sub_dir; } unsigned short free_cluster(leave_fl) BOOL leave_fl; { static unsigned short cl_index = 2; while (cl_index <= total_clusters && next_cluster(cl_index) != FREE) cl_index++; if (leave_fl && cl_index > total_clusters) { flush(); print_string(TRUE, "Diskette full. File not added.\n"); leave(1); } return cl_index++; } link_fat(cl_1, cl_2) unsigned short cl_1; register unsigned short cl_2; { register unsigned char *fat_index = &fat[(cl_1 >> 1) * 3 + 1]; if (cl_1 & 0x01) { *(fat_index + 1) = cl_2 >> 4; *fat_index = (*fat_index & 0x0F) | ((cl_2 & 0x0F) << 4); } else { *(fat_index - 1) = cl_2 & 0x0FF; *fat_index = (*fat_index & 0xF0) | (cl_2 >> 8); } } unsigned short next_cluster(cl_no) register unsigned short cl_no; { register unsigned char *fat_index = &fat[(cl_no >> 1) * 3 + 1]; if (cl_no & 0x01) cl_no = (*(fat_index + 1) << 4) | (*fat_index >> 4); else cl_no = ((*fat_index & 0x0F) << 8) | *(fat_index - 1); if ((cl_no & MASK) == MASK) cl_no = LAST_CLUSTER; else if ((cl_no & BAD) == BAD) cl_no = BAD; return cl_no; } char *slash(str) register char *str; { register char *result = str; while (*str) if (*str++ == '/') result = str; return result; } add_path(file, slash_fl) register char *file; BOOL slash_fl; { register char *ptr = path; while (*ptr) ptr++; if (file == NIL_PTR) { ptr--; do { ptr--; } while (*ptr != '/' && ptr != path); if (ptr != path && !slash_fl) ptr++; *ptr = '\0'; } else while (*ptr++ = *file++); } bcopy(src, dest, bytes) register char *src, *dest; short bytes; { while (bytes--) *dest++ = *src++; } disk_io(op, seek, address, bytes) register BOOL op; unsigned long seek; DIRECTORY *address; register unsigned bytes; { unsigned int r; if (lseek(disk, seek, 0) < 0L) { flush(); print_string(TRUE, "Bad lseek\n"); leave(1); } if (op == READ) r = read(disk, address, bytes); else r = write(disk, address, bytes); if (r != bytes) bad(); } bad() { flush(); perror("I/O error"); leave(1); } /* echo - echo arguments Author: Andy Tanenbaum */ #define SIZE 2048 char buf[SIZE]; int count; main(argc, argv) int argc; char *argv[]; { register int i, nflag; nflag = 0; if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n') { nflag++; argc--; argv++; } for(i = 1; i < argc; i++) { collect(argv[i]); if (i < argc - 1) collect(" "); } if (nflag == 0) collect("\n"); /* Print accumulated output. */ if (count > 0) write(1, buf, count); exit(0); } collect(s) char *s; { /* Collect characters. For efficiency, write them in large chunks. */ char c; if (count == SIZE) {write(1, buf, count); count = 0;} while ( (c = *s++) != 0) { if (count < SIZE && c != '"') buf[count++] = c; } } /* fdisk - partition a hard disk Author: Jakob Schripsema */ /* * First run the DOS utilities FDISK and FORMAT. FDISK * puts the boot code in sector 0. * Then run fdisk * * fdisk /dev/hdx (MINIX) * fdisk x: (DOS) * * Compiling * * cc -o fdisk -DUNIX fdisk.c (MINIX) * cl -DDOS fdisk.c (DOS with MS C compiler) */ #include "stdio.h" #define UNIX /* for MINIX */ #ifdef DOS #include #endif /* * Constants */ #define NHEAD 4 /* # heads */ #define NSEC 17 /* sectors / track */ #define SECSIZE 512 /* sector size */ #define OK 0 #define ERR 1 #define TABLEOFFSET 0x1be /* offset in boot sector*/ /* * Description of entry in partition table */ struct part_entry { char bootind; /* boot indicator 0/0x80 */ char start_head; /* head value for first sector */ char start_sec; /* sector value for first sector*/ char start_cyl; /* track value for first sector */ char sysind; /* system indicator 00=?? 01=DOS*/ char last_head; /* head value for last sector */ char last_sec; /* sector value for last sector */ char last_cyl; /* track value for last sector */ long lowsec; /* logical first sector */ long size; /* size of partion in sectors */ }; /* * Globals */ char secbuf[SECSIZE]; char *devname; char *dosstr = " DOS "; char *ndosstr = "Non-DOS"; #ifdef DOS union REGS regs; struct SREGS sregs; int drivenum; #endif #ifdef UNIX int devfd; #endif main(argc,argv) int argc; char *argv[]; { char ch; /* init */ if (argc != 2) { printf("Usage: fdisk /dev/hdx\n"); exit(1); } devname = argv[1]; getboot(secbuf); /* get boot sector */ do { dpl_partitions(); print_menu(); ch = get_a_char(); putchar('\n'); switch (ch) { case 'c' : change_table(); break; case 'w' : if (chk_table() == OK) { putboot(secbuf); exit(0); } break; case 'l' : load_from_file(); break; case 's' : save_to_file(); break; case 'p' : dump_table(); break; case 'q' : exit(0); default : printf(" %c ????\n",ch); } } while (1); } /* * Read boot sector */ #ifdef DOS getboot(buffer) char *buffer; { segread(&sregs); /* get ds */ if (devname[1] != ':') { printf("Invalid drive %s\n",devname); exit(1); } if (*devname >= 'a') *devname += 'A' - 'a'; drivenum = (*devname - 'C') & 0xff; if (drivenum < 0 || drivenum > 7) { printf("Funny drive number %d\n",drivenum); exit(1); } regs.x.ax = 0x201; /* read 1 sectors */ regs.h.ch = 0; /* track */ regs.h.cl = 1; /* first sector = 1 */ regs.h.dh = 0; /* head = 0 */ regs.h.dl = 0x80+drivenum;/* drive = 0 */ sregs.es = sregs.ds; /* buffer address */ regs.x.bx = (int)secbuf; int86x(0x13,®s,®s,&sregs); if (regs.x.cflag) { printf("Cannot read boot sector\n"); exit(1); } } #endif #ifdef UNIX getboot(buffer) char *buffer; { devfd = open(devname,2); if (devfd < 0) { printf("Cannot open device %s\n",devname); exit(1); } if (read(devfd,buffer,SECSIZE) != SECSIZE) { printf("Cannot read boot sector\n"); exit(2); } } #endif /* * Write boot sector */ #ifdef DOS putboot(buffer) char *buffer; { regs.x.ax = 0x301; /* read 1 sectors */ regs.h.ch = 0; /* track */ regs.h.cl = 1; /* first sector = 1 */ regs.h.dh = 0; /* head = 0 */ regs.h.dl = 0x80+drivenum;/* drive = 0 */ sregs.es = sregs.ds; /* buffer address */ regs.x.bx = (int)secbuf; int86x(0x13,®s,®s,&sregs); if (regs.x.cflag) { printf("Cannot write boot sector\n"); exit(1); } } #endif #ifdef UNIX putboot(buffer) char *buffer; { int r; if (lseek(devfd,0L,0) < 0) { printf("Seek error during write\n"); exit(1); } if (write(devfd,buffer,SECSIZE) != SECSIZE) { printf("Write error\n"); exit(1); } sync(); } #endif /* * Load buffer from file */ load_from_file() { char file[80]; int fd; printf("Enter file name: "); gets(file); #ifdef UNIX fd = open(file,0); #endif #ifdef DOS fd = open(file,0x8000); #endif if (fd < 0) { fprintf(stderr,"Cannot load from %s\n",file); exit(1); } if (read(fd,secbuf,SECSIZE) != SECSIZE) { fprintf(stderr,"Read error\n"); exit(1); } close(fd); } /* * Save to file */ save_to_file() { char file[80]; int fd; printf("Enter file name: "); gets(file); #ifdef UNIX fd = creat(file,0644); #endif #ifdef DOS fd = creat(file,0644); if (fd < 0) { fprintf(stderr,"Cannot creat %s\n",file); exit(1); } close(fd); fd = open(file,0x8001); #endif if (fd < 0) { fprintf(stderr,"Cannot save to %s\n",file); exit(1); } if (write(fd,secbuf,SECSIZE) != SECSIZE) { fprintf(stderr,"Write error\n"); exit(1); } close(fd); } /* * Dump partition table */ dump_table() { struct part_entry *pe; int i; pe = (struct part_entry *)&secbuf[TABLEOFFSET]; printf("\n --first--- ---last---\n"); printf("Prt ac hd sec cyl sys hd sec cyl low size\n"); for (i = 1 ; i < 5 ; i++) { printf(" %x %2x %x %2x %2x %2x %x %2x %2x %6D %9D\n", i, pe->bootind & 0xff, pe->start_head & 0xff, pe->start_sec & 0xff, pe->start_cyl & 0xff, pe->sysind & 0xff, pe->last_head & 0xff, pe->last_sec & 0xff, pe->last_cyl & 0xff, pe->lowsec, pe->size); pe++; } } /* * Display partition table */ dpl_partitions() { struct part_entry *pe; int i; printf("\nPartition Type Begin End Active\n"); pe = (struct part_entry *)&secbuf[TABLEOFFSET]; for (i = 1 ; i <= 4 ; i++) { dpl_entry(i,pe); pe++; } } /* * Display an entry */ dpl_entry(number,entry) int number; struct part_entry *entry; { int low_cyl,high_cyl,temp; char *typestring; char active; if (entry->sysind == 0x01) typestring = dosstr; else typestring = ndosstr; printf("%5d %s ",number,typestring); temp = entry->start_sec & 0xc0; low_cyl = (entry->start_cyl & 0xff) + (temp << 2); temp = entry->last_sec & 0xc0; high_cyl = (entry->last_cyl & 0xff) + (temp << 2); printf("%4d %4d",low_cyl,high_cyl); if ((entry->bootind & 0xff) == 0x80) active = 'A'; else active = 'N'; printf(" %c\n",active); } /* * Check partition table */ chk_table() { struct part_entry *pe; int i; int active; long limit; pe = (struct part_entry *)&secbuf[TABLEOFFSET]; limit = 0L; active = 0; for (i = 1 ; i < 5 ; i++) { if (pe->size == 0L) return(OK); if (pe->lowsec <= limit) { printf("Overlap between part. %d and %d\n",i,i-1); return(ERR); } limit = pe->lowsec + pe->size - 1L; if (pe->bootind == 0x80) active++; pe++; } if (active > 1) { printf("%d active partitions\n",active); return(ERR); } return(OK); } /* * Check entry * head/sector/track info must match logical sector number * Used to check 'foreign' partition table during debugging */ chk_entry(entry) struct part_entry *entry; { char head; char sector; char track; sec_to_hst(entry->lowsec,&head,§or,&track); if ( (head != entry->start_head) || (sector != entry->start_sec) || (track != entry->start_cyl)) return(ERR); sec_to_hst(entry->lowsec + entry->size - 1L,&head,§or,&track); if ( (head != entry->last_head) || (sector != entry->last_sec) || (track != entry->last_cyl)) return(ERR); return(OK); } /* * Convert a logical sector number to * head / sector / track */ sec_to_hst(logsec,hd,sec,cyl) long logsec; char *hd,*sec,*cyl; { int bigcyl; bigcyl = logsec / (NHEAD * NSEC); *sec = (logsec % NSEC) + 1 + ((bigcyl >> 2) & 0xc0); *cyl = bigcyl & 0xff; *hd = (logsec % (NHEAD * NSEC)) / NSEC; } /* * change partition table */ change_table() { struct part_entry *pe; int i,temp,low_cyl,high_cyl; char ch; pe = (struct part_entry *)&secbuf[TABLEOFFSET]; for (i = 1 ; i <= 4 ; i++) { temp = pe->start_sec & 0xc0; low_cyl = (pe->start_cyl & 0xff) + (temp << 2); temp = pe->last_sec & 0xc0; high_cyl = (pe->last_cyl & 0xff) + (temp << 2); printf("Partition %d from %d to %d. Change? (y/n) ", i,low_cyl,high_cyl); ch = get_a_char(); if (ch == 'y' || ch == 'Y') get_partition(pe); pe++; } putchar('\n'); } /* * Get partition info : first & last cylinder */ get_partition(entry) struct part_entry *entry; { char buf[80]; int first,last; long low,high; char ch; printf(" Enter first cylinder: "); gets(buf); sscanf(buf,"%d",&first); printf(" Enter last cylinder: "); gets(buf); sscanf(buf,"%d",&last);; if (first == 0 && last == 0) { entry->bootind = 0; entry->start_head = 0; entry->start_sec = 0; entry->start_cyl = 0; entry->sysind = 0; entry->last_head = 0; entry->last_sec = 0; entry->last_cyl = 0; entry->lowsec = 0L; entry->size = 0L ; return; } low = first & 0xffff; low = low * NSEC * NHEAD; if (low == 0) low = 1; /* sec0 is master boot record */ high = last & 0xffff; high = (high + 1)*NSEC*NHEAD - 1; entry->lowsec = low; entry->size = high - low + 1; sec_to_hst(low, &entry->start_head, &entry->start_sec, &entry->start_cyl); sec_to_hst(high, &entry->last_head, &entry->last_sec, &entry->last_cyl); printf(" DOS partition? (y/n) "); ch = get_a_char(); if (ch == 'y' || ch == 'Y') entry->sysind = 1; else entry->sysind = 0; printf(" Active partition? (y/n) "); ch = get_a_char(); if (ch == 'y' || ch == 'Y') entry->bootind = 0x80; else entry->bootind = 0; } /* * Read 1 character and discard rest of line */ get_a_char() { char ch; ch = getchar(); if (ch != '\n') while (getchar() != '\n'); return(ch); } print_menu() { printf("\nType a command letter, then a carriage return:\n"); printf(" c - change a partition\n"); printf(" w - write changed partition table back to disk and exit\n"); printf(" q - quit without making any changes\n"); printf(" s - save boot block (including partition table) on a file\n"); printf(" l - load boot block (including partition table) from a file\n"); printf(" p - print partition table\n\n"); } /* find - look for files satisfying a predicat Author: Erik Baalbergen */ /* *** Check the switches in the SWITCHES section below. *** Differences from UNIX version 7 find(1): * -name: no name allowed; only uid e.g. find all core files: "find . -name core -a -print" The "-atime" may not work well on Minix. Please report bugs and suggestions to erikb@cs.vu.nl */ #include "stdio.h" /*######################## SWITCHES ##############################*/ #include "stat.h" #define SHELL "/usr/bin/sh" #define PLEN 256 /* maximum path length; overflows are not detected */ #define DIRSIZ 16 /* size of a directory entry */ #define MAXARG 256 /* maximum length for an argv */ #define NPATHS 256 /* maximum number of paths in path-list */ #define BSIZE 1024 /* bytes per block */ /*######################## DEFINITIONS ##############################*/ #define SECS_PER_DAY (24L * 60L * 60L) /* check your planet */ struct exec { int e_cnt; char *e_vec[MAXARG]; }; #define OP_NAME 1 #define OP_PERM 2 #define OP_TYPE 3 #define OP_LINKS 4 #define OP_USER 5 #define OP_GROUP 6 #define OP_SIZE 7 #define OP_INUM 8 #define OP_ATIME 9 #define OP_MTIME 10 #define OP_EXEC 11 #define OP_OK 12 #define OP_PRINT 13 #define OP_NEWER 14 #define OP_AND 15 #define OP_OR 16 struct oper { char *op_str; int op_val; } ops[] = { {"name", OP_NAME}, {"perm", OP_PERM}, {"type", OP_TYPE}, {"links", OP_LINKS}, {"user", OP_USER}, {"group", OP_GROUP}, {"size", OP_SIZE}, {"inum", OP_INUM}, {"atime", OP_ATIME}, {"mtime", OP_MTIME}, {"exec", OP_EXEC}, {"ok", OP_OK}, {"print", OP_PRINT}, {"newer", OP_NEWER}, {"a", OP_AND}, {"o", OP_OR}, {0, 0} }; #define EOI -1 #define NONE 0 #define LPAR 20 #define RPAR 21 #define NOT 22 char *prog, *strcpy(), *Malloc(), *find_bin(); struct node { int n_type; /* any OP_ or NOT */ union { char *n_str; struct { long n_val; int n_sign; } n_int; struct exec *n_exec; struct { struct node *n_left, *n_right; } n_opnd; } n_info; }; struct node *expr(); char **ipp; int tty; /* fd for /dev/tty when using -ok */ long current_time; char * Malloc(n) { char *malloc(), *m; if ((m = malloc(n)) == 0) fatal("out of memory", ""); return m; } char * Salloc(s) char *s; { return strcpy(Malloc(strlen(s) + 1), s); } main(argc, argv) char *argv[]; { char *pathlist[NPATHS]; int pathcnt = 0; register i; struct node *pred; prog = *argv++; while (--argc > 0 && lex(*argv) == NONE) pathlist[pathcnt++] = *argv++; if (pathcnt == 0 || argc == 0) fatal("Usage: path-list predicate-list", ""); ipp = argv; time(¤t_time); pred = expr(lex(*ipp)); if (lex(*++ipp) != EOI) fatal("syntax error: garbage at end of predicate", ""); for (i = 0; i < pathcnt; i++) find(pathlist[i], pred, ""); exit(0); } find(path, pred, last) char *path, *last; struct node *pred; { char spath[PLEN], ent[DIRSIZ + 1]; struct stat st; register char *send = spath; FILE *fp, *fopen(); if (path[1] == '\0' && *path == '/') { *send++ = '/'; *send = '\0'; } else while (*send++ = *path++) {} if (stat(spath, &st) == -1) nonfatal("can't get status of ", spath); else { (void) check(spath, &st, pred, last); if ((st.st_mode & S_IFMT) == S_IFDIR) { if ((fp = fopen(spath, "r")) == NULL) { nonfatal("can't read directory ", spath); return; } send[-1] = '/'; ent[DIRSIZ] = '\0'; while (fread(ent, DIRSIZ, 1, fp) == 1) { if (!((*ent == '\0' && ent[1] == '\0') || (ent[2] == '.') && (ent[3] == '\0' || (ent[3] == '.' && ent[4] == '\0')) )) { strcpy(send, ent + 2); find(spath, pred, ent + 2); } } fclose(fp); } } } check(path, st, n, last) char *path, *last; register struct stat *st; register struct node *n; { switch (n->n_type) { case OP_AND: return check(path, st, n->n_info.n_opnd.n_left, last) && check(path, st, n->n_info.n_opnd.n_right, last); case OP_OR: return check(path, st, n->n_info.n_opnd.n_left, last) || check(path, st, n->n_info.n_opnd.n_right, last); case NOT: return !check(path, st, n->n_info.n_opnd.n_left, last); case OP_NAME: return smatch(last, n->n_info.n_str); case OP_PERM: if (n->n_info.n_int.n_sign < 0) return st->st_mode == (int) n->n_info.n_int.n_val; return (st->st_mode & 0777) == (int) n->n_info.n_int.n_val; case OP_NEWER: return st->st_mtime > n->n_info.n_int.n_val; case OP_TYPE: return (st->st_mode & S_IFMT) == n->n_info.n_int.n_val; case OP_LINKS: return ichk((long)(st->st_nlink), n); case OP_USER: return st->st_uid == n->n_info.n_int.n_val; case OP_GROUP: return st->st_gid == n->n_info.n_int.n_val; case OP_SIZE: return ichk((st->st_size == 0) ? 0L : ((st->st_size - 1) / BSIZE + 1), n); case OP_INUM: return ichk((long)(st->st_ino), n); case OP_ATIME: return ichk(st->st_atime, n); case OP_MTIME: return ichk(st->st_mtime, n); case OP_EXEC: case OP_OK: return execute(n->n_type, n->n_info.n_exec, path); case OP_PRINT: prints("%s\n", path); return 1; } fatal("ILLEGAL NODE", ""); } ichk(val, n) long val; struct node *n; { switch (n->n_info.n_int.n_sign) { case 0: return val == n->n_info.n_int.n_val; case 1: return val > n->n_info.n_int.n_val; case -1: return val < n->n_info.n_int.n_val; } fatal("internal: bad n_sign", ""); } lex(str) char *str; { if (str == 0) return EOI; if (*str == '-') { register struct oper *op; str++; for (op = ops; op->op_str; op++) if (strcmp(str, op->op_str) == 0) break; return op->op_val; } if (str[1] == 0) { switch(*str) { case '(': return LPAR; case ')': return RPAR; case '!': return NOT; } } return NONE; } struct node * newnode(t) { struct node *n = (struct node*) Malloc(sizeof(struct node)); n->n_type = t; return n; } /*########################### PARSER ###################################*/ /* grammar: expr : primary | primary OR expr; primary : secondary | secondary AND primary | secondary primary; secondary : NOT secondary | LPAR expr RPAR | simple; simple : -OP args... */ struct node *expr(), *primary(), *secondary(), *simple(); number(str, base, pl, ps) char *str; long *pl; int *ps; { int up = '0' + base - 1; long val = 0; *ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0); while (*str >= '0' && *str <= up) val = base * val + *str++ - '0'; if (*str) fatal("syntax error: illegal numeric value", ""); *pl = val; } struct node * expr(t) { struct node *nd, *p, *nd2; nd = primary(t); if ((t = lex(*++ipp)) == OP_OR) { nd2 = expr(lex(*++ipp)); p = newnode(OP_OR); p->n_info.n_opnd.n_left = nd; p->n_info.n_opnd.n_right = nd2; return p; } ipp--; return nd; } struct node * primary(t) { struct node *nd, *p, *nd2; nd = secondary(t); if ((t = lex(*++ipp)) != OP_AND) { ipp--; if (t == EOI || t == RPAR || t == OP_OR) return nd; } nd2 = primary(lex(*++ipp)); p = newnode(OP_AND); p->n_info.n_opnd.n_left = nd; p->n_info.n_opnd.n_right = nd2; return p; } struct node * secondary(t) { struct node *n, *p; if (t == LPAR) { n = expr(lex(*++ipp)); if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", ""); return n; } if (t == NOT) { n = secondary(lex(*++ipp)); p = newnode(NOT); p->n_info.n_opnd.n_left = n; return p; } return simple(t); } checkarg(arg) char *arg; { if (arg == 0) fatal("syntax error, argument expected", ""); } struct node * simple(t) { struct node *p = newnode(t); struct exec *e; struct stat est; long l; switch (t) { case OP_TYPE: checkarg(*++ipp); switch (**ipp) { case 'b': p->n_info.n_int.n_val = S_IFBLK; break; case 'c': p->n_info.n_int.n_val = S_IFCHR; break; case 'd': p->n_info.n_int.n_val = S_IFDIR; break; case 'f': p->n_info.n_int.n_val = S_IFREG; break; default: fatal("-type needs b, c, d or f", ""); } break; case OP_LINKS: case OP_USER: case OP_GROUP: case OP_SIZE: case OP_INUM: case OP_PERM: checkarg(*++ipp); number(*ipp, (t == OP_PERM) ? 8 : 10, &(p->n_info.n_int.n_val), &(p->n_info.n_int.n_sign)); break; case OP_ATIME: case OP_MTIME: checkarg(*++ipp); number(*ipp, 10, &l, &(p->n_info.n_int.n_sign)); p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY; /* more than n days old means less than the absolute time */ p->n_info.n_int.n_sign *= -1; break; case OP_EXEC: case OP_OK: checkarg(*++ipp); e = (struct exec *)Malloc(sizeof(struct exec)); e->e_cnt = 2; e->e_vec[0] = SHELL; p->n_info.n_exec = e; while (*ipp) { if (**ipp == ';' && (*ipp)[1] == '\0') { e->e_vec[e->e_cnt] = 0; break; } e->e_vec[(e->e_cnt)++] = (**ipp == '{' && (*ipp)[1] == '}' && (*ipp)[2] == '\0') ? (char *)(-1) : *ipp; ipp++; } if (*ipp == 0) fatal("-exec/-ok: ; missing", ""); if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0) fatal("can't find program ", e->e_vec[2]); if (t == OP_OK) if ((tty = open("/dev/tty", 2)) < 0) fatal("can't open /dev/tty", ""); break; case OP_NEWER: checkarg(*++ipp); if (stat(*ipp, &est) == -1) fatal("-newer: can't get status of ", *ipp); p->n_info.n_int.n_val = est.st_mtime; break; case OP_NAME: checkarg(*++ipp); p->n_info.n_str = *ipp; break; case OP_PRINT: break; default: fatal("syntax error, operator expected", ""); } return p; } /*######################## DIAGNOSTICS ##############################*/ nonfatal(s1, s2) char *s1, *s2; { std_err(prog); std_err(": "); std_err(s1); std_err(s2); std_err("\n"); } fatal(s1, s2) char *s1, *s2; { nonfatal(s1, s2); exit(1); } /*################### SMATCH #########################*/ /* Don't try to understand the following one... */ smatch(s, t) /* shell-like matching */ char *s, *t; { register n; if (*t == '\0') return *s == '\0'; if (*t == '*') { ++t; do if (smatch(s,t)) return 1; while (*s++ != '\0'); return 0; } if (*s == '\0') return 0; if (*t == '\\') return (*s == *++t) ? smatch(++s, ++t) : 0; if (*t == '?') return smatch(++s, ++t); if (*t == '[') { while (*++t != ']') { if (*t == '\\') ++t; if (*(t+1) != '-') if (*t == *s) { while (*++t != ']') if (*t == '\\') ++t; return smatch(++s, ++t); } else continue; if (*(t+2) == ']') return (*s == *t || *s == '-'); n = (*(t+2) == '\\') ? 3 : 2; if (*s >= *t && *s <= *(t+n)) { while (*++t != ']') if (*t == '\\') ++t; return smatch(++s, ++t); } t += n; } return 0; } return (*s == *t) ? smatch(++s, ++t) : 0; } /*####################### EXECUTE ###########################*/ /* do -exec or -ok */ char *epath = 0; char * getpath() { extern char **environ; register char **e = environ; if (epath) /* retrieve PATH only once */ return epath; while (*e) { if (strncmp("PATH=", *e, 5) == 0) { return epath = *e + 5; } e++; } fatal("can't get PATH from environment", ""); } char * find_bin(s) char *s; { char *f, *l, buf[PLEN]; if (*s == '/') /* absolute path name */ return (access(s, 1) == 0) ? s : 0; l = f = getpath(); for (;;) { if (*l == ':' || *l == 0) { if (l == f) { if (access(s, 1) == 0) return Salloc(s); f++; } else { register char *p = buf, *q = s; while (f != l) *p++ = *f++; f++; *p++ = '/'; while (*p++ = *q++) {} if (access(buf, 1) == 0) return Salloc(buf); } if (*l == 0) break; } l++; } return 0; } execute(op, e, path) struct exec *e; char *path; { int s, pid; char *argv[MAXARG]; register char **p, **q; for (p = e->e_vec, q = argv; *p;) /* replace the {}s */ if ((*q++ = *p++) == (char *)-1) q[-1] = path; *q = '\0'; if (op == OP_OK) { char answer[10]; for (p = &argv[2]; *p; p++) { write(tty, *p, strlen(*p)); write(tty, " ", 1); } write(tty, "? ", 2); if (read(tty, answer, 10) < 2 || *answer != 'y') return 0; } if ((pid = fork()) == -1) fatal("can't fork", ""); if (pid == 0) { register i = 3; while (close(i++) == 0) {} /* wow!!! */ execv(argv[1], &argv[2]); /* binary itself? */ execv(argv[0], &argv[1]); /* shell command? */ fatal("exec failure: ", argv[1]); /* none of them! */ exit(127); } return wait(&s) == pid && s == 0; } main(argc, argv) int argc; char *argv[]; { char c; /* Echo argument, if present. */ if (argc == 2) { std_err(argv[1]); std_err("\n"); } close(0); open("/dev/tty0", 0); do { read(0, &c, 1); } while (c != '\n'); exit(0); } /* grep - search for a pattern Author: Martin C. Atkins */ /* * Search files for a regular expression * *<-xtx-*>cc -o grep grep.c -lregexp */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. * * The program was modified by Andy Tanenbaum. */ #include "regexp.h" #include "stdio.h" #define MAXLINE (1024) int status = 1; char *progname; int pmflag = 1; /* print lines which match */ int pnmflag = 0; /* print lines which don't match */ int nflag = 0; /* number the lines printed */ int args; extern char *index(); main(argc,argv) int argc; char *argv[]; { regexp *exp; char **argp = &argv[1]; if (!isatty(1)) setbuf(stdout); args = argc; progname = argv[0]; while(*argp != 0 && argp[0][0] == '-') { args--; /* flags don't count */ switch(argp[0][1]) { case 'v': pmflag = 0; pnmflag = 1; break; case 'n': nflag++; break; case 's': pmflag = pnmflag = 0; break; case 'e': argp++; goto out; default: usage(); } argp++; } out: if(*argp == 0) usage(); if((exp = regcomp(*argp++)) == NULL) { std_err("grep: regcomp failed\n"); done(2); } if(*argp == 0) match((char *)0,exp); else while(*argp) { int infd; if(strcmp(*argp,"-") == 0) match("-",exp); else { fclose(stdin); if(fopen(*argp, "r") == NULL) { std_err("Can't open "); std_err(*argp); std_err("\n"); status = 2; } else { match(*argp,exp); close(infd); } } argp++; } done(status); } /* * This routine actually matches the file */ match(name, exp) char *name; regexp *exp; { char buf[MAXLINE]; int lineno = 0; while(getline(buf,MAXLINE) != NULL) { char *cr = index(buf,'\n'); lineno++; if(cr == 0) { std_err("Line too long in "); std_err(name == 0 ? "stdin":name); } else *cr = '\0'; if(regexec(exp,buf)) { if(pmflag) pline(name,lineno,buf); if(status != 2) status = 0; } else if(pnmflag) pline(name,lineno,buf); } } void regerror(s) char *s; { std_err("grep: "); std_err(s); std_err("\n"); done(2); } pline(name, lineno, buf) char *name; int lineno; char buf[]; { if(name && args > 3) prints("%s:",name); if(nflag) prints("%s:", itoa(lineno)); prints("%s\n",buf); } usage() { std_err("Usage: grep [-v] [-n] [-s] [-e expr] expression [file ...]\n"); done(2); } getline(buf, size) char *buf; int size; { char *initbuf = buf, c; while (1) { c = getc(stdin); *buf++ = c; if (c <= 0) return(NULL); if (buf - initbuf == size - 1) return(buf - initbuf); if (c == '\n') return(buf - initbuf); } } done(n) int n; { fflush(stdout); exit(n); } /* gres - grep and substitute Author: Martin C. Atkins */ /* * globally search, and replace * *<-xtx-*>cc -o gres gres.c -lregexp */ /* * This program was written by: * Martin C. Atkins, * University of York, * Heslington, * York. Y01 5DD * England * and is released into the public domain, on the condition * that this comment is always included without alteration. */ #include "stdio.h" #include "regexp.h" #define MAXLINE (1024) int status = 1; char *usagemsg = "Usage: gres [-g] search replace [file ...]\n"; char *progname; int gflag = 0; /* != 0 => only do first substitution on line */ extern char *index(); FILE *fopen(); main(argc,argv) int argc; char *argv[]; { regexp *exp; char *repstr; char **argp = &argv[1]; progname = argv[0]; if(*argp != 0 && argp[0][0] == '-' && argp[0][1] == 'g') { gflag = 1; argp++,argc--; } if(argc < 3) { std_err(usagemsg); done(2); } if(argp[0][0] == '\0') { std_err("gres: null match string is silly\n"); done(2); } if((exp = regcomp(*argp++)) == NULL) { std_err("gres: regcomp failed\n"); done(2); } repstr = *argp++; if(*argp == 0) process(stdin,exp,repstr); else while(*argp) { FILE *inf; if(strcmp(*argp,"-") == 0) process(stdin,exp,repstr); else { if((inf = fopen(*argp,"r")) == NULL) { std_err("gres: Can't open "); std_err(*argp); std_err("\n"); status = 2; } else { process(inf,exp,repstr); fclose(inf); } } argp++; } done(status); } /* * This routine does the processing */ process(inf, exp, repstr) FILE *inf; regexp *exp; char *repstr; { char ibuf[MAXLINE]; while(fgets(ibuf,MAXLINE,inf) != NULL) { char *cr = index(ibuf,'\n'); if(cr == 0) std_err("gres: Line broken\n"); else *cr = '\0'; if(regexec(exp,ibuf,1)) { pline(exp,ibuf,repstr); if(status != 2) status = 0; } else printf("%s\n",ibuf); } } void regerror(s) char *s; { std_err("gres: "); std_err(s); std_err("\n"); done(2); } char * getbuf(exp, repstr) regexp *exp; char *repstr; { char *malloc(); void free(); static bufsize = 0; static char *buf = 0; int guess = 10; int ch; while(*repstr) { switch(*repstr) { case '&': guess += exp->endp[0] - exp->startp[0]; break; case '\\': if((ch = *++repstr) < '0' || ch > '9') guess += 2; else { ch -= '0'; guess += exp->endp[ch] - exp->startp[ch]; } break; default: guess++; } repstr++; } if(bufsize < guess) { if(buf != 0) free((char *)buf); buf = malloc(guess); } return buf; } pline(exp, ibuf, repstr) regexp *exp; char ibuf[]; char *repstr; { do { dosub(exp,ibuf,repstr); ibuf = exp->endp[0]; if(*ibuf == '\0') break; if(ibuf == exp->startp[0]) putchar(*ibuf++); } while(!gflag && regexec(exp,ibuf,0)); printf("%s\n",ibuf); } /* * print one subsitution */ dosub(exp,ibuf,repstr) regexp *exp; char ibuf[]; char *repstr; { char *buf = getbuf(exp, repstr); char *end = exp->startp[0]; int ch = *end; *end = '\0'; fputs(ibuf,stdout); /* output the initial part of line */ *end = ch; regsub(exp, repstr, buf); fputs(buf,stdout); } done(n) int n; { _cleanup(); /* flush stdio's internal buffers */ exit(n); } /* head - print the first few lines of a file Author: Andy Tanenbaum */ /* change to use putc() instead of prints() -- Dean Long 3/7/87 */ #include "stdio.h" #define DEFAULT 10 char buff[BUFSIZ]; main(argc, argv) int argc; char *argv[]; { int n, k, nfiles; char *ptr; /* Check for flag. Only flag is -n, to say how many lines to print. */ setbuf(stdout, buff); k = 1; ptr = argv[1]; n = DEFAULT; if (*ptr++ == '-') { k++; n = atoi(ptr); if (n <= 0) usage(); } nfiles = argc - k; if (nfiles == 0) { /* Print standard input only. */ do_file(n); fflush(stdout); exit(0); } /* One or more files have been listed explicitly. */ while (k < argc) { fclose(stdin); if (nfiles > 1) prints("==> %s <==\n", argv[k]); if (fopen(argv[k], "r") == NULL) prints("head: cannot open %s\n", argv[k]); else { do_file(n); fflush(stdout); } k++; if (k < argc) prints("\n"); } exit(0); } do_file(n) int n; { int c; /* Print the first 'n' lines of a file. */ while(n) switch (c = getc(stdin)) { case EOF : return; case '\n': --n; default : putc((char)c, stdout); } } usage() { std_err("Usage: head [-n] [file ...]\n"); exit(1); } /* kill - send a signal to a process Author: Adri Koppes */ #include "signal.h" main(argc,argv) int argc; char **argv; { int proc, signal = SIGTERM; if (argc < 2) usage(); if (*argv[1] == '-') { signal = atoi(&argv[1][1]); *argv++; argc--; } if (!signal) signal = SIGTERM; while(--argc) { *argv++; proc = atoi(*argv); if (!proc && strcmp(*argv, "0")) usage(); if (kill(proc,signal)) { prints("Kill: %s no such process\n", itoa(proc)); exit(1); } } exit(0); } usage() { prints("Usage: kill pid\n"); exit(1); } /* libpack - pack ASCII assembly code Author: Andy Tanenbaum */ #define BUFSIZ 20000 #define FS 1 #define WRITE 4 #define NILP (char *)0 char *table[] = { "push ax", "ret", "mov bp,sp", "push bp", "pop bp", "mov sp,bp", ".text", "xor ax,ax", "push 4(bp)", "pop bx", "pop si", "cbw", "movb al,(bx)", "pop ax", "xorb ah,ah", "mov ax,#1", "call _callm1", "add sp,#16", "mov bx,4(bp)", "push 6(bp)", "mov -2(bp),ax", "I0013:", "call .cuu", "mov ax,-2(bp)", "add 4(bp),#1", "or ax,ax", "jmp I0011", "mov bx,8(bp)", "push dx", "mov cx,#2", "mov bx,#2", "I0011:", "I0012:", "push -2(bp)", "mov ax,4(bp)", "mov ax,-4(bp)", "add sp,#6", "and ax,#255", "push bx", "mov bx,-2(bp)", "loop 2b", "jcxz 1f", ".word 4112", "mov ax,(bx)", "mov -4(bp),ax", "jmp I0013", ".data", "mov bx,6(bp)", "mov (bx),ax", "je I0012", ".word 8224", ".bss", "mov ax,#2", "call _len", "call _callx", ".word 28494", ".word 0", "push -4(bp)", "movb (bx),al", "mov bx,ax", "mov -2(bp),#0", "I0016:", ".word 514", ".word 257", "mov ", "push ", ".word ", "pop ", "add ", "4(bp)", "-2(bp)", "(bx)", ".define ", ".globl ", "movb ", "xor ", "jmp ", "cmp ", "6(bp)", "-4(bp)", "-6(bp)", "#16", "_callm1", "call ", "8(bp)", "xorb ", "and ", "sub ", "-8(bp)", "jne ", ".cuu", "lea ", "inc ", "_M+10", "#255", "loop", "jcxz", "ax,#", "bx,#", "cx,#", "ax,", "bx,", "cx,", "dx,", "si,", "di,", "bp,", "ax", "bx", "cx", "dx", "si", "di", "bp", "sp", "dec ", "neg ", "_execve", ",#0", 0}; int bol = 1; int white = 0; #define MAX 128 /* This table is used to look up strings. */ struct node { char *string; struct node *next; } node[MAX]; struct node *hash[MAX]; /* hash table */ char input[BUFSIZ+2]; char xbuf[BUFSIZ+2]; main() { int n, count, outbytes; char *p; hainit(); while (1) { for (p = &input[0]; p < &input[BUFSIZ+1]; p++) *p = 0; n = read(0, input, BUFSIZ); if (n == BUFSIZ) { std_err("Input file too long\n"); exit(1); } if (n <= 0) exit(0); outbytes = pack88(input, xbuf, n); write(1, xbuf, outbytes); } } int pack88(inp, outp, count) register char *inp; char *outp; int count; { /* Take a string and pack it to compact assembly code. */ int k, hit, whchar, n; char *orig = outp; char *inbeg = inp; int ct; char *p, **ppt; struct node *nood; /* Convert all tabs to spaces. */ p = inp; while (p - inbeg < count) { if (*p == '\t') *p = ' '; p++; } /* Loop on every char in the buffer. */ while (1) { /* Is the current string in the table? */ if (inp - inbeg > count) write(2, "Bug in packing algorithm\n", 25); if (inp - inbeg == count) return(outp - orig); /* Delete leading white space */ whchar = (*inp == ' ' ? 1 : 0); if (bol && whchar) { inp++; continue; } else { bol = 0; } if (*inp == '\n') bol = 1; /* Delete comments */ if (*inp == '|') { while (*inp++ != '\n') ; inp--; bol = 1; } /* Compact white space */ if (white && whchar) { inp++; continue; } white = whchar; ppt = table; hit = 0; /* Compute hash value for inp. */ n = (*inp + *(inp+1)) & 0177; nood = hash[n]; while (nood != 0) { if (match(inp, nood->string)) { *outp++ = (char) (128 + (nood - node)); inp += strlen(nood->string); hit++; break; } nood = nood->next; } if (hit == 0) *outp++ = *inp++; } } int match(s1, s2) register char *s1, *s2; { while (*s2 != 0) { if (*s1++ != *s2++) return(0); } return(1); } hainit() { /* Initialize the hash tables. */ int n, i, free; char *p; struct node *nood; free = 0; /* next free slot in node table */ for (i = 0; i < MAX; i++) { p = table[i]; if (p == (char *) 0) return; n = *p + *(p+1); n = n & 0177; /* Enter string i on hash slot n. */ if (hash[n] == (struct node *) 0) { hash[n] = &node[free]; } else { /* Find the end of the chain. */ nood = hash[n]; while (nood->next != (struct node *) 0) nood = nood->next; nood->next = &node[free]; } node[free].string = p; node[free].next = (struct node *) 0; free++; } } char *table[] = { "push ax", "ret", "mov bp,sp", "push bp", "pop bp", "mov sp,bp", ".text", "xor ax,ax", "push 4(bp)", "pop bx", "pop si", "cbw", "movb al,(bx)", "pop ax", "xorb ah,ah", "mov ax,#1", "call _callm1", "add sp,#16", "mov bx,4(bp)", "push 6(bp)", "mov -2(bp),ax", "I0013:", "call .cuu", "mov ax,-2(bp)", "add 4(bp),#1", "or ax,ax", "jmp I0011", "mov bx,8(bp)", "push dx", "mov cx,#2", "mov bx,#2", "I0011:", "I0012:", "push -2(bp)", "mov ax,4(bp)", "mov ax,-4(bp)", "add sp,#6", "and ax,#255", "push bx", "mov bx,-2(bp)", "loop 2b", "jcxz 1f", ".word 4112", "mov ax,(bx)", "mov -4(bp),ax", "jmp I0013", ".data", "mov bx,6(bp)", "mov (bx),ax", "je I0012", ".word 8224", ".bss", "mov ax,#2", "call _len", "call _callx", ".word 28494", ".word 0", "push -4(bp)", "movb (bx),al", "mov bx,ax", "mov -2(bp),#0", "I0016:", ".word 514", ".word 257", "mov ", "push ", ".word ", "pop ", "add ", "4(bp)", "-2(bp)", "(bx)", ".define ", ".globl ", "movb ", "xor ", "jmp ", "cmp ", "6(bp)", "-4(bp)", "-6(bp)", "#16", "_callm1", "call ", "8(bp)", "xorb ", "and ", "sub ", "-8(bp)", "jne ", ".cuu", "lea ", "inc ", "_M+10", "#255", "loop", "jcxz", "ax,#", "bx,#", "cx,#", "ax,", "bx,", "cx,", "dx,", "si,", "di,", "bp,", "ax", "bx", "cx", "dx", "si", "di", "bp", "sp", "dec ", "neg ", "_execve", ",#0", 0}; #define IBUFSIZE 10000 #define OBUFSIZE 30000 char input[IBUFSIZE+1], output[OBUFSIZE+1]; main() { int n, count; while (1) { n = read(0, input,IBUFSIZE); if (n <= 0) exit(1); input[n] = 0; count = unpack88(input, output); n = write(1, output, count); } } unpack88(inp, outp) register char *inp, *outp; { register k; char *p, *orig; orig = outp; while (*inp != 0) { k = *inp & 0377; if (k < 128) { *outp++ = *inp++; } else { p = table[k-128]; while (*p != 0) *outp++ = *p++; *inp++; } } return(outp - orig); } /* ln - link a file Author: Andy Tanenbaum */ #include "stat.h" char name[17]; struct stat stb; main(argc, argv) int argc; char **argv; { char *file1, *file2; char *last_comp(); if (argc < 2 || argc > 3) usage(); if (access(argv[1], 0) < 0) { std_err("ln: cannot access "); std_err(argv[1]); std_err("\n"); exit(1); } if (stat(argv[1], &stb) >= 0 && (stb.st_mode & S_IFMT) == S_IFDIR) usage(); file1 = argv[1]; /* "ln file" means "ln file ." */ if (argc == 2) file2 = "."; else file2 = argv[2]; /* Check to see if target is a directory. */ if (stat(file2, &stb) >= 0 && (stb.st_mode & S_IFMT) == S_IFDIR) { strcpy(name, file2); strcat(name, "/"); strcat(name, last_comp(file1)); file2 = name; } if (link(file1, file2)) { std_err("ln: Can't link\n"); exit(1); } exit(0); } char *last_comp(s) char *s; { /* Return pointer to last component of string. */ int n; n = strlen(s); while (n--) if (*(s+n) == '/') return(s+n+1); return(s); } usage() { std_err("Usage: ln file1 [file2]\n"); exit(1); } /* login - log into the system Author: Patrick van Kleef */ #include "signal.h" #include "sgtty.h" #include "pwd.h" main() { char buf[30], buf1[30], *crypt(); int n, n1, bad; struct sgttyb args; struct passwd *pwd, *getpwnam(); args.sg_kill = '@'; args.sg_erase = '\b'; args.sg_flags = 06030; ioctl (0, TIOCSETP, &args); /* Get login name and passwd. */ for (;;) { bad = 0; do { write(1,"login: ",7); n = read (0, buf, 30); } while (n < 2); buf[n - 1] = 0; /* Look up login/passwd. */ if ((pwd = getpwnam (buf)) == 0) bad++; if (bad || strlen (pwd->pw_passwd) != 0) { args.sg_flags = 06020; ioctl (0, TIOCSETP, &args); write(1,"Password: ",10); n1 = read (0, buf1, 30); buf1[n1 - 1] = 0; write(1,"\n",1); args.sg_flags = 06030; ioctl (0, TIOCSETP, &args); if (bad || strcmp (pwd->pw_passwd, crypt(buf1, pwd->pw_passwd))) { write (1,"Login incorrect\n",16); continue; } } /* Successful login. */ setgid (pwd->pw_gid); setuid (pwd->pw_uid); chdir (pwd->pw_dir); if (pwd->pw_shell) { execl(pwd->pw_shell, "-", (char *) 0); } execl("/bin/sh", "-", (char *) 0); write(1,"exec failure\n",13); } } /* lpr - line printer front end Author: Andy Tanenbaum */ #include "errno.h" #define BLOCK 1024 char in_buf[BLOCK], out_buf[BLOCK]; int cur_in, in_count, out_count, column; main(argc, argv) int argc; char *argv[]; { /* This program copies files to the line printer. It expands tabs and converts * line feeds to carriage returns + line feeds. */ int i, fd; close(1); if (open("/dev/lp", 1) < 0) { std_err("lpr: can't open /dev/lp\n"); exit(1); } if (argc == 1) { copy(0); /* standard input only */ } else { for (i = 1; i < argc; i++) { if ( (fd = open(argv[i],0)) < 0) { std_err("lpr: can't open "); std_err(argv[1]); std_err("\n"); exit(1); } else { copy(fd); close(fd); cur_in = 0; in_count = 0; } } } exit(0); } copy(fd) int fd; { /* Print a file, adding carriage returns and expanding tabs. */ char c; while (1) { if (cur_in == in_count) { in_count = read(fd, in_buf, BLOCK); if (in_count == 0) { flush(); return; } cur_in = 0; } c = in_buf[cur_in++]; if (c == '\n') { putc('\r'); putc('\n'); } else if (c == '\t') { do { putc(' '); } while (column & 07); } else putc(c); } } putc(c) char c; { out_buf[out_count++] = c; if (c == '\n') column = 0; else column++; if (out_count == BLOCK) { flush(); } } flush() { int n, count = 0; if (out_count == 0) return; while (1) { n = write(1, out_buf, out_count); if (n == out_count) break; if (n != EAGAIN) { std_err("Printer error\n"); exit(1); } if (count > 5) { std_err("Printer keeps returning busy status\n"); exit(1); } count++; sleep(1); } out_count = 0; } /* ls - list files and directories Author: Andy Tanenbaum */ #include "const.h" #include "type.h" #include "stat.h" #include "../fs/const.h" #include "../fs/type.h" #include "stdio.h" #define DIRNAMELEN 14 /* # chars in a directory entry name */ #define NFILE 256 /* max files in arg list to ls */ #define MAXPATHLEN 256 /* max chars in a path name */ #define NDIRBLOCKS 16 /* max length of a directory */ #define LEGAL 0x1E096DL /* legal flags to ls */ struct file { char *name; unsigned short mode; unsigned short f_uid; unsigned short f_gid; unsigned short inumber; long modtime; long size; short link; } file[NFILE+1]; struct dir { short inum; char dirname[DIRNAMELEN]; } dir[INODES_PER_BLOCK*NDIRBLOCKS]; int nrfiles; char linebuf[BLOCK_SIZE]; /* for reading passwd file */ int linenext; int linelimit; int topfiles; /* nr of files in ls command */ int passwd; /* file descr for /etc/passwd or /etc/group */ short sort_index[NFILE]; long flags; int lastuid = -1; char lastname[10]; char buffer[BUFSIZ]; char *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", "--s", "--s", "-ws", "-ws", "r-s", "r-s", "rws", "rws"}; char *null = {"."}; extern long get_flags(); extern char *getuidgid(); extern int errno; main(argc, argv) int argc; char *argv[]; { int expand_flag; /* allows or inhibits directory expansion */ char *pwfile; setbuf(stdout, buffer); expand_flag = 1; flags = get_flags(argc, argv); expand_args(argc, argv); if (topfiles == 0) { file[NFILE].name = null; exp_dir(&file[NFILE]); expand_flag = 0; } if (present('f')) flags = 0x21; /* -f forces other flags on and off */ sort(0, nrfiles, expand_flag); if (present('l')) { if (present('g')) pwfile = "/etc/group"; else pwfile = "/etc/passwd"; passwd = open(pwfile, 0); if (passwd < 0) fprintf(stdout, "Can't open %s\n", pwfile); } if (topfiles == 0) print_total(0, nrfiles); print(0, nrfiles, expand_flag, ""); fflush(stdout); exit(0); } expand_args(argc, argv) int argc; char *argv[]; { /* Put each argument presented to ls in a 'file' entry. */ int k, statflag; k = argc - topfiles; statflag = (topfiles == 0 ? 0 : 1); if (present('c') || present('t') || present('u')) statflag = 1; if (present('s') || present('l')) statflag = 1; while (k < argc) fill_file("", argv[k++], statflag); } sort(index, count, expand_flag) int index, count, expand_flag; { /* Sort the elements file[index] ... file[index+count-1] as needed. */ int i, j, tmp; if (count == 0) return; for (i = index; i < index + count; i++) sort_index[i] = i; if (present('f')) return; /* -f inhibits any sorting */ for (i = index; i < index + count - 1; i++) for (j = i + 1; j < index + count; j++) { if (reversed(sort_index[i], sort_index[j], expand_flag)) { /* Swap two entries */ tmp = sort_index[j]; sort_index[j] = sort_index[i]; sort_index[i] = tmp; } } } int reversed(i, j, expand_flag) int i, j, expand_flag; { /* Return 1 if elements 'i' and 'j' are reversed, else return 0. */ int r, m1, m2; struct file *fp1, *fp2; fp1 = &file[i]; fp2 = &file[j]; if (expand_flag) { if (fp1->size == -1L || fp2->size == -1L) { fprintf(stdout, "ls: internal bug: non-stat'ed file in reversed()\n"); fflush(stdout); exit(1); } m1 = fp1->mode & I_TYPE; m2 = fp2->mode & I_TYPE; if (m1 == I_DIRECTORY && m2 != I_DIRECTORY) return(1); if (m1 != I_DIRECTORY && m2 == I_DIRECTORY) return(0); } r = present('r'); if (present('t') || present('u')) { /* Sort on time field. */ if (fp1->modtime > fp2->modtime) return(r); else return(1-r); } else { /* Sort alphabetically. */ if (strlower(fp1->name, fp2->name, MAXPATHLEN)) return(r); else return(1-r); } } int strlower(s1, s2, count) char *s1, *s2; int count; { /* Return 1 is s1 < s2 alphabetically, else return 0. */ while (count--) { if (*s1 == 0 && *s2 == 0) return(1); if (*s1 == 0) return(1); if (*s2 == 0) return(0); if (*s1 < *s2) return(1); if (*s1 > *s2) return(0); s1++; s2++; } /* The strings are identical up to the given length. */ return(1); } print(index, count, expand, dirname) int index, count, expand; char *dirname; { /* If an entry is a file, print it; if a directory, process it. */ int k, m, nrf; struct file *fp; nrf = nrfiles; for (k = index; k < index + count; k++) { fp = &file[sort_index[k]]; if (present('l') || present('s') || present('i')) if (fp->size == -1L) /* -1 means stat not done */ if (stat_file(dirname, fp) < 0) continue; m = fp->mode & I_TYPE; /* 'm' may be junk if 'expand' = 0 */ if (present('f')) m = I_DIRECTORY; if (m != I_DIRECTORY || present('d') || expand == 0) { /* List a single line. */ print_line(fp); } else { /* Expand and print directory. */ exp_dir(fp); sort(nrf, nrfiles - nrf, 0); if (topfiles > 1) fprintf(stdout, "\n%s:\n", fp->name); print_total(nrf, nrfiles - nrf); print(nrf, nrfiles - nrf, 0, fp->name); /* recursion ! */ nrfiles = nrf; } } } exp_dir(fp) struct file *fp; { /* List the files within a directory. Read whole dir in one blow. * Expand and print whole dir in core, since 'file' struct has pointers to it. */ int n, fd, k, klim, suppress, statflag; char *p; fd = open(fp->name, 0); if (fd < 0) { fprintf(stdout, "Cannot list contents of %s\n", fp->name); return; } suppress = !present('a'); n = read(fd, dir, INODE_SIZE * INODES_PER_BLOCK * NDIRBLOCKS); klim = (n + DIRNAMELEN + 1)/(DIRNAMELEN + 2); if (n == INODE_SIZE * INODES_PER_BLOCK * NDIRBLOCKS) { fprintf(stdout, "Directory %s too long\n", fp->name); return; } statflag = 0; if (present('c') || present('t') || present('u')) statflag = 1; if (present('s') || present('l')) statflag = 1; for (k = 0; k < klim; k++) { if (dir[k].inum != 0) { p = dir[k].dirname; if (suppress) { if (*p == '.' && *(p+1) == 0) continue; if (*p == '.' && *(p+1) == '.' && *(p+2) == 0) continue; } fill_file(fp->name, p, statflag); } } close(fd); } fill_file(prefix, postfix, statflag) char *prefix, *postfix; int statflag; { /* Fill the next 'file' struct entry with the file whose name is formed by * concatenating 'prefix' and 'postfix'. Stat only if needed. */ struct file *fp; if (nrfiles == NFILE) { fprintf(stdout, "ls: Out of space\n"); fflush(stdout); exit(1); } fp = &file[nrfiles++]; fp->name = postfix; if(statflag) { if (stat_file(prefix, fp) < 0) nrfiles--; } else { fp->size = -1L; /* mark file as not yet stat'ed */ } } print_line(fp) struct file *fp; { int blks, m, prot, s; char *p1, *p2, *p3, c; if (present('i')) fprintf(stdout, "%5d ", fp->inumber); if (present('s')) { /* Print file size */ blks = nblocks(fp->size); fprintf(stdout, "%4d ", blks); } if (present('l')) { m = fp->mode & I_TYPE; if (m == I_DIRECTORY) c = 'd'; else if (m == I_BLOCK_SPECIAL) c = 'b'; else if (m == I_CHAR_SPECIAL) c = 'c'; else c = '-'; m = fp->mode & 07777; prot = (m >> 6) & 07; if (m & I_SET_UID_BIT) prot += 8; p1 = rwx[prot]; prot = (m >> 3) & 07; if (m & I_SET_GID_BIT) prot += 8; p2 = rwx[prot]; prot = m & 07; p3 = rwx[prot]; fprintf(stdout, "%c%s%s%s %2d ",c, p1, p2, p3, fp->link); /* Print owner or group */ owngrp(fp); m = fp->mode & I_TYPE; if (m == I_CHAR_SPECIAL || m == I_BLOCK_SPECIAL) { s = (short) fp->size; fprintf(stdout, "%2d, %2d ", (s>>8)&0377, s&0377); } else { fprintf(stdout, "%6D ", fp->size); /* DEBUG use 6D */ } date(fp->modtime); } /* Print file name. */ m = 0; p1 = fp->name; while (*p1 != 0 && (m < DIRNAMELEN || *p1 == '/') ) { fprintf(stdout, "%c", *p1); m = (*p1 == '/' ? 0 : m + 1); p1++; } fprintf(stdout, "\n"); } owngrp(fp) struct file *fp; { char *buf; int xid; if (present('g')) { xid = fp->f_gid; } else { xid = fp->f_uid; } buf = getuidgid(xid); if (buf != 0) fprintf(stdout, "%6s ",buf); else fprintf(stdout, "%6d ",xid); } int stat_file(prefix, fp) char *prefix; struct file *fp; { /* Stat a file and enter it in 'file'. */ char namebuf[MAXPATHLEN], *p, *org, *q; struct stat sbuf; int m, ctr; /* Construct the full path name in 'namebuf'. */ p = namebuf; q = prefix; while (*q != 0 && p - namebuf < MAXPATHLEN) *p++ = *q++; if (*prefix != 0) *p++ = '/'; org = fp->name; q = fp->name; ctr = 0; while (*q != 0 && p - namebuf < MAXPATHLEN) { ctr++; if (*q == '/') ctr = 0; if (ctr > DIRNAMELEN) break; *p++ = *q++; } *p = 0; /* The name has been built. Stat the file and copy the info. */ if ((m = stat(namebuf, &sbuf)) < 0) { fprintf(stdout, "%s not found\n", namebuf); return(-1); } m = sbuf.st_mode & I_TYPE; fp->mode = sbuf.st_mode; fp->f_uid = sbuf.st_uid; fp->f_gid = sbuf.st_gid; fp->inumber = sbuf.st_ino; fp->modtime = sbuf.st_mtime; fp->size = sbuf.st_size; fp->size = (m == I_CHAR_SPECIAL || m == I_BLOCK_SPECIAL ? sbuf.st_rdev : sbuf.st_size); fp->link = sbuf.st_nlink; return(0); } long get_flags(argc, argv) int argc; char *argv[]; { /* Get the flags. */ long fl, t; int k, n; char *ptr; fl = 0L; n = 1; topfiles = argc - 1; while (n < argc) { ptr = argv[n]; if (*ptr != '-') return(fl); topfiles--; ptr++; while (*ptr != 0) { k = *ptr - 'a'; t = 1L << k; if (*ptr < 'a' || *ptr > 'z' || (t|LEGAL) != LEGAL) { fprintf(stdout, "Bad flag: %c\n", *ptr); ptr++; continue; } fl |= t; ptr++; } n++; } return(fl); } present(let) char let; { return (flags >> (let - 'a')) & 01; } #define YEAR (365L * 24L * 3600L) #define LYEAR (366L * 24L * 3600L) int mo[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; long curtime; char *moname[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; date(t) long t; /* time in seconds */ { /* Print the date. This only works from 1970 to 2099. */ int i, year, day, month, hour, minute; long length, time(), original; year = 1970; original = t; while (t > 0) { length = (year % 4 == 0 ? LYEAR : YEAR); if ( t < length) break; t -= length; year++; } /* Year has now been determined. Now the rest. */ day = t/(24L * 3600L); t -= (long) day * 24L * 3600L; hour = t/3600L; t -= 3600L * (long) hour; minute = (int) t/60L; /* Determine the month and day of the month. */ mo[1] = (year % 4 == 0 ? 29 : 28); month = 0; i = 0; while (day >= mo[i]) { month++; day -= mo[i]; i++; } /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ if (curtime == 0) curtime = time( (long*)0); /* approximate current time */ fprintf(stdout, "%3s %2d ",moname[month], day+1); if (curtime - original >= YEAR/2L) { fprintf(stdout, "%5d ",year); } else { if (hour < 10) fprintf(stdout, "0%d:",hour); else fprintf(stdout, "%2d:",hour); if (minute < 10) fprintf(stdout, "0%d ",minute); else fprintf(stdout, "%2d ",minute); } } print_total(index, count) int index, count; { int blocks, i; if (!present('l') && !present('s')) return; blocks = 0; for (i = index; i < index + count; i++) blocks += nblocks(file[i].size); fprintf(stdout, "total %d\n", blocks); } char getpwdch() { if (linenext == linelimit) { /* Fetch another block of passwd file. */ linelimit = read(passwd, linebuf, BLOCK_SIZE); linenext = 0; if (linelimit <= 0) return (char) 0; } return (linebuf[linenext++]); } getline(buf) char *buf; { while (1) { *buf = getpwdch(); if (*buf == 0 || *buf == '\n') break; buf++; } *buf = 0; } char *getuidgid(usrid) int usrid; { char lbuf[100], *ptr, *ptr1; int bin; if (usrid == lastuid) return(lastname); lseek(passwd, 0L, 0); /* rewind the file */ linenext = 0; linelimit = 0; /* Scan the file. */ while (1) { ptr = lbuf; while (ptr < &lbuf[100]) *ptr++ = 0; getline(lbuf); if (lbuf[0] == 0) return(0); /* Scan this line for uid/gid */ ptr = lbuf; while (*ptr != ':' && *ptr != 0) ptr++; if (*ptr == 0) return(0); *ptr++ = 0; while (*ptr != ':' && *ptr != 0) ptr++; if (*ptr == 0) return(0); ptr++; /* Ptr now points at a uid. Convert it to binary. */ bin = 0; while (*ptr != ':' && *ptr != 0 && *ptr != '\n') { bin = 10*bin + (*ptr - '0'); ptr++; } if (bin == usrid) { /* Hit. */ lastuid = usrid; ptr = lastname; ptr1 = lbuf; while (*ptr++ = *ptr1++) ; *ptr++ = 0; return(lastname); } } } nblocks(size) long size; { /* Convert file length to blocks, including indirect blocks. */ int blocks, fileb; fileb = (size + (long) BLOCK_SIZE - 1)/BLOCK_SIZE; blocks = fileb; if (fileb <= NR_DZONE_NUM) return(blocks); blocks++; fileb -= NR_DZONE_NUM; if (fileb <= NR_INDIRECTS) return(blocks); blocks++; fileb -= NR_INDIRECTS; blocks += (fileb + NR_INDIRECTS - 1)/NR_INDIRECTS; return(blocks); } #include "stdio.h" #include "errno.h" extern int errno; #ifdef LC int _stack = 4000; #define SWITCHCHAR '\\' /* character that separates path elements */ #define PATHCHAR ';' /* character that separates elements of the PATH */ char linecont = '+'; /* default line continuation character */ char switchc = '\\'; /* default directory separation char */ #else #define SHELL "/bin/sh" /* the shell to execute */ #define SWITCHCHAR '/' /* character that separates path elements */ #define PATHCHAR ':' /* character that separates elements of the PATH */ char linecont = '\\'; /* default line continuation character */ char switchc = '/'; /* default directory separation char */ #endif /* the argument to malloc */ #define UI unsigned int #define TIME long /* generic linked list */ struct llist { char *name; struct llist *next; }; struct defnrec { char *name; int uptodate; TIME modified; struct llist *dependson; struct llist *howto; struct defnrec *nextdefn; }; struct macrec { char *name,*mexpand; struct macrec *nextmac; }; struct rulerec { char *dep,*targ; /* order is important because there are defaults */ struct llist *rule; int def_flag; struct rulerec *nextrule; }; /* default rules for make */ /* 1. Modifiy NDRULES to reflect the total number of rules... 2. Enter rules in the following format "source-extension","object-extension","rule",NULL, and update NDRULES. 3. Note that the default rules are searched from top to bottom in this list, and that within default rules, macros are ignored if not defined (You may specify FFLAGS in the rule without requiring the user to define FFLAGS in his/her makefile) 4. The rule applied will be the first one matching. If I ever get a public domain YACC working, the rule for it will be first, and look like ".y",".o","bison $(YFLAGS) $*.y","cc $* $(CFLAGS)",NULL, There are at present no depends in rules, so you need a .y.o: and a .y.c: rule 5. The src and dest extensions are expected to be in lower case 6. SUFFIX sets the name and precedence for the prerequisite macros, $< and $?, and for looking up rules. Basically, all type extensions must be to the left of type extensions. All rules should have their suffix mentioned. See UNIX documentation or make.doc */ #define NDRULES 3 char *def_list[] = { ".c",".s","$(CC) -S $(CFLAGS) $*.c",NULL, ".c",".o","$(CC) -c $(CFLAGS) $*.c",NULL, ".s",".o","$(AS) $(AFLAGS) -o $*.o $*.s",NULL, }; #define SUFFIXES ".o .s .c" #ifndef LC TIME time(); #define now() (TIME) time( (char *) 0) /* the current time, in seconds */ #else #include "time.h" TIME now() { struct tm timer,*p; long t,ftpack(); char tim[6]; p = &timer; time(&t); p = localtime(&t); tim[0] = p->tm_year - 80; tim[1] = p->tm_mon + 1; tim[2] = p->tm_mday; tim[3] = p->tm_hour; tim[4] = p->tm_min; tim[5] = p->tm_sec; return(ftpack(tim)); } #endif char **ext_env; char *whoami = "Make"; #ifndef LC #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<=(b)?(a):(b)) #endif #define BKSLSH '\134' #undef ERROR #define ERROR -1 #define TRUE 1 #define FALSE 0 #define EQ(X,Y) (strcmp(X,Y) == 0) #define NUL '\0' #define isnull(X) (X == '\0' ? TRUE : FALSE) #define notnull(X) (X == '\0' ? FALSE : TRUE ) #define isspace(X) ( (X == ' ') || (X == '\011') ) /* flags for expand. Report and ignore errors, and no_target means error if $@ or $* is attempted ( as in $* : a.obj ) */ #define NO_TARG 2 #define REPT_ERR 1 #define IGN_ERR 0 #define INMAX 500 /* maximum input line length (allow for expansion)*/ #define INMAXSH 80 /* length for short strings */ #ifdef BSD4.2 #include #include #include #define WAIT union wait #else /* sysV and MINIX and LATTICE */ struct stat { short int st_dev; unsigned short st_ino; unsigned short st_mode; short int st_nlink; short int st_uid; short int st_gid; short int st_rdev; long st_size; TIME st_atime; TIME st_mtime; TIME st_ctime; } ; /* #include #include */ #define WAIT int #endif struct macrec *maclist = NULL; struct defnrec *defnlist = NULL; struct llist *dolist = NULL; struct llist *path_head = NULL; struct llist *suff_head = NULL; struct rulerec *rulelist = NULL; struct llist *makef = NULL; #ifdef LC int linkerf = TRUE; char tfilename[50] = "makefile.mac"; #endif int execute = TRUE; int stopOnErr = TRUE; int forgeahead = FALSE; int madesomething = FALSE; int knowhow = FALSE; int no_file = TRUE; int silentf = FALSE; #ifdef DEBUG int tree_and_quit = FALSE; int post_tree = FALSE; #endif DEBUG int path_set = FALSE; /* return declarations for functions not returning an int */ TIME make(),getmodified(),findexec(); char *mov_in(),*get_mem(); struct llist *MkListMem(), *mkllist(), *mkexphow(), *mkexpdep(),*add_llist(); /* temp storage variables for the prerequisite lists */ struct m_preq { char m_dep[6]; char m_targ[6]; char m_name[INMAXSH]; }; char dothis[INMAX]; /* generic temporary storage */ FILE *fopen(); main(argc,argv,envp) int argc; char *argv[],*envp[]; { ext_env = envp; init(argc,argv); #ifdef DEBUG if (tree_and_quit){ prtree(); fprintf(stderr, "tree and quit\n"); done(0); } #endif DEBUG /* now fall down the dolist and do them all */ while (dolist != NULL) { madesomething = FALSE; make(dolist->name); if (!madesomething) { if (knowhow) { if ( !silentf ) fprintf(stdout,"%s: '%s' is up to date.\n",whoami,dolist->name); } else { error2("Don't know how to make %s",dolist->name); } } dolist = dolist->next; } #ifdef DEBUG if (post_tree) prtree(); #endif DEBUG done( 0 ); } init(argc,argv) int argc; char *argv[]; { int i,k; int pdep,ptarg; struct llist *ptr; int usedefault = TRUE; for (k=i=0; i < NDRULES; i++,k++) { /* couldn't init the linked list with the compiler */ pdep = k++; ptarg = k++; ptr = NULL; while ( def_list[k] != NULL ) { ptr = add_llist(ptr,def_list[k]); k++; } add_rule2(def_list[pdep],def_list[ptarg],ptr,TRUE); } /* initialize the suffix list */ add_suff(SUFFIXES); /* load the macro MFLAGS */ for ( i = 1,dothis[0] = NUL; i < argc ; i++ ) { strcat(dothis,argv[i]); strcat(dothis," "); } add_macro("MFLAGS",dothis); /* add any default macros here, such as CC */ add_macro("CC","cc"); add_macro("AS","as"); /* step thru the args and read the flags, patterns and objects */ for (i=1; i < argc; i++) { if (argv[i][0] == '-') { /* option */ switch (argv[i][1]) { case 'f': case 'F': /* arg following is a makefile */ if (++i < argc) { makef = add_llist(makef,argv[i]); usedefault = FALSE; } else panic("'-f' requires filename"); break; case 'c': case 'C': /* line continuation char */ if ( argv[i][2] != NUL ) linecont = argv[i][2]; else { if ( ++i < argc || notnull(argv[i][1]) ) linecont = argv[i][0]; else error("'-c' requires single character"); } break; case 'k':case 'K': /* abandon work on this branch on error */ forgeahead = TRUE; break; case 'b': case 'B': /* switchchar change */ if ( argv[i][2] != NUL ) switchc = argv[i][2]; else { if ( ++i < argc || notnull(argv[i][1]) ) switchc = argv[i][0]; else error("'-b' requires single character"); } break; case 'i': case 'I': /* ignore errors on execution */ stopOnErr = FALSE; break; case 'n': case 'N': /* don't execute commands - just print */ execute = FALSE; break; case 's': case 'S': /* execute, but don't print */ silentf = TRUE; break; #ifdef DEBUG case 'p':case 'P': /* print a tree and quit */ tree_and_quit = TRUE; break; case 'v': case 'V': /* print the tree after all processing */ post_tree = TRUE; break; #endif DEBUG default: error2("unknown option '%s'",argv[i]); } } else { if ( !maccheck(argv[i]) ) { /* if argv[i] is not of the pattern xxx=yyy, then it must be something to make. maccheck will add the macro if it is... */ dolist = add_llist(dolist,argv[i]); no_file = FALSE; } } } /* collect the flags, then read the makefile, otherwise a construct like make -f make2 aardvark will make both aardvark and the first target in make2 */ if (usedefault) { if ( getmodified("Makefile") != (TIME) 0 ) readmakefile("Makefile"); else readmakefile("makefile"); } else { for ( ptr = makef; ptr != NULL; ptr = ptr->next ) readmakefile(ptr->name); } /* if not done by a PATH directive, set the basic PATH */ if ( !path_set ) {mkpathlist();path_set = TRUE;} }/* init */ TIME make(s) /* returns the modified date/time */ char *s; { struct defnrec *defnp,*tryrules(),*dummy; struct llist *depp,*depp2; struct llist *howp; char *m_comp,*m_ood,*m_obj; char *stradd(),*add_prereq(); TIME latest,timeof; struct m_preq ma; /* look for the definition */ for ( defnp = defnlist; defnp != NULL; defnp = defnp->nextdefn ) if ( EQ(defnp->name,s) ) break; /* there might be some adjusting of the lists for implied compilations. these additions are not done in readmakefile; they might not be required for these targets ( ie not requested ) */ if (defnp == NULL ){ defnp = tryrules(s); if (defnp == NULL){ /* tryrules returns a pointer to a defnrec */ /* tryrules fails, and there is no definition */ knowhow = FALSE; latest = getmodified(s); if (latest==0) { /* doesn't exist but don't know how to make */ panic2("Can't make %s",s); /* NOTREACHED */ } else { /* exists - assume it's up to date since we don't know how to make it. Make a defnrec with uptodate == TRUE. This is not strictly necessary, and this line may be deleted. It is a speed win, at the expense of core, when there are a lot of header files. */ /*add_defn(s,TRUE,latest, (struct llist *)NULL,(struct llist*)NULL); */ return(latest); } } } else{ /* there is a definition line */ if (defnp->uptodate) { return(defnp->modified); } dummy = tryrules(s); if (dummy != NULL && defnp->howto == NULL){ /* any explicit howto overrides an implicit one */ /*add depend*/ if (defnp->dependson == NULL) defnp->dependson = dummy->dependson; else{ for (depp2 = defnp->dependson; depp2->next != NULL; depp2 = depp2->next); /* advance to end of list */ depp2->next = dummy->dependson; } /* add howto line */ defnp->howto = dummy->howto; } } /* finished adjusting the lists */ /* check that everything that the current target depends on is uptodate */ m_comp = m_ood = m_obj = NULL; latest = 0; depp = defnp->dependson; while (depp != NULL) { m_comp = add_prereq(m_comp,depp->name,&ma);/* add to string for $< */ timeof = make(depp->name); latest = max(timeof,latest);/*written this way to avoid side effects*/ if ( defnp->modified < timeof ) { /* these are out of date with respect to the current target */ m_ood = stradd(m_ood,ma.m_name,ma.m_dep); /* add source */ m_obj = stradd(m_obj,ma.m_name,ma.m_targ);/* add object */ } depp = depp->next; } knowhow = TRUE; /* has dependencies therefore we know how */ /* if necessary, execute all of the commands to make it */ /* if (out of date) || (depends on nothing) */ if (latest > defnp->modified || defnp->dependson==NULL) { /* make those suckers */ howp = defnp->howto; if ((howp == NULL) && !in_dolist(s)) { fprintf(stderr,"%s: %s is out of date, but there is no command line\n", whoami,s); if ( stopOnErr ) mystop_err(); } while (howp != NULL) { /* the execute flag controls whether execution takes place */ p_expand(howp->name,dothis,m_comp,m_ood,m_obj); if ( (exec_how(dothis) != 0) ) if (forgeahead) break; else if (stopOnErr) panicstop(); howp = howp->next; } /* we just made something. Set the time of modification to now. */ defnp->modified = now(); defnp->uptodate = TRUE; if (defnp->howto != NULL) /* we had instructions */ madesomething = TRUE; } if ( m_comp != NULL ) free( m_comp ); if ( m_ood != NULL ) free( m_ood ); if ( m_obj != NULL ) free( m_obj ); return(defnp->modified); } struct llist *add_llist(head,s) /*this adds something to a linked list */ char *s; struct llist *head; { struct llist *ptr1; /* find a slot in the list */ if (head == NULL) { ptr1 = MkListMem(); ptr1->name = mov_in(s); ptr1->next = NULL; return ( ptr1 ); } else { for (ptr1 = head; ptr1->next != NULL ; ptr1 = ptr1->next ) ; ptr1->next = MkListMem(); ptr1->next->name = mov_in(s); ptr1->next->next = NULL; return( head ); } } expand(src,dest,target,flag) /* expand any macros found*/ char *src,*dest,*target; int flag; { char thismac[INMAX],*ismac(),*ismac_c(); char thismac2[INMAX],*macptr; int i,pos,back, j; back = pos = 0; if ( src == NULL ) { /* NULL pointer, shouldn't happen */ dest[0] = NUL; return; } while( notnull(src[pos]) ) { if (src[pos] != '$') dest[back++] = src[pos++]; else { pos++; /*found '$'. What kind of macro is this? */ switch(src[pos]){ case '(': /*regular macro*/ case '{': /*regular macro*/ /* do macro stuff */ pos = x_scan(src,pos,thismac); /* get macro */ if ( maclist == NULL && (flag & REPT_ERR) ) error2("No macros defined -- %s",thismac); else if ( (macptr=ismac(thismac)) == NULL) { expand(thismac,thismac2,target,flag); if ( (macptr = ismac(thismac2)) != NULL) /* the recursive expand found it */ back = mv_install(macptr,dest,back); else { if ( flag & REPT_ERR ) error2("Can't expand macro -- %s",thismac2); } } else { /* macptr points to appropriate macro */ back = mv_install(macptr,dest,back); } break; case '*': /*target without extension*/ case '@': /*whole target*/ if ((flag & NO_TARG) && (flag & REPT_ERR) ){ fprintf(stderr,"%s: '$%c' not in a command or dependency line\n", whoami,src[pos]); if ( stopOnErr ) mystop_err(); else return; } else { for (i=0; notnull(target[i]) ; i++) { if (target[i] == '.' && src[pos] == '*') { j = i; while (notnull(target[j]) && target[j] != switchc) j++; if (notnull(target[j]) == FALSE) break; } dest[back++] = target[i]; } } break; default: if ( (macptr = ismac_c(src[pos])) != NULL ) back = mv_install(macptr,dest,back); else { /*not an approved macro, ignore*/ dest[back++] = '$'; dest[back++] = src[pos]; } break; }/* else */ pos++; } } dest[back] = NUL; } p_expand(src,dest,compl_preq,ood_preq,ood_obj) char *src,*dest; char *compl_preq,*ood_preq,*ood_obj; { /* expand the special macros $< $? $> just before execution */ int back,pos,i; if ( src == NULL ) { dest[0] = NUL; return; } back = pos = 0; while( notnull(src[pos]) ) { if (src[pos] != '$' ) dest[back++] = src[pos++]; else { pos++; switch( src[pos] ) { case '<': /* put in the complete list of prerequisites */ for ( i = 0; notnull(compl_preq[i]); i++ ) dest[back++] = compl_preq[i]; break; case '?': /* the prerequisites that are out of date */ for ( i = 0; notnull(ood_obj[i]); i++ ) dest[back++] = ood_obj[i]; break; case '>': /* the source files that are out of date (NOT STANDARD)*/ for ( i = 0; notnull(ood_preq[i]); i++ ) dest[back++] = ood_preq[i]; break; case '$': /* get rid of the doubled $$ */ dest[back++] = '$'; break; default: dest[back++] = '$'; dest[back++] = src[pos]; break; } pos++; } /* else */ } /* switch */ dest[back] = NUL; } /* is this a character macro? */ char *ismac_c(cc) char cc; { char *ismac(); char *str = " "; /* space for a one char string */ str[0] = cc; return(ismac(str)); } /* is this string a macro? */ char *ismac(test) char *test; { struct macrec *ptr; ptr = maclist; if ( ptr == NULL ) return( NULL ); while( TRUE ) { if ( EQ(ptr->name,test) ) return( ptr->mexpand ); else if ( ptr->nextmac == NULL ) return( NULL ); else ptr = ptr->nextmac; } } maccheck(sptr) /* if this string has a '=', then add it as a macro */ char *sptr; { int k; for ( k=0; notnull(sptr[k]) && (sptr[k] != '='); k++ ); if ( isnull(sptr[k]) ) return( FALSE ); else { /* found a macro */ sptr[k] = NUL; add_macro(sptr,sptr + k + 1); return( TRUE ); } } x_scan(src,pos,dest) char *src,*dest; int pos; { char bterm,eterm; int cnt; /* load dest with macro, allowing for nesting */ if ( src[pos] == '(' ) eterm = ')'; else if ( src[pos] == '{' ) eterm = '}'; else panic("very bad things happening in x_scan"); bterm = src[pos++]; cnt = 1; while ( notnull(src[pos]) ) { if ( src[pos] == bterm ) cnt++; else if ( src[pos] == eterm ) { cnt--; if ( cnt == 0 ) { *dest = NUL; return( pos ); } } *dest++ = src[pos++]; } panic2("No closing brace/paren for %s",src); /* NOTREACHED */ } /* expand and move to dest */ mv_install(from,to,back) char *from,*to; int back; { int i; for ( i=0; notnull(from[i]) ; i++) to[back++] = from[i]; return( back ); } /* attempts to apply a rule. If an applicable rule is found, returns a pointer to a (new) struct which can be added to the defnlist An applicable rule is one in which target ext matches, and a source file exists. */ struct defnrec *tryrules(string) char *string; { struct rulerec *rptr,*isrule(); struct llist *sptr; struct defnrec *retval; char s[INMAXSH],buf[INMAXSH],sext[10]; my_strcpy(s,string); get_ext(s,sext); /* s is now truncated */ if ( sext[0] == NUL ) { /*target has no extension*/ return(NULL); } /* look for this extension in the suffix list */ for ( sptr = suff_head; sptr != NULL; sptr = sptr->next ) if ( EQ(sptr->name,sext) ) break; if ( sptr == NULL ) { /* not a valid extension */ return( NULL ); } /* continue looking, now for existence of a source file **/ for ( sptr = sptr->next; sptr != NULL; sptr = sptr->next ) if ( exists(s,sptr->name) && ((rptr = isrule(rulelist,sptr->name,sext)) != NULL) ) break; if ( sptr == NULL ) { /* no rule applies */ return( NULL ); } retval = (struct defnrec *)get_mem((UI) sizeof(struct defnrec)); my_strcpy(buf,s); /* s -- is the stem of the object*/ strcat(buf,rptr->targ); retval->name = mov_in(buf); my_strcpy(buf,s); strcat(buf,rptr->dep); retval->dependson = mkllist(buf); retval->uptodate = FALSE; retval->modified = getmodified(retval->name); retval->nextdefn = NULL; retval->howto = mkexphow(rptr->rule,retval->name, (rptr->def_flag)? IGN_ERR : REPT_ERR); return(retval); /*whew*/ } /* does the file exist? */ exists(name,suffix) char *name,*suffix; { char t[INMAXSH]; my_strcpy(t,name); strcat(t,suffix); return (getmodified(t) != (TIME) 0 ? TRUE : FALSE ); } struct rulerec *isrule(head,src,dest) struct rulerec *head; char *src,*dest; { /* return ptr to rule if this is a legit rule */ struct rulerec *ptr; if ( head == NULL ) return( NULL ); else { for ( ptr = head; ptr != NULL; ptr = ptr->nextrule ) if ( EQ(ptr->dep,src) && EQ(ptr->targ,dest) ) return( ptr ); return( NULL ); } } #ifdef DEBUG /*debugging*/ /* print the dependencies and command lines... */ prtree() { struct defnrec *dummy; struct macrec *mdum; struct llist *dum2,*dum3,*rdum2; struct rulerec *rdum; int cnt; dummy = defnlist; while (dummy != NULL){ fprintf(stdout,"name '%s' exists: %s\n", dummy->name,(dummy->modified)?"no":"yes"); dum2 = dummy->dependson; fprintf(stdout," depends-on:"); cnt =0; while (dum2 != NULL){ fprintf(stdout," %13s ",dum2->name); cnt++; if (cnt == 4){ cnt = 0; fprintf(stdout,"\n "); } dum2 = dum2->next; } fprintf(stdout,"\n"); dum3 = dummy->howto; while (dum3 != NULL){ fprintf(stdout," command: %s\n",dum3->name); dum3 = dum3->next; } dummy = dummy->nextdefn; fprintf(stdout,"\n"); } fprintf(stdout,"\n *RULES*\n\n"); fprintf(stdout,"src= dest= rule=\n"); rdum = rulelist; while ( rdum != NULL ) { if ( rdum->rule == NULL ) fprintf(stdout,"%4s %4s %s\n", rdum->dep,rdum->targ,"** Empty Rule **"); else { fprintf(stdout,"%4s %4s %s\n", rdum->dep,rdum->targ,rdum->rule->name); rdum2 = rdum->rule->next; while ( rdum2 != NULL ) { fprintf(stdout," %s\n",rdum2->name); rdum2 = rdum2->next; } } rdum = rdum->nextrule; } mdum = maclist; if ( mdum == NULL ) fprintf(stdout,"\n *NO MACROS*\n"); else { fprintf(stdout,"\n *MACROS*\n\n"); fprintf(stdout," macro expansion\n"); while ( mdum != NULL ) { fprintf(stdout," %8s %s\n",mdum->name,mdum->mexpand); mdum = mdum->nextmac; } } fprintf(stdout,"\n\nsuffix list is"); if ( suff_head == NULL ) fprintf(stdout," empty."); else for ( dum2 = suff_head; dum2 != NULL; dum2 = dum2->next){ fprintf(stdout," %s",dum2->name); } fprintf(stdout,"\npath is "); if (path_head == NULL) fprintf(stdout," empty."); else for ( dum2 = path_head; dum2 != NULL; dum2 = dum2->next) fprintf(stdout," %s:",dum2->name); fprintf(stdout,"\nswitch character '%c'\n",switchc); fprintf(stdout,"line continuation '%c'\n",linecont); } /*debug*/ #endif DEBUG error(s1) char *s1; { fprintf(stderr,"%s: ",whoami); fprintf(stderr,s1); fprintf(stderr,"\n"); if (stopOnErr) mystop_err(); else return; } error2(s1,s2) char *s1,*s2; { fprintf(stderr,"%s: ",whoami); fprintf(stderr,s1,s2); fprintf(stderr,"\n"); if (stopOnErr) mystop_err(); else return; } panic(s1) char *s1; { fprintf(stderr,"%s: ",whoami); fprintf(stderr,s1); fprintf(stderr,"\n"); mystop_err(); /* NOTREACHED */ } panic2(s1,s2) char *s1,*s2; { fprintf(stderr,"%s: ",whoami); fprintf(stderr,s1,s2); fprintf(stderr,"\n"); mystop_err(); /* NOTREACHED */ } panicstop() { fprintf(stderr,"\n\n ***Stop.\n"); mystop_err(); /* NOTREACHED */ } mystop_err() { done( -1 ); /* NOTREACHED */ } in_dolist(s) /* true if this is something we are to make */ char *s; { struct llist *ptr; for ( ptr = dolist; ptr != NULL ; ptr = ptr->next ) if ( EQ(ptr->name,s) ) return( TRUE ); return( FALSE ); } char *add_prereq(head,nam,f) char *head,*nam; struct m_preq *f; { char *stradd(); struct llist *ptr; /* move the stem, src and dest extensions and the current time of modification to where make() can get at them. returns the updated list of prerequisites */ /* get the prerequisite */ /* if ext does not exist, return */ my_strcpy(f->m_name,nam); get_ext(f->m_name,f->m_targ); if ( f->m_targ[0] == NUL ) return( head ); /* if ext not on suffix list, return */ for ( ptr = suff_head; ptr != NULL; ptr = ptr->next ) if ( EQ(ptr->name,f->m_targ) ) break; if ( ptr == NULL ) return( head ); /* if there does not exist a corresponding file, return */ for ( ; ptr != NULL; ptr = ptr->next ) if ( exists(f->m_name,ptr->name) ) break; if ( ptr == NULL ) return( head ); /* add the source file to the string m_comp with a strcat */ my_strcpy(f->m_dep,ptr->name); return( stradd(head,f->m_name,f->m_dep) ); } char *stradd(f1,f2,f3) char *f1,*f2,*f3; { char *ptr; /* return a new pointer to a string containing the three strings */ ptr = get_mem((UI)(my_strlen(f1) + strlen(f2) + strlen(f3) + 2) ); my_strcpy(ptr,f1); strcat(ptr," "); strcat(ptr,f2); strcat(ptr,f3); if ( f1 != NULL ) free( f1 ); return( ptr ); } get_ext(n,ex) char *ex,*n; { int start,end,x; /* put the extension of n in ex ( with the period ) and truncate name ( at period ) */ start = my_strlen(n); end = ( start > 6 ) ? start - 6 : 0; for ( x = start; x > end; x-- ) if ( n[x] == '.' ) break; if ( x == end ) { ex[0] = NUL; return; } else { my_strcpy(ex,n + x); n[x] = NUL; } } /* read the makefile, and generate the linked lists */ #define DONE 1 #define ADEFN 2 #define ARULE 3 #define AMACRO 4 #define DIRECTIVE 5 /* local variables */ FILE *fil; char *fword,*restline,line[INMAX],backup[INMAX]; char *frule; struct llist *fhowto,*howp3; struct llist *fdeps,*deprec3; struct defnrec *defnp; int sending,def_ready,gdone,rule_send,rule_ready; struct llist *targ,*q_how,*q_dep,*targ2; readmakefile(s) char *s; { int i,k; char temp[50],tempdep[50]; FILE *fopen(); /* open the file */ if ( EQ(s,"-") ) fil = stdin; else if ( (fil = fopen(s,"r")) == NULL) { error2("couldn't open %s",s); return; } /* initialise getnxt() */ sending = def_ready = gdone = rule_send = rule_ready = FALSE; targ = q_how = q_dep = NULL; if (getline(fil, backup) == FALSE) panic("Empty Makefile"); /* getnxt() parses the next line, and returns the parts */ while (TRUE) switch( getnxt() ){ case DONE: fclose(fil);return; case AMACRO: /* add a macro to the list */ add_macro(fword,restline); break; case DIRECTIVE: /* perform the actions specified for a directive */ squeezesp(temp,fword); if ( EQ(temp,"PATH") ) { if ( my_strlen(restline) == 0 ) {free_list(path_head);path_head = NULL;path_set = TRUE;} else { /* this fooling around is because the switchchar may not be set yet, and the PATH variable will use it */ if ( !path_set ) {mkpathlist();path_set = TRUE;} add_path(restline); } } else if ( EQ(temp,"SUFFIXES") ) { /* this is easier, suffix syntax characters don't change */ if ( my_strlen(restline) == 0 ) {free_list(suff_head);suff_head = NULL;} else add_suff(restline); } else if ( EQ(temp,"IGNORE") ) stopOnErr = FALSE; else if ( EQ(temp,"SWITCH") ) switchc = (isnull(restline[0])) ? switchc : restline[0]; else if ( EQ(temp,"LINECONT") ) linecont = ( isnull( restline[0] ) ) ? linecont : restline[0]; else if ( EQ(temp,"SILENT") ) silentf = TRUE; #ifdef LC else if ( EQ(temp,"LINKER") ) { if ( my_strlen(restline) == 0 ) linkerf = TRUE; else switch (restline[0]) { case 'f': case 'F': linkerf = FALSE; case 't': case 'T': linkerf = TRUE; default: panic("Bad argument to LINKER (TRUE/FALSE)"); } } else if ( EQ(temp,"MACFILE") ) { if ( my_strlen(restline) == 0 ) { warn2("no MACFILE name, defaulting to %s",tfilename); } else my_strcpy(tfilename,restline); } #endif else { error2("unknown directive \(rule?\) '%s'",temp); } break; case ARULE: /* add a rule to the list */ /*fword[0] is defined to be a period*/ for (i=1; notnull(fword[i]) ;i++) if ( fword[i] == '.' ) break; if ( i == my_strlen(fword) ) { panic2("Bad rule '%s'",fword); /* NOTREACHED */ } fword[i] = NUL; /* dep */ my_strcpy(tempdep,fword); /* be sure object extension has no spaces */ for ( k = i+1 ; notnull(fword[k]) && !isspace(fword[k]) ; k++ ); if ( isspace(fword[k]) ) fword[k] = NUL; my_strcpy(temp,"."); strcat(temp,fword + i + 1); /* targ */ add_rule2(tempdep, temp, fhowto, FALSE); /* update the suffix list if required. To get fancier than this, the use has to do it himself. Start at the beginning, and if not present, add to the end. */ add_s_suff(temp); /* order is important -- add targ first **/ add_s_suff(tempdep); /* then dep */ break; case ADEFN: /* add a definition */ if (no_file) { /*if no target specified on command line... */ dolist = add_llist(dolist,fword); /*push target on to-do list */ no_file = FALSE; } /* getnxt() returns target ( fword ) , pointer to expanded howto list ( fhowto ) and pointer to expanded depends ( fdeps ) */ if ( defnlist == NULL ) { /* add the current definition to the end */ add_defn(fword,FALSE,getmodified(fword),fdeps,fhowto); } else { defnp = defnlist; while ( defnp != NULL ) { if ( EQ(defnp->name,fword) ) break; else defnp = defnp->nextdefn; } if ( defnp == NULL ) { /* target not currently in list */ add_defn(fword,FALSE,getmodified(fword),fdeps,fhowto); } else { /* target is on list, add new depends and howtos */ if (defnp->dependson == NULL) defnp->dependson = fdeps; else { deprec3 = defnp->dependson; while (deprec3->next != NULL) deprec3 = deprec3->next; deprec3->next = fdeps; } /* add new howtos */ if (defnp->howto == NULL) defnp->howto = fhowto; else { howp3 = defnp->howto; while ( howp3->next != NULL) howp3 = howp3->next; howp3->next = fhowto; } } } break; } } add_defn(n,u,m,d,h) /* add a new definition */ char *n; /* name */ int u; /* uptodate */ TIME m; /* time of modification */ struct llist *d,*h; /* pointers to depends, howto */ { struct defnrec *ptr,*ptr2; ptr = (struct defnrec *)get_mem(sizeof(struct defnrec)); ptr->name = mov_in(n); ptr->uptodate = u; ptr->modified = m; ptr->dependson = d; ptr->howto = h; ptr->nextdefn = NULL; if ( defnlist == NULL ) { defnlist = ptr; return; } else { ptr2 = defnlist; while ( ptr2->nextdefn != NULL ) ptr2 = ptr2->nextdefn; ptr2->nextdefn = ptr; } } getnxt() { int pos,mark,parsed,x; char exp_line[INMAX]; struct llist *q_how2,*q_how3; while ( TRUE ) { /* if we are currently sending targets */ if ( sending ) { if ( targ2->next == NULL) { sending = def_ready = FALSE; } fword = mov_in(targ2->name); fhowto = mkexphow(q_how,targ2->name,REPT_ERR); fdeps = mkexpdep(q_dep,targ2->name); targ2 = targ2->next; return ( ADEFN ); } /* are we sending a rule? */ if ( rule_send ) { fword = frule; fhowto = mkexphow(q_how,(char *)NULL,IGN_ERR); /* target == NULL -> don't expand */ rule_send = rule_ready = FALSE; return( ARULE ); } if ( gdone ) return ( DONE ); /* if we are not currently sending... */ /* load the next line into 'line' ( which may be backed-up ) */ if ( backup[0] != NUL ) { my_strcpy(line,backup); backup[0] = NUL; } else { if ( getline(fil,line) == FALSE ) { if ( def_ready ) sending = TRUE; if ( rule_ready ) rule_send = TRUE; gdone = TRUE; continue; /* break the loop, and flush any definitions */ } } parsed = FALSE; /* check for rule or directive, and begin loading it if there */ if (line[0] == '.'){ for (pos = 0 ; line[pos] != ':' && notnull(line[pos]) ; pos++) ; if (isnull(line[pos])) error2("bad rule or directive, needs colon separator:\n%s",line); mark = pos; for ( x = 1 ; x < mark ; x++ ) if ( line[x] == '.' ) break; if ( x == mark ) { /* found DIRECTIVE -- .XXXXX: */ line[mark] = NUL; fword = line + 1; for ( x++ ; isspace(line[x]) ; x++ ) ; restline = line + x ; return( DIRECTIVE ); } else { /* found RULE -- .XX.XXX: */ parsed = TRUE; if ( rule_ready || def_ready ) { if ( def_ready ) sending = TRUE; else rule_send = TRUE; /* push this line, and send what we already have */ my_strcpy(backup,line); } else { /* begin a new rule */ rule_ready = TRUE; line[mark] = NUL; frule = mov_in(line); free_list(q_how); /* one last decision to make. If next non-space char is ';', then the first howto of the rule follows, unless there is a '#', in which case we ignore the comment */ for ( pos++ ; line[pos] != ';' && notnull(line[pos]) ; pos++) if ( !isspace(line[pos]) ) break; if ( notnull(line[pos]) ) { if ( line[pos] == '#' ) ; /* do nothing, fall thru */ else if ( line[pos] != ';' ) /* found non-, non-';' after rule declaration */ error("rule needs ';' or after ':'"); else { /* found :; */ q_how = MkListMem(); q_how->name = mov_in(line + pos + 1 ); q_how->next = NULL; } } } } } /* check for macro, and return it if there */ if ( !parsed ) { pos = 0; while ( line[pos] != '=' && line[pos] != ':' && !isspace(line[pos]) && notnull(line[pos])) pos++; mark = pos; if (notnull(line[pos]) && line[pos] != ':'){ /* found a macro */ if (isspace(line[pos])) while (isspace(line[pos]) && notnull(line[pos])) pos++; if (isnull(line[pos])) panic2("bad macro or definition '%s'",line); if ( line[pos] == '=' ) { /* found a macro */ line[mark] = NUL; fword = line; mark = pos + 1; while ( isspace(line[mark]) ) mark++; /* skip spaces before macro starts */ restline = line + mark; return ( AMACRO ); } } } /* check for and add howto line */ if ( isspace(line[0]) ) { if (!def_ready && !rule_ready) error2("how-to line without preceeding definition or rule\n%s",line); q_how2 = MkListMem(); if ( q_how == NULL ) { q_how = q_how2; } else { for (q_how3 = q_how; q_how3->next != NULL; q_how3 = q_how3->next); /* go to end of list */ q_how3->next = q_how2; } q_how2->name = mov_in(line); q_how2->next = NULL; parsed = TRUE; } /* check for definition */ if (!parsed) { pos = 0; while ( notnull(line[pos]) && line[pos] != ':') pos++; if (line[pos] == ':') { /* found a definition */ parsed = TRUE; if (def_ready || rule_ready) { if ( def_ready ) sending = TRUE; else rule_send = TRUE; my_strcpy(backup,line); } else { /* free up the space used by the previous lists */ free_list(targ);targ = NULL; free_list(q_how);q_how = NULL; free_list(q_dep);q_dep = NULL; line[pos] = NUL; expand(line,exp_line,"",NO_TARG); targ2 = targ = mkllist(exp_line); q_dep = mkllist(line + pos + 1); def_ready = TRUE; } } } if (!parsed) panic2("unable to parse line '%s'",line); } } /* load the next line from 'stream' to 'where' allowing for comment char and line continuations */ getline(stream,where) char *where; FILE *stream; { int i; if (get_stripped_line(where,INMAX,stream) == TRUE) { i = my_strlen(where); where[--i] = NUL; while ( where[i-1] == linecont ) { if ( get_stripped_line(where + i -1,INMAX,stream) == FALSE ) panic("end of file before end of line"); i = my_strlen(where); where[--i] = NUL; } if ( i >= INMAX ) { where[INMAX] = NUL; panic2("line too long\n'%s'",where); } return ( TRUE ); } else return ( FALSE ); } get_stripped_line(where,len,stream) char *where; int len; FILE *stream; { int x; /* return a meaningful line */ while ( TRUE ) { if ( fgets(where,len,stream) == NULL ) return( FALSE ); if ( where[my_strlen(where)-1] != '\n' ) { x = my_strlen(where); where[x] = '\n'; where[x+1] = NUL; } /* terminate standard input with a period alone */ if ( (stream == stdin) && EQ(where,".\n") ) return( FALSE ); /* if the line is only or #, skip it */ for ( x = 0; isspace(where[x]) && (where[x] != '\n') ; x++) ; if ( (where[x] == '\n') || (where[x] == '#') ) continue; /* no reason to throw it out... */ return( TRUE ); } /* NOTREACHED */ } struct llist *mkllist( s ) /* make a linked list */ char *s; { int pos; char lname[INMAX]; struct llist *ptr,*ptr2,*retval; pos = 0; retval = NULL; while ( TRUE ) { /* get the next element, may have quotes */ pos = get_element(s,pos,lname); if ( isnull(lname[0]) ) return( retval ); /* found something to add */ ptr = MkListMem(); if ( retval == NULL ) retval = ptr; else { for (ptr2 = retval; ptr2->next != NULL ; ptr2 = ptr2->next ) ; ptr2->next = ptr; } ptr->name = mov_in(lname); ptr->next = NULL; } } get_element(src,p,dest) char *src,*dest; int p; { int i,quotestop; i = 0; dest[0] = NUL; while ( notnull(src[p]) && isspace(src[p]) ) p++; if ( isnull(src[p]) ) return( p ); if ( src[p] == '"' ) { quotestop = TRUE; p++; } else quotestop = FALSE; while ( TRUE ) { if ( isnull(src[p]) ) break; else if (src[p] == BKSLSH) { if (src[p+1] == '"') p++; dest[i++] = src[p++]; } else if ( !quotestop && isspace(src[p]) ) break; else if ( quotestop && (src[p] == '"') ) break; else dest[i++] = src[p++]; } dest[i] = NUL; return( p ); } struct llist *mkexphow(head,target,eflag) /* make an expanded linked list for how */ struct llist *head; char *target; int eflag; { struct llist *p,*p2,*retval; int x; char temp[INMAX]; if ( head == NULL ) { return ( NULL ); } retval = NULL; while ( head != NULL ) { if ( target != NULL ) expand(head->name,temp,target,eflag); else my_strcpy(temp,head->name); p = MkListMem(); for ( x = 0 ; notnull(temp[x]) ; x++ ) if ( !isspace(temp[x]) ) break; p->name = mov_in(temp + x); p->next = NULL; if ( retval == NULL ) retval = p; else { p2 = retval; while ( p2->next != NULL ) p2 = p2->next; p2->next = p; } head = head->next; } return( retval ); } struct llist *mkexpdep(head,target) /* make an expanded linked list for dep*/ struct llist *head; char *target; { struct llist *p,*p2,*p3,*retval; char temp[INMAX]; if ( head == NULL ) { return ( NULL ); } retval = NULL; while ( head != NULL ) { expand(head->name,temp,target, REPT_ERR); p3 = mkllist(temp); while ( p3 != NULL ) { p = MkListMem(); p->name = mov_in(p3->name); p->next = NULL; if ( retval == NULL ) retval = p; else { p2 = retval; while ( p2->next != NULL ) p2 = p2->next; p2->next = p; } p3 = p3->next; } free_list(p3); head = head->next; } return( retval ); } add_suff(lin) char *lin; { struct llist *ptr; /* add *lin to the list suff_head */ if ( lin == NULL ) return; if ( suff_head == NULL ) suff_head = mkllist(lin); else { /* go to the tail of suff_head */ for ( ptr = suff_head; ptr->next != NULL; ptr = ptr->next ); ptr->next = mkllist(lin); } /* do a little error checking */ for ( ptr = suff_head; ptr != NULL; ptr = ptr->next ) if ( ptr->name[0] != '.' ) error2("add_suffix: bad syntax '%s'",ptr->name); } add_s_suff(lext) char *lext; { struct llist *sptr; /* add this extension to suff_list, if its not already there */ for ( sptr = suff_head; sptr != NULL; sptr = sptr->next ) if ( EQ(sptr->name,lext) ) return; /* must not be there... */ suff_head = add_llist(suff_head,lext); } add_macro(mname,expan) char *mname,*expan; { struct macrec *macp,*macp2; if (maclist == NULL) maclist = macp = (struct macrec *)get_mem((UI) sizeof(struct macrec)); else { macp2 = maclist; while (macp2->nextmac != NULL) { if ( EQ(macp2->name,mname) ) { macp2->mexpand = mov_in(expan); /* previous contents not freed cause mostly they were not malloc()-ed */ return; } macp2 = macp2->nextmac; } if ( EQ(macp2->name,mname) ) { /* if the last on the list matches, replace it */ macp2->mexpand = mov_in(expan); return; } macp2->nextmac = macp = (struct macrec *)get_mem((UI) sizeof(struct macrec)); } macp->name = mov_in(mname); macp->mexpand = mov_in(expan); macp->nextmac = NULL; } add_rule2(adep,atarg,arule,aflag) char *adep,*atarg; struct llist *arule; int aflag; { struct rulerec *rulep,*rulep2; if (rulelist == NULL) rulelist = rulep = (struct rulerec *)get_mem((UI) sizeof(struct rulerec)); else { rulep2 = rulelist; while (rulep2->nextrule != NULL) { if ( EQ(rulep2->dep,adep) && EQ(rulep2->targ,atarg) ) { free_list(rulep2->rule); rulep2->rule = arule; return; } rulep2 = rulep2->nextrule; } if ( EQ(rulep2->dep,adep) && EQ(rulep2->targ,atarg) ) { free_list(rulep2->rule); rulep2->rule = arule; return; } rulep2->nextrule = rulep = (struct rulerec *)get_mem((UI) sizeof(struct rulerec)); } rulep->dep = mov_in(adep); rulep->targ = mov_in(atarg); rulep->rule = arule; rulep->def_flag = aflag; rulep->nextrule = NULL; } free_list(head) /* kill a linked list */ struct llist *head; { struct llist *ptr; if ( head == NULL ) return; else if ( head->next == NULL ) { free( head->name ); free( (char *)head ); return; } else { while ( TRUE ) { for ( ptr = head; ptr->next->next != NULL; ptr = ptr->next ) ; free(ptr->next->name); free((char *)ptr->next); ptr->next = NULL; if ( ptr == head ) { free( ptr->name ); free( (char *)ptr); return; } } } } exec_how(cmd) char *cmd; { int pos,this_echo,this_ign,x,i,no_more_flags; int err_ret; char cmdname[INMAXSH]; i = pos = 0; this_echo = !silentf; this_ign = FALSE; no_more_flags = FALSE; while ( TRUE ) { while ( isspace( cmd[pos] ) ) pos++; switch ( cmd[pos] ) { case '@':this_echo = FALSE;break; case '-':this_ign = TRUE;break; default: no_more_flags = TRUE;break; } if (no_more_flags) break; else pos++; } /* get the name of the command */ for (x=pos; !isspace(cmd[x]) && notnull(cmd[x]); x++) cmdname[i++] = cmd[x]; cmdname[i] = NUL; /* echo if appropriate */ if ( this_echo ) { fprintf(stdout," %s\n",cmd+pos); } else if ( !execute && !this_echo) { fprintf(stdout," %s\n",cmd+pos); return(0); } /* if we are not to actually do it... */ if ( !execute ) return(0); #ifdef LC else if( EQ(cmdname,"write-macro") || EQ(cmdname,"WRITE-MACRO") ) { err_ret = w_macros(cmd+x); return( (this_ign) ? 0 : err_ret); } #endif else { err_ret = perform( cmdname, cmd+pos); return( (this_ign) ? 0 : err_ret ); } } perform(cname, syscmd) char *cname; /* the name of the command */ char *syscmd; /* the string to send to 'system' */ { int x,ccode; #ifndef LC int pid; WAIT status; #endif struct llist *largs; char **vargs,**mkargs(); char wholenam[INMAXSH]; /* if there are metacharacters, use 'system' */ for ( x= 0; notnull(syscmd[x]); x++ ) if ( (syscmd[x] == '>') || (syscmd[x] == '<') || (syscmd[x] == '|') || (syscmd[x] == '*') || (syscmd[x] == '?') || (syscmd[x] == '&') ) { return( mysystem(syscmd) ); } /* is this a builtin command? */ if ( findexec(cname,wholenam) == (TIME) 0 ) { /* file doesn't exist -- yes */ return(mysystem(syscmd)); } /* directly exec a file with args */ largs = mkllist(syscmd); vargs = mkargs(largs); #ifndef LC if ( (pid = fork()) == 0 ) { execv(wholenam,vargs); done( -1 ); } free( (char *)vargs ); free_list( largs ); if ( pid < 0 ) { perror(whoami); return( -1 ); } else { while( ((ccode = wait(&status)) != pid) && (ccode != -1) ); if ( pid < 0 ) { perror(whoami); return( -1 ); } return( pr_warning(&status) ); } #else if ( forkv(wholenam,vargs) != 0 ) { perror(whoami); panicstop(); } free( (char *)vargs ); free_list( largs ); ccode = wait(); return( pr_warning(&ccode) ); #endif } #ifndef LC mysystem(cmd) /* use the SHELL to execute a command line, print warnings */ char *cmd; { int ccode,pid; WAIT status; if ( (pid = fork()) == 0 ) { execl(SHELL, "sh", "-c", cmd, (char *) 0); done( -1 ); } if ( pid < 0 ) { perror(whoami); /* say why we couldn't fork */ return( -1 ); } else { while ( ((ccode = wait(&status)) != pid) && (ccode != -1)); if ( pid < 0 ) { /* no children? */ perror(whoami); return( -1 ); } return( pr_warning(&status) ); } } #else mysystem(cmd) char *cmd; { extern int _oserr; if ( system(cmd) != 0 ) { if ( _oserr == 0 ) panic("Can't process system() args"); else panic("error calling system()"); } return( pr_warning(wait()) ); } #endif pr_warning(s) /* print a warning, if any */ WAIT *s; { #ifdef BSD4.2 if ( (s->w_T.w_Termsig == 0) && (s->w_T.w_Retcode == 0) ) return( 0 ); else { if ( s->w_T.w_Termsig ) fprintf(stderr,"%s: received signal %x\n",whoami,s->w_T.w_Termsig); else { fprintf(stderr,"%s: Error code %x",whoami,s->w_T.w_Retcode); fprintf(stderr,"%s\n",( stopOnErr ) ? "" : " (ignored)"); } return( -1 ); } } #else if ( *s == 0 ) return( 0 ); else { fprintf(stderr,"%s:",whoami); if ( *s & 0xFF) { fprintf(stderr," received signal %x\n",*s & 0xFF); } else { fprintf(stderr," Error code %x",(*s & ~0xFF) >> 8); fprintf(stderr,"%s\n",( stopOnErr ) ? "" : " (ignored)"); } return( -1 ); } } #endif char **mkargs(arglist) struct llist *arglist; { struct llist *ptr; char **retval; int i; /* count up the number of args */ for ( i=0,ptr = arglist; ptr != NULL; ptr = ptr->next,i++); retval = (char **)get_mem(((UI)(i+1)*sizeof(char *))); for ( i=0,ptr=arglist; ptr != NULL; ptr = ptr->next,i++) retval[i] = ptr->name; retval[i] = NULL; return( retval ); } char *get_mem(size) UI size; { char *p,*malloc(); if ((p = malloc(size)) == 0) panic("Ran out of memory"); return(p); } struct llist *MkListMem() { struct llist *p; char *malloc(); if ((p = (struct llist *)malloc(sizeof(struct llist))) == 0 ) panic("Ran out of memory"); return(p); } char *mov_in(string) /* return pointer to fresh memory with copy of string*/ char *string; { char *ptr; ptr = get_mem((UI)(my_strlen(string) + 1)); my_strcpy(ptr,string); return(ptr); } mkpathlist() { char *getenv(); /* go get the PATH variable, and turn it into a linked list */ char *path; path_head = NULL; path = getenv("PATH"); add_path(path); } squeezesp(to,from) char *to,*from; { /* copy from from to to, squeezing out any spaces */ if ( from == NULL ) return; while( *from ) { if ( isspace(*from) ) from++; else *to++ = *from++; } *to = NUL; } TIME findexec(s,where) char *s,*where; { int i; TIME retval; struct llist *ptr; my_strcpy(where,s); /* search for switch character, if present, then this is full name and we won't search the path */ for ( i = 0; notnull(s[i]); i++) if ( s[i] == switchc ) return(getmodified(where)); if ( (retval=getmodified(where)) != (TIME) 0 ) return( retval ); /* if there is no prefix to this file name */ for ( ptr = path_head; ptr != NULL; ptr = ptr->next) { my_strcpy( where, ptr->name); strcat( where, s); if ( (retval=getmodified(where)) != (TIME) 0 ) return( retval ); } return( (TIME)0 ); /* didn't find it */ } TIME getmodified(s) char *s; { struct stat statb; if ( stat(s,&statb) != 0 ) { if ( errno == ENOENT ) return( (TIME) 0 ); else { perror(whoami); if (stopOnErr) panicstop(); else return( (TIME) 0 ); } } else { return( statb.st_mtime ); } /* NOTREACHED */ } add_path(p) char *p; { char temp[50]; int i,k; /* add to the linked list path_head */ k = i = 0; squeezesp(p,p); if ( p == NULL ) return; while ( TRUE ) { while ( notnull(p[k]) && (p[k] != PATHCHAR ) ) temp[i++] = p[k++]; if ( temp[i-1] != switchc ) temp[i++] = switchc; temp[i] = NUL; if ( i == 0 ) return; path_head = add_llist(path_head,temp); if ( isnull(p[k]) ) { return; } k++; i = 0; } } /* emulation of getenv() */ char *getenv(s) char *s; { char **p,*tp,*ematch(); p = ext_env; while ( *p != NULL ) { if ( (tp = ematch(s,*p)) != NULL ) return(mov_in(tp)); p++; } return( NULL ); } char *ematch(s,p) char *s,*p; { /* if match up to the '=', return second half */ while( *s != NULL ) if ( *s++ != *p++ ) return( NULL ); if ( *p++ != '=' ) return( NULL ); return( p ); } #ifdef LC #include stat(st,ptr) char *st; struct stat *ptr; { int fd; TIME getft(),retval; /* return 0 for success, -1 on failure */ fd = open(st,O_RDONLY); if ( fd < 0 ) return( -1 ); retval = getft(fd); if ( retval == (TIME)(-1) ) return( -1 ); else { ptr->st_mtime = retval; return( 0 ); } } #define W_PERLINE 4 #define W_BUFLEN 80 char w_buf[W_BUFLEN]; int w_count; int w_first; w_macros(list) char *list; { FILE *tfp; struct llist *ptr,*ptr2,*mkllist(); if ( (tfp = fopen(tfilename,"w")) == NULL ) { warn2("Can't write to '%s'",tfilename); return( 1 ); /* non-zero is error */ } w_buf[0] = NUL; w_count = 0; w_first = TRUE; ptr = mkllist(list); for ( ptr2 = ptr ; ptr2 != NULL ; ptr2 = ptr2->next ) if ( w_mac2(ptr2->name,tfp,ptr2->next) != 0 ) return( 1 ); /* non-zero is error */ free_list(ptr); if ( w_buf[0] != NUL ) fprintf(tfp,"%s\n",w_buf); fclose(tfp); return( 0 ); } w_mac2(w_word,stream,n) char *w_word; FILE *stream; struct llist *n; { /* write to stream */ if ( !linkerf ) { fprintf(stream,"%s\n",w_word); return( 0 ); } else { if ( w_first ) { my_strcpy(w_buf,w_word); w_first = FALSE; w_count++; } else { strcat(w_buf," + "); if ( (my_strlen(w_buf) + strlen(w_word)) > W_BUFLEN ) { fprintf(stream,"%s\n",w_buf); w_buf[0] = NUL; w_count = 1; } strcat(w_buf,w_word); w_count++; if ( w_count >= W_PERLINE ) { w_count = 0; w_first = TRUE; fprintf(stream,"%s %c\n",w_buf,( n == NULL )?' ':'+'); w_buf[0] = NUL; } else w_count++; } return( 0 ); } /* NOTREACHED */ } warn2(s1,s2) char *s1,*s2; { fprintf(stderr,"%s: ",whoami); fprintf(stderr,s1,s2); fprintf(stderr,"\n"); } #endif done(n) int n; { _cleanup(); exit(n); } my_strlen (src) char *src; { if (src == NULL) return 0; return strlen (src); } my_strcpy (dest, src) char *dest, *src; { if (src == NULL) *dest = '\0'; else return strcpy (dest, src); } # To make 'cp', type: make f=cp # To make 'ls', type: make f=ls # To make 'cat', type: make f=cat # Get the idea? l=/usr/lib i=/usr/include CFLAGS= -I/usr/include -F file: $l/libc.a $f.s @cc -o bin/$f $f.s @chmem =2048 bin/$f >/dev/null @echo "$f done ." mined: mined1.s mined2.s $i/mined.h @asld -o bin/mined $l/crtso.s mined1.s mined2.s $l/libc.a $l/end.s shobj = sh1.s sh2.s sh3.s sh4.s sh5.s sh: $(shobj) $i/sh.h @asld -o bin/sh $l/crtso.s $(shobj) $l/libc.a $l/end.s /* mkdir - make a directory Author: Adri Koppes */ #include "signal.h" int error = 0; main(argc, argv) int argc; char **argv; { if (argc < 2) { std_err("Usage: mkdir directory...\n"); exit(1); } signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); while (--argc) makedir(*++argv); if (error) exit(1); } makedir(dirname) char *dirname; { char dots[128], parent[128]; int sl = 0, i = 0; while (dirname[i]) if (dirname[i++] == '/') sl = i; strncpy(parent, dirname, sl); parent[sl] = '\0'; strcat(parent, "."); if (access(parent, 2)) { stderr3("mkdir: can't access ", parent, "\n"); exit(1); } if (mknod(dirname, 040777, 0)) { stderr3("mkdir: can't create ", dirname, "\n"); error++; return; } chown(dirname, getuid(), getgid()); strcpy(dots, dirname); strcat(dots, "/."); if (link(dirname, dots)) { stderr3("mkdir: can't link ", dots, " to "); stderr3(dirname, "\n", ""); error++; unlink(dirname); return; } strcat(dots, "."); if (link(parent, dots)) { stderr3("mkdir: can't link ", dots, " to "); stderr3(parent, "\n", ""); error++; dots[strlen(dots)] = '\0'; unlink(dots); unlink(dirname); return; } } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); } /* mkfs - make the MINIX filesystem * Andy Tanenbaum & Paul Ogilvie, Jun 1986 * * This program was initially designed to build a filesystem * with blocksize = zonesize. During the course of time the * program is being converted to handle zone_size > blocksize * but this isn't complete yet. Where routines can handle the * situation this is mentioned in the comment. * * To compile this program for MS-DOS, use: cc -DDOS mkfs.c diskio.asm * To compile this program for UNIX, use: cc -DUNIX mkfs.c * To compile this program for MINIX, use: cc mkfs.c */ #include "const.h" #include "type.h" #include "../fs/const.h" #undef EXTERN #define EXTERN /* get rid of EXTERN by making it null */ #include "../fs/type.h" #include "../fs/super.h" #ifdef DOS #include "/lib/c86/stdio.h" #define COMPILERFLAG #endif #ifdef UNIX #include #include #include #undef major #undef minor #define COMPILERFLAG #endif #ifndef COMPILERFLAG #include "stdio.h" #include "stat.h" #endif #ifndef DOS #ifndef UNIX #define UNIX #endif #endif #ifdef UNIX #undef printf /* printf is a macro for printk */ #endif #define INODE_MAP 2 #define MAX_TOKENS 10 #define LINE_LEN 200 #define BIN 2 #define BINGRP 2 #define BIT_MAP_SHIFT 13 #define N_BLOCKS 32000 /* must be multiple of 8 */ #ifdef DOS # define BREAD 4 # define BWRITE 5 #else # define BREAD 0 # define BWRITE 1 #endif int next_zone, next_inode, zone_size, zone_shift=0, zoff, nrblocks,inode_offset, nrinodes, lct=1, disk, fd, print=0, file=0, override=0, simple=0, dflag; long current_time, bin_time; char zero[BLOCK_SIZE], *lastp; char umap[(N_BLOCKS+8)/8]; /* bit map tells if block read yet */ int zone_map = 3; /* where is zone map? (depends on # inodes) */ FILE *proto; long lseek(); char *size_fmt = "%6D"; char *ldfmt = "%6ld"; char *mode_fmt = "%6o"; char *ldmode = "%06o"; char gwarning[] = {65,46,83,46,84,97,110,101,110,98,97,117,109,10}; /* MS-DOS and PC-IX use %ld for longs, MINIX uses %D */ /*================================================================ * mkfs - make filesystem *===============================================================*/ main(argc, argv) int argc; char *argv[]; { int i, blocks, zones, inodes, mode, usrid, grpid, badusage = 0; char *token[MAX_TOKENS], buf[BLOCK_SIZE]; int testb[2]; FILE *fopen(); long time(), ls; struct stat statbuf; /* Get two times, the current time and the mod time of the binary of * mkfs itself. When the -d flag is used, the later time is put into * the i_modtimes of all the files. This feature is useful when producing * a set of file systems, and one wants all the times to be identical. * First you set the time of the mkfs binary to what you want, then go. */ current_time = time(0L); /* time mkfs is being run */ stat(argv[0], &statbuf); bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */ /* process parameters and switches */ if (argc != 3 && argc != 4) badusage = 1; if (stat(argv[argc - 1], &statbuf) == 0) { if ( (statbuf.st_mode&S_IFMT) != S_IFREG) badusage = 1; } if (badusage) { write(2, "Usage: mkfs [-L] special proto\n", 31); exit(1); } while (--argc) { switch (argv[argc][0]) { case '-': while (*++argv[argc]) switch (*argv[argc]) { case 'L' : print=1; break; case 'l' : print=1; size_fmt = ldfmt; mode_fmt = ldmode; break; case 'o' : case 'O' : override=1; break; case 'd' : current_time = bin_time; dflag=1; break; default : printf ("Bad switch %c, ignored.\n",*argv[argc]); } break; default : /* process proto & special */ proto = fopen(argv[argc], "r" ); if (proto != NULL) { /* Prototype file is readable. */ getline(buf, token); /* skip boot block info. */ /* Read the line with the block and inode counts. */ getline(buf, token); blocks = atoi(token[0]); if (blocks > N_BLOCKS) pexit("Block count too large"); inodes = atoi(token[1]); /* Process mode line for root directory. */ getline(buf, token); mode = mode_con(token[0]); usrid = atoi(token[1]); grpid = atoi(token[2]); } else { /* Maybe the prototype file is just a size. Check for that. */ blocks = atoi(argv[argc]); if (blocks < 4) pexit("Can't open prototype file"); /* Ok, make simple file system of given size, using defaults. */ inodes = (blocks/3) + 8; /* default is 3 blocks/file */ mode = 040777; usrid = BIN; grpid = BINGRP; simple = 1; } /* open special */ argc--; special(argv[argc]); nrblocks = blocks; nrinodes = inodes; } /* end switch */ } /* end while */ #ifdef UNIX /* Try writing the last block of partition or diskette. */ ls = lseek(fd, ((long)blocks - 1L) * BLOCK_SIZE, 0); testb[0] = 0x3245; testb[1] = 0x11FF; if (write(fd, testb, BLOCK_SIZE) != BLOCK_SIZE) pexit("File system is too big for minor device"); lseek(fd, ((long)blocks - 1L) * BLOCK_SIZE, 0); testb[0] = 0; testb[1] = 0; i = read(fd, testb, BLOCK_SIZE); if (i != BLOCK_SIZE || testb[0] != 0x3245 || testb[1] != 0x11FF) pexit("File system is too big for minor device"); lseek(fd, 0L, 0); #endif /* make the file-system */ cache_init(); put_block (0, zero); /* Write a null boot block. */ zone_shift = 0; /* for future use */ zones = blocks >> zone_shift; super(zones, inodes); i = alloc_inode(mode, usrid, grpid); rootdir(i); if (simple == 0) eat_dir(i); if (print) print_fs(); flush(); exit (0); } /* end main */ /*================================================================ * super - construct a superblock *===============================================================*/ super(zones, inodes) int zones, inodes; { unsigned int i, inodeblks, initblks, initzones, nrzones, bs; unsigned int map_size, bit_map_len, b_needed, b_allocated, residual; long zo; struct super_block *sup; char buf[BLOCK_SIZE], *cp; sup= (struct super_block *) buf; bs = 1 << BIT_MAP_SHIFT; sup->s_ninodes = inodes; sup->s_nzones = zones; sup->s_imap_blocks = (inodes + bs)/bs; sup->s_zmap_blocks = (zones + bs - 1)/bs; inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2; inodeblks = (inodes + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK; initblks = inode_offset + inodeblks; initzones = (initblks + (1<> zone_shift; nrzones = nrblocks >> zone_shift; sup->s_firstdatazone = (initblks + (1<> zone_shift; zoff = sup->s_firstdatazone - 1; sup->s_log_zone_size = zone_shift; sup->s_magic = SUPER_MAGIC; /* identify super blocks */ zo = 7L + (long) NR_INDIRECTS + (long) NR_INDIRECTS * NR_INDIRECTS; sup->s_max_size = zo * BLOCK_SIZE; zone_size = 1 << zone_shift; /* nr of blocks per zone */ for (cp = buf + sizeof(*sup); cp < &buf[BLOCK_SIZE]; cp++) *cp=0; put_block (1,buf); /* Clear maps and inodes. */ for (i = 2; i < initblks; i++) put_block (i, zero); next_zone = sup->s_firstdatazone; next_inode = 1; /* Mark all bits beyond the end of the legal inodes and zones as allocated. * Unfortunately, the coding the bit maps is inconsistent. The rules are: * For inodes: Every i-node occupies a bit map slot, even i-node 0 * The first i-node on the disk is i-node 1, not 0 * For zones: Zone map bit 0 is for the last i-node block on disk * The first zone available goes with bit 1 in the map * * Thus for i-nodes, every i-node, starting at 0 occupies a bit map slot, * but for zones, only those starting with the final i-node block occupy * bit slots. This is inconsistent. In retrospect it would might have been * simpler to have bit 0 of the zone map be zone 0 on the disk. Although * this would have increased the zone bit map by a few dozen bits, it would * have prevented a number of bugs in the early days. This is an example of * what happens when one ignores  the maxim: First make it work, then make * it optimal. For both maps, 0 = available, 1 = in use. */ /* Mark bits beyond end of inodes as allocated. (Fails if >8192 inodes). */ map_size = 1 << BIT_MAP_SHIFT; bit_map_len = nrinodes + 1; /* # bits needed in map */ residual = bit_map_len % (8 * BLOCK_SIZE); if (residual == 0) residual = 8 * BLOCK_SIZE; b_needed = (bit_map_len + map_size - 1 ) >> BIT_MAP_SHIFT; zone_map += b_needed - 1; /* if imap > 1, adjust start of zone map */ insert_bit(INODE_MAP + b_needed - 1, residual, 8 * BLOCK_SIZE - residual); bit_map_len = nrzones - initzones + 1; /* # bits needed in map */ residual = bit_map_len % (8 * BLOCK_SIZE); if (residual == 0) residual = 8 * BLOCK_SIZE; b_needed = (bit_map_len + map_size - 1 ) >> BIT_MAP_SHIFT; b_allocated = (nrzones + map_size - 1 ) >> BIT_MAP_SHIFT; insert_bit(zone_map + b_needed - 1, residual, 8 * BLOCK_SIZE - residual); if (b_needed != b_allocated) { insert_bit(zone_map + b_allocated - 1, 0, map_size); } insert_bit(zone_map, 0, 1); /* bit zero must always be allocated */ insert_bit(INODE_MAP, 0, 1); /* inode zero not used but must be allocated */ } /*================================================================ * rootdir - install the root directory *===============================================================*/ rootdir(inode) int inode; { int z; z = alloc_zone(); add_zone (inode, z, 32L, current_time); enter_dir(inode, ".", inode); enter_dir(inode, "..", inode); incr_link(inode); incr_link(inode); } /*================================================================ * eat_dir - recursively install directory *===============================================================*/ eat_dir(parent) int parent; /* parent's inode nr */ { /*Read prototype lines and set up directory. Recurse if need be. */ char *token[MAX_TOKENS], *p; char line[LINE_LEN]; int mode, n, usrid, grpid, z, major, minor, f; long size; while (1) { getline(line, token); p = token[0]; if (*p == '$') return; p = token[1]; mode = mode_con(p); usrid = atoi(token[2]); grpid = atoi(token[3]); if (grpid & 0200) write(2, gwarning, 14); n = alloc_inode(mode, usrid, grpid); /* Enter name in directory and update directory's size. */ enter_dir(parent, token[0], n); incr_size(parent, 16L); /* Check to see if file is directory or special. */ incr_link(n); if (*p == 'd') { /* This is a directory. */ z = alloc_zone(); /* zone for new directory */ add_zone(n, z, 32L, current_time); enter_dir(n, ".", n); enter_dir(n, "..", parent); incr_link(parent); incr_link(n); eat_dir(n); } else if (*p == 'b' || *p == 'c') { /* Special file. */ major = atoi(token[4]); minor = atoi(token[5]); size = atoi(token[6]); size = BLOCK_SIZE * size; add_zone(n, (major<<8)|minor, size, current_time); } else { /* Regular file. Go read it. */ if ((f=open(token[4],BREAD)) < 0) { write(2, "Can't open file ", 16); write(2, token[4], strlen(token[4]) ); write(2, "\n", 1); } else eat_file(n, f); } } } /*================================================================ * eat_file - copy file to MINIX *===============================================================*/ /* zonesize >= blocksize */ eat_file(inode, f) int inode, f; { int z, ct, i, j, k; char buf[BLOCK_SIZE]; long timeval; extern long file_time(); do { for (i=0, j=0; i < zone_size; i++, j+=ct ) { for (k = 0; k < BLOCK_SIZE; k++) buf[k] = 0; if ((ct=read(f,buf, BLOCK_SIZE)) > 0) { if (i==0) z = alloc_zone(); put_block ( (z << zone_shift) + i, buf); } } timeval = (dflag ? current_time : file_time(f) ); if (ct) add_zone (inode, z, (long) j, timeval ); } while (ct == BLOCK_SIZE); close(f); } /*================================================================ * directory & inode management assist group *===============================================================*/ enter_dir(parent, name, child) int parent, child; /* inode nums */ char *name; { /* enter child in parent directory */ /* works for dir > 1 block and zone > block */ int i, j, k, l, b, z, off; char *p1, *p2; struct { short inumb; char name[14]; } dir_entry[NR_DIR_ENTRIES]; d_inode ino[INODES_PER_BLOCK]; b = ((parent-1) / INODES_PER_BLOCK) + inode_offset; off = (parent-1) % INODES_PER_BLOCK ; get_block ( b, ino); for ( k=0; ki_size += bytes; p->i_modtime = cur_time; for (i=0; i < NR_DZONE_NUM; i++) if (p->i_zone[i] == 0) { p->i_zone[i] = z; put_block(b, inode); return; } put_block(b, inode); /* File has grown beyond a small file. */ if (p->i_zone[NR_DZONE_NUM] == 0) p->i_zone[NR_DZONE_NUM] = alloc_zone(); indir = p->i_zone[NR_DZONE_NUM]; put_block(b, inode); b = indir << zone_shift; get_block(b, blk); for (i = 0; i < NR_INDIRECTS; i++) if (blk[i] == 0) { blk[i] = (zone_nr) z; put_block(b, blk); return; } pexit("File has grown beyond single indirect"); } incr_link(n) int n; { /* increment the link count to inode n */ int b, off; d_inode inode[INODES_PER_BLOCK]; b = ((n-1)/INODES_PER_BLOCK) + inode_offset; off = (n-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_nlinks++; put_block(b, inode); } incr_size(n,count) int n; long count; { /* increment the file-size in inode n */ int b, off; d_inode inode[INODES_PER_BLOCK]; b = ((n-1)/INODES_PER_BLOCK) + inode_offset; off = (n-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_size += count; put_block(b, inode); } /*================================================================ * allocation assist group *===============================================================*/ int alloc_inode(mode, usrid, grpid) int mode, usrid, grpid; { int num, b, off; d_inode inode[INODES_PER_BLOCK]; num = next_inode++; if (num >= nrinodes) pexit("File system does not have enough inodes"); b = ((num-1) / INODES_PER_BLOCK) + inode_offset; off = (num-1) % INODES_PER_BLOCK; get_block(b, inode); inode[off].i_mode = mode; inode[off].i_uid = usrid; inode[off].i_gid = grpid; put_block(b, inode); /* Set the bit in the bit map. */ insert_bit(INODE_MAP, num, 1); return(num); } int alloc_zone() { /* allocate a new zone */ /* works for zone > block */ int b,z,i; z = next_zone++; b = z << zone_shift; if ( (b+zone_size) > nrblocks) pexit("File system not big enough for all the files"); for ( i=0; i < zone_size; i++) put_block ( b+i, zero ); /* give an empty zone */ insert_bit(zone_map, z - zoff, 1); return(z); } insert_bit(block, bit, count) int block, bit, count; { /* insert 'count' bits in the bitmap */ int w,s, i; int buf[BLOCK_SIZE/sizeof(int)]; get_block(block, buf); for (i = bit; i < bit + count; i++) { w = i / (8*sizeof(int)); s = i % (8*sizeof(int)); buf[w] |= (1 << s); } put_block(block, buf); } /*================================================================ * proto-file processing assist group *===============================================================*/ int mode_con(p) char *p; { /* convert string to mode */ int o1, o2, o3, mode; char c1, c2, c3; c1 = *p++; c2 = *p++; c3 = *p++; o1 = *p++ - '0'; o2 = *p++ - '0'; o3 = *p++ - '0'; mode = (o1 << 6) | (o2 << 3) | o3; if (c1 == 'd') mode += I_DIRECTORY; if (c1 == 'b') mode += I_BLOCK_SPECIAL; if (c1 == 'c') mode += I_CHAR_SPECIAL; if (c1 == '-') mode += I_REGULAR; if (c2 == 'u') mode += I_SET_UID_BIT; if (c3 == 'g') mode += I_SET_GID_BIT; return(mode); } getline(line, parse) char *parse[MAX_TOKENS]; char line[LINE_LEN]; { /* read a line and break it up in tokens */ int k; char c, *p; for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0; for (k = 0; k < LINE_LEN; k++) line[k] = 0; k = 0; parse[0] = 0; p = line; while (1) { *p = fgetc(proto); if (*p == '\n') lct++; if (*p <= 0) pexit("Unexpected end-of-file\n"); if (*p == ' ' || *p == '\t') *p = 0; if (*p == '\n') {*p++ = 0; *p = '\n'; break;} p++; } p = line; lastp = line; while (1) { c = *p++; if (c == '\n') return; if (c == 0) continue; parse[k++] = p - 1; do { c = *p++; } while (c != 0 && c != '\n'); } } /*================================================================ * other stuff *===============================================================*/ long file_time(f) int f; { #ifdef UNIX struct stat statbuf; fstat(f, & statbuf); return (statbuf.st_mtime); #else /* fstat not supported by DOS */ return( 0L ); #endif } pexit(s) char *s; { char *s0; s0 = s; while (*s0 != 0) s0++; write (2,"Error: ", 7); write (2, s, (int)(s0-s) ); write(2, "\n", 1); printf("Line %d being processed when error detected.\n", lct); flush(); exit(2); } copy (from, to, count) char *from, *to; int count; { while (count--) *to++ = *from++; } print_fs() { int i, j, k; d_inode inode[INODES_PER_BLOCK]; int ibuf[INTS_PER_BLOCK], b; struct { short inum; char name[14]; } dir[NR_DIR_ENTRIES]; get_block(1, ibuf); printf("\nSuperblock: "); for (i= 0; i<8; i++) printf("%06o ",ibuf[i]); get_block(2, ibuf); printf("\nInode map: "); for (i = 0; i < 9; i++) printf("%06o ", ibuf[i]); get_block(3, ibuf); printf("\nZone map: "); for (i = 0; i < 9; i++) printf("%06o ", ibuf[i]); printf("\n"); for (b = 4; b < 8; b++) { get_block(b, inode); for (i = 0; i < INODES_PER_BLOCK; i++) { k = INODES_PER_BLOCK * (b - 4) + i + 1; if (k > nrinodes) break; if (inode[i].i_mode != 0) { printf("Inode %2d: mode=",k, inode[i].i_mode); printf(mode_fmt, inode[i].i_mode); printf(" uid=%2d gid=%2d size=", inode[i].i_uid, inode[i].i_gid); printf(size_fmt, inode[i].i_size); printf(" zone[0]=%d\n", inode[i].i_zone[0]); } if ( (inode[i].i_mode & I_TYPE) == I_DIRECTORY) { /* This is a directory */ get_block(inode[i].i_zone[0], dir); for (j = 0; j < NR_DIR_ENTRIES; j++) if (dir[j].inum) printf("\tInode %2d: %s\n",dir[j].inum,dir[j].name); } } } printf("%d inodes used. %d zones used.\n",next_inode-1, next_zone); } int read_and_set(n) int n; { /* The first time a block is read, it returns alls 0s, unless there has * been a write. This routine checks to see if a block has been accessed. */ int w, s, mask, r; w = n/8; s = n%8; mask = 1 << s; r = (umap[w] & mask ? 1 : 0); umap[w] |= mask; return(r); } /*================================================================ * get_block & put_block for MS-DOS *===============================================================*/ #ifdef DOS /* * These are the get_block and put_block routines * when compiling & running mkfs.c under MS-DOS. * * It requires the (asembler) routines absread & abswrite * from the file diskio.asm. Since these routines just do * as they are told (read & write the sector specified), * a local cache is used to minimize the i/o-overhead for * frequently used blocks. * * The global variable "file" determines whether the output * is to a disk-device or to a binary file. */ #define PH_SECTSIZE 512 /* size of a physical disk-sector */ char *derrtab[14] = { "no error", "disk is read-only", "unknown unit", "device not ready", "bad command", "data error", "internal error: bad request structure length", "seek error", "unknown media type", "sector not found", "printer out of paper (??)", "write fault", "read error", "general error" }; #define CACHE_SIZE 20 /* 20 block-buffers */ struct cache { char blockbuf[BLOCK_SIZE]; int blocknum; int dirty; int usecnt; } cache[CACHE_SIZE]; special (string) char *string; { if (string[1] == ':' && string[2]==0) { /* format: d: or d:fname */ disk = (string[0] & ~32) - 'A'; if (disk>1 && !override) /* safety precaution */ pexit ("Bad drive specifier for special"); } else { file=1; if ((fd = creat(string,BWRITE)) == 0) pexit ("Can't open special file"); } } get_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* get a block to the user */ struct cache *bp,*fp; /* First access returns a zero block */ if (read_and_set(n) == 0) { copy(zero, buf, BLOCK_SIZE); return; } /* look for block in cache */ fp=0; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) { if (bp->blocknum==n) { copy (bp,buf,BLOCK_SIZE); bp->usecnt++; return; } /* remember clean block */ if (bp->dirty == 0) if (fp) {if (fp->usecnt > bp->usecnt) fp=bp;} else fp=bp; } /* block not in cache, get it */ if (!fp) { /* no clean buf, flush one */ for (bp=cache,fp=cache; bp<&cache[CACHE_SIZE]; bp++) if (fp->usecnt > bp->usecnt) fp=bp; mx_write (fp->blocknum, fp); } mx_read (n, fp); fp->dirty=0; fp->usecnt=0; fp->blocknum=n; copy (fp, buf, BLOCK_SIZE); } put_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Accept block from user */ struct cache *fp, *bp; read_and_set(n); /* look for block in cache */ fp=0; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) { if (bp->blocknum==n) { copy (buf,bp,BLOCK_SIZE); bp->dirty=1; return; } /* remember clean block */ if (bp->dirty == 0) if (fp) {if (fp->usecnt > bp->usecnt) fp=bp;} else fp=bp; } /* block not in cache */ if (!fp) { /* no clean buf, flush one */ for (bp=cache,fp=cache; bp<&cache[CACHE_SIZE]; bp++) if (fp->usecnt > bp->usecnt) fp=bp; mx_write (fp->blocknum, fp); } fp->dirty=1; fp->usecnt=1; fp->blocknum=n; copy (buf,fp,BLOCK_SIZE); } cache_init() { struct cache *bp; for (bp=cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1; } flush () { /* flush all dirty blocks to disk */ struct cache *bp; for (bp=cache; bp<&cache[CACHE_SIZE]; bp++) if (bp->dirty) { mx_write (bp->blocknum, bp); bp->dirty=0; } } /*================================================================== * hard read & write etc. *=================================================================*/ #define MAX_RETRIES 5 mx_read (blocknr,buf) int blocknr; char buf[BLOCK_SIZE]; { /* read the requested MINIX-block in core */ char (*bp)[PH_SECTSIZE]; int sectnum,retries,err; if (file) { lseek (fd, (long) blocknr * BLOCK_SIZE, 0); if (read (fd, buf, BLOCK_SIZE) != BLOCK_SIZE) pexit ("mx_read: error reading file"); } else { sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE); for (bp=buf; bp<&buf[BLOCK_SIZE]; bp++) { retries = MAX_RETRIES; do err=absread (disk,sectnum,bp); while (err && --retries); if (retries) { sectnum++; } else { dexit ("mx_read",sectnum,err); } } } } mx_write (blocknr,buf) int blocknr; char buf[BLOCK_SIZE]; { /* write the MINIX-block to disk */ char (*bp)[PH_SECTSIZE]; int retries,sectnum,err; if (file) { lseek (fd, blocknr * BLOCK_SIZE, 0); if (write (fd, buf, BLOCK_SIZE) != BLOCK_SIZE) { pexit ("mx_write: error writing file"); } } else { sectnum = blocknr * (BLOCK_SIZE / PH_SECTSIZE); for (bp=buf; bp<&buf[BLOCK_SIZE]; bp++) { retries = MAX_RETRIES; do { err=abswrite (disk,sectnum,bp); } while (err && --retries); if (retries) { sectnum++; } else { dexit ("mx_write",sectnum,err); } } } } dexit (s,sectnum,err) int sectnum, err; char *s; { printf ("Error: %s, sector: %d, code: %d, meaning: %s\n", s, sectnum, err, derrtab[err] ); exit (2); } #endif /*================================================================ * get_block & put_block for UNIX *===============================================================*/ #ifdef UNIX special (string) char *string; { fd = creat(string, 0777); close(fd); fd = open(string, 2); if (fd < 0) pexit("Can't open special file"); } get_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Read a block. */ int k; /* First access returns a zero block */ if (read_and_set(n) == 0) { copy(zero, buf, BLOCK_SIZE); return; } lseek(fd, (long) n*BLOCK_SIZE, 0); k = read(fd, buf, BLOCK_SIZE); if (k != BLOCK_SIZE) { pexit("get_block couldn't read"); } } put_block(n, buf) int n; char buf[BLOCK_SIZE]; { /* Write a block. */ read_and_set(n); if (lseek(fd, (long)n*BLOCK_SIZE, 0) < 0L) { pexit("put_block couldn't seek"); } if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) { pexit("put_block couldn't write"); } } /* dummy routines to keep source file clean from #ifdefs */ flush() { return; } cache_init() { return; } #endif /* mknod - build a special file Author: Andy Tanenbaum */ main(argc, argv) int argc; char *argv[]; { /* mknod name b/c major minor makes a node. */ int mode, major, minor; if (argc != 5) badcomm(); if (*argv[2] != 'b' && *argv[2] != 'c') badcomm(); mode = (*argv[2] == 'b' ? 060666 : 020666); major = atoi(argv[3]); minor = atoi(argv[4]); if (major < 0 || minor < 0) badcomm(); if (mknod(argv[1], mode, (major<<8) | minor) < 0) perror("mknod"); exit(0); } int atoi(p) char *p; { /* Ascii to integer conversion. */ int c, n; n = 0; while (c = *p++) { if (c < '0' || c > '9') return (-1); n = 10 * n + (c - '0'); } return(n); } badcomm() { std_err("Usage: mknod name b/c major minor\n"); exit(1); } /* more - terminal pager Author: Brandon S. Allbery */ /* Pager commands: * display next page * scroll up 1 line * q quit */ #define reverse() write(1, "\033z\160", 3) /* reverse video */ #define normal() write(1, "\033z\7", 3) /* undo reverse() */ #define clearln() write(1, "\r\033~0", 4) /* clear line */ #define LINES 23 /* lines/screen (- 1 to retain last line) */ #define COLS 80 /* columns/line */ #define TABSTOP 8 /* tabstop expansion */ #include #include extern int byebye(); extern char *index(); int line = 0; /* current terminal line */ int col = 0; /* current terminal column */ int fd = -1; /* terminal file descriptor (/dev/tty) */ struct sgttyb ttymode; /* and the terminal modes */ char ibuf[1024]; /* input buffer */ char obuf[1024]; /* output buffer */ int ibl = 0; /* chars in input buffer */ int ibc = 0; /* position in input buffer */ int obc = 0; /* position in output buffer (== chars in) */ int isrewind = 0; /* flag: ' command -- next input() rewind */ int isdone = 0; /* flag: return EOF next read even if not */ main(argc, argv) char **argv; { char ch; int fd, arg; signal(SIGINT, byebye); fd = 0; cbreak(); if (argc < 2) while ((ch = input(fd)) != 0) output(ch); else for (arg = 1; argv[arg] != (char *) 0; arg++) { if ((fd = open(argv[arg], 0)) == -1) { write(1, "more: cannot open ", 18); write(1, argv[arg], strlen(argv[arg])); write(1, "\n", 1); nocbreak(); exit(1); } while ((ch = input(fd)) != 0) output(ch); close(fd); if (argv[arg + 1] != (char *) 0) { oflush(); if (isdone) { /* 'n' command */ reverse(); write(1, "*** Skipping to next file ***\n", 30); normal(); isdone = 0; } reverse(); write(1, "--More-- (Next file: ", 21); write(1, argv[arg + 1], strlen(argv[arg + 1])); write(1, ")", 1); normal(); switch (wtch()) { case ' ': case '\'': case 'n': case 'N': line = 0; break; case '\r': case '\n': line = LINES - 1; break; case 'q': case 'Q': clearln(); byebye(); } clearln(); } } oflush(); byebye(); } input(fd) { if (isdone) { ibl = 0; ibc = 0; return 0; } if (isrewind) { lseek(fd, 0L, 0); ibl = 0; ibc = 0; isrewind = 0; } if (ibc == ibl) { ibc = 0; if ((ibl = read(fd, ibuf, sizeof ibuf)) <= 0) return 0; } return ibuf[ibc++]; } output(c) char c; { if (obc == sizeof obuf) { lwrite(1, obuf, sizeof obuf); obc = 0; } if (!isrewind) obuf[obc++] = c; } oflush() { if (!isdone) lwrite(1, obuf, obc); obc = 0; } lwrite(fd, buf, len) char *buf; unsigned len; { unsigned here, start; char cmd; start = 0; here = 0; while (here != len) { cmd = '\0'; switch (buf[here++]) { case '\n': col = 0; if (++line == LINES) { write(fd, buf + start, here - start); reverse(); write(1, "--More--", 8); normal(); cmd = wtch(); clearln(); line = 0; start = here; } break; case '\r': col = 0; break; case '\b': if (col != 0) col--; else { line--; col = COLS - 1; } break; case '\t': do { col++; } while (col % TABSTOP != 0); break; default: if (++col == COLS) { col = 0; if (++line == LINES) { write(fd, buf + start, here - start); reverse(); write(1, "--More--", 8); normal(); cmd = wtch(); clearln(); line = 0; start = here; } } } switch (cmd) { case '\0': break; case ' ': line = 0; break; case '\r': case '\n': line = LINES - 1; break; case 'q': case 'Q': byebye(); case '\'': isrewind = 1; reverse(); write(1, "*** Back ***\n", 13); normal(); return; case 'n': case 'N': isdone = 1; return; default: break; } } if (here != start) write(fd, buf + start, here - start); } wtch() { char ch; do { read(fd, &ch, 1); } while (index(" \r\nqQ'nN", ch) == (char *) 0); return ch; } cbreak() { if (fd != -1) return; if ((fd = open("/dev/tty", 0)) == -1) { write(2, "OOPS -- can't open /dev/tty\n", 28); exit(1); } ioctl(fd, TIOCGETP, &ttymode); ttymode.sg_flags |= CBREAK; ttymode.sg_flags &= ~ECHO; ioctl(fd, TIOCSETP, &ttymode); /* NB: add TIOCSETN! */ } nocbreak() { if (fd == -1) return; ttymode.sg_flags &= ~CBREAK; ttymode.sg_flags |= ECHO; ioctl(fd, TIOCSETP, &ttymode); close(fd); fd = -1; } byebye() { nocbreak(); exit(0); } /* mount - mount a file system Author: Andy Tanenbaum */ #include "errno.h" extern int errno; main(argc, argv) int argc; char *argv[]; { int ro; if (argc < 3 || argc > 4) usage(); if (argc == 4 && *argv[3] != '-' && *(argv[3]+1) != 'r') usage(); ro = (argc == 4 ? 1 : 0); if (mount(argv[1], argv[2], ro) < 0) { if (errno == EINVAL) { std_err("mount: "); std_err(argv[1]); std_err(" is not a valid file system.\n"); } else { perror("mount"); } exit(1); } std_err(argv[1]); std_err(" mounted\n"); exit(0); } usage() { std_err("Usage: mount special name [-r]\n"); exit(1); } /* mv - move files Author: Adri Koppes * * 4/25/87 - J. Paradis Bug fixes for directory handling */ #include "signal.h" #include "stat.h" int error = 0; struct stat st, st1; main (argc, argv) int argc; char **argv; { char *destdir; if (argc < 3) { std_err ("Usage: mv file1 file2 or mv dir1 dir2 or mv file1 file2 ... dir\n"); exit (1); } if (argc == 3) { if (stat (argv[1], &st)) { std_err ("mv: "); std_err (argv[1]); std_err (" doesn't exist\n"); exit (1); } move (argv[1], argv[2]); } else { destdir = argv[--argc]; if (stat (destdir, &st)) { std_err ("mv: target directory "); std_err (destdir); std_err (" doesn't exist\n"); exit(1); } if ((st.st_mode & S_IFMT) != S_IFDIR) { std_err ("mv: target "); std_err (destdir); std_err (" not a directory\n"); exit (1); } while (--argc) move (*++argv, destdir); } if (error) exit (1); exit(0); } move (old, new) char *old, *new; { int retval; char name[64]; /* It's too dangerous to fool with "." or ".." ! */ if((strcmp(old, ".") == 0) || (strcmp(old, "..") == 0)) { cant(old); } /* Don't move a file to itself. */ if (stat(old, &st)==0 && stat(new, &st1)==0 && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) cant(old); if (!stat (new, &st)) if((st.st_mode & S_IFMT) != S_IFDIR) unlink (new); else { char *p, *rindex(); if ((strlen(old) + strlen(new) + 2) > 64) { cant(old); error++; return; } strcpy(name, new); strcat(name, "/"); p = rindex(old, '/'); strcat(name, p ? p : old); new = name; } stat (old, &st); if (link (old, new)) if ((st.st_mode & S_IFMT) != S_IFDIR) { switch (fork ()) { case 0: setgid (getgid ()); setuid (getuid ()); execl ("/bin/cp", "cp", old, new, (char *) 0); cant(old); case -1: std_err ("mv: can't fork\n"); exit (1); default: wait (&retval); if (retval) cant(old); } } else cant(old); /* If this was a directory that we moved, then we have ** to update its ".." entry (in case it was moved some- ** where else in the tree...) */ if ((st.st_mode & S_IFMT) == S_IFDIR) { int i; char parent[64], dotdot[64]; strcpy(parent, new); /* Determine the name for the parent of ** the new name by counting back until we ** hit a '/' or the begining of the string */ for(i = (strlen(parent) - 1); i > 0; i--) { if(parent[i] == '/') break; } /* If there are no slashes, then the name is ** in the current directory, so its parent ** is ".". Otherwise, the parent is the name ** up to the last slash. */ if(i == 0) { strcpy(parent, "."); } else { /* null-terminate name at last slash */ parent[i] = '\0'; } /* Unlink the ".." entry */ strcpy(dotdot, new); strcat(dotdot, "/.."); unlink(dotdot); /* Now link it to its parent */ link(parent, dotdot); } utime (new, &st.st_atime); unlink(old); } cant(name) char *name; { std_err("mv: can't move "); std_err (name); std_err ("\n"); exit (1); } /* od - octal dump Author: Andy Tanenbaum */ #include "stdio.h" int bflag, cflag, dflag, oflag, xflag, hflag, linenr, width, state, ever; int prevwds[8]; long off; char buf[512], buffer[BUFSIZ]; int next; int bytespresent; char hexit(); main(argc, argv) int argc; char *argv[]; { int k, flags; long offset(); char *p; /* Process flags */ setbuf(stdout, buffer); flags = 0; p = argv[1]; if (argc > 1 && *p == '-') { /* Flags present. */ flags++; p++; while (*p) { switch(*p) { case 'b': bflag++; break; case 'c': cflag++; break; case 'd': dflag++; break; case 'h': hflag++; break; case 'o': oflag++; break; case 'x': xflag++; break; default: usage(); } p++; } } else { oflag = 1; } if ( (bflag | cflag | dflag | oflag | xflag) == 0) oflag = 1; k = (flags ? 2 : 1); if (bflag | cflag ) { width = 8; } else if (oflag) { width = 7; } else if (dflag) { width = 6; } else { width = 5; } /* Process file name, if any. */ p = argv[k]; if (k < argc && *p != '+') { /* Explicit file name given. */ close(0); if (open(argv[k], 0) != 0) { std_err("od: cannot open "); std_err(argv[k]); std_err("\n"); fflush(stdout); exit(1); } k++; } /* Process offset, if any. */ if (k < argc) { /* Offset present. */ off = offset(argc, argv, k); off = (off/16L) * 16L; lseek(0, off, 0); } dumpfile(); addrout(off); printf("\n"); fflush(stdout); exit(0); } long offset(argc, argv, k) int argc; char *argv[]; int k; { int dot, radix; char str[80], *p, c; long val; /* See if the offset is decimal. */ dot = 0; p = argv[k]; while (*p) if (*p++ == '.') dot = 1; /* Convert offset to binary. */ radix = (dot ? 10 : 8); val = 0; p = argv[k]; if (*p == '+') p++; while (*p != 0 && *p != '.') { c = *p++; if (c < '0' || c > '9') { printf("Bad character in offset: %c\n", c); fflush(stdout); exit(1); } val = radix * val + c - '0'; } p = argv[k+1]; if (k + 1 == argc - 1 && *p == 'b') val = 512L * val; return(val); } dumpfile() { int k; int *words; while ( (k = getwords(&words))) {/* 'k' is # bytes read */ if (k == 16 && same(words, prevwds) && ever==1) { if (state == 0) { printf("*\n"); state = 1; off += 16; continue; } else if (state == 1) { off += 16; continue; } } addrout(off); off += k; state = 0; ever = 1; linenr = 1; if (oflag) wdump(words, k, 8); if (dflag) wdump(words, k, 10); if (xflag) wdump(words, k, 16); if (cflag) bdump(words, k, 'c'); if (bflag) bdump(words, k, 'b'); for (k = 0; k < 8; k++) prevwds[k] = words[k]; for (k = 0; k < 8; k++) words[k] = 0; } } wdump(words, k, radix) int words[8], k, radix; { int i; if (linenr++ != 1) printf(" "); for (i = 0; i < (k+1)/2; i++) outword(words[i], radix); printf("\n"); } bdump(bytes, k, c) char bytes[16]; int k; char c; { int i; if (linenr++ != 1) printf(" "); for (i = 0; i < k; i++) byte(bytes[i] & 0377, c); printf("\n"); } byte(val, c) int val; char c; { if (c == 'b') { printf(" "); outnum(val, 7); return; } if (val == 0) printf(" \\0"); else if (val == '\b') printf(" \\b"); else if (val == '\f') printf(" \\f"); else if (val == '\n') printf(" \\n"); else if (val == '\r') printf(" \\r"); else if (val == '\t') printf(" \\t"); else if (val >= ' ' && val < 0177) printf(" %c",val); else {printf(" "); outnum(val, 7);} } int getwords(words) int **words; { int count; if (next >= bytespresent) { bytespresent = read(0, buf, 512); next = 0; } if (next >= bytespresent) return(0); *words = (int *) &buf[next]; if (next + 16 <= bytespresent) count = 16; else count = bytespresent - next; next += count; return(count); } int same(w1, w2) int *w1, *w2; { int i; i = 8; while (i--) if (*w1++ != *w2++) return(0); return(1); } outword(val, radix) int val, radix; { /* Output 'val' in 'radix' in a field of total size 'width'. */ int i; if (radix == 16) i = width - 4; if (radix == 10) i = width - 5; if (radix == 8) i = width - 6; if (i == 1) printf(" "); else if (i == 2) printf(" "); else if (i == 3) printf(" "); else if (i == 4) printf(" "); outnum(val, radix); } outnum(num, radix) int num, radix; { /* Output a number with all leading 0s present. Octal is 6 places, * decimal is 5 places, hex is 4 places. */ int d, i; unsigned val; char s[8]; val = (unsigned) num; if (radix == 8) d = 6; else if (radix == 10) d = 5; else if (radix == 16) d = 4; else if (radix == 7) {d = 3; radix = 8;} for (i = 0; i < d; i++) { s[i] = val % radix; val -= s[i]; val = val/radix; } for (i = d - 1 ; i >= 0; i--) { if (s[i] > 9) printf("%c",'a'+s[i]-10); else printf("%c",s[i]+'0'); } } addrout(l) long l; { int i; if (hflag == 0) { for (i = 0; i < 7; i++) printf("%c", ((l>>(18-3*i)) & 07) + '0'); } else { for (i = 0; i < 7; i++) printf("%c", hexit( ((l>>(24-4*i)) & 0x0F)) ); } } char hexit(k) int k; { if (k <= 9) return('0' + k); else return('A' + k - 10); } usage() { std_err("Usage: od [-bcdhox] [file] [ [+] offset [.] [b] ]"); } /* passwd - change a passwd Author: Adri Koppes */ #include "signal.h" #include "pwd.h" char pwd_file[] = "/etc/passwd"; char pw_tmp[] = "/etc/pwtemp"; char bad[] = "Permission denied\n"; char buf[512]; main (argc, argv) int argc; char *argv[]; { int uid, cn, n; int fpin, fpout; long salt; struct passwd *pwd, *getpwnam (), *getpwuid (), *getpwent (); char name[9], password[14], sl[2]; char *getpass (), *crypt (); uid = getuid (); if (!access (pw_tmp, 0)) { std_err("Temporary file in use.\nTry again later\n"); exit (1); } if (argc < 2) { pwd = getpwuid (uid); strcpy (name, pwd->pw_name); } else { strcpy (name, argv[1]); pwd = getpwnam (name); } if (!pwd || ((uid != pwd->pw_uid) && uid)) { std_err(bad); exit (1); } signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGTERM, SIG_IGN); prints("Changing password for %s\n",name); if (pwd->pw_passwd[0] && uid) if (strcmp (pwd->pw_passwd, crypt (getpass ("Old password: "), pwd->pw_passwd))) { std_err(bad); exit (1); } strcpy (password, getpass ("New password: ")); if (password[0] == '\0') { std_err("password cannot be null\n"); exit(1); } if (strcmp (password, getpass ("Retype password: "))) { std_err("Passwords don't match\n"); exit (1); } time (&salt); sl[0] = (salt & 077) + '.'; sl[1] = ((salt >> 6) & 077) + '.'; for (cn = 0; cn < 2; cn++) { if (sl[cn] > '9') sl[cn] += 7; if (sl[cn] > 'Z') sl[cn] += 6; } if (password[0]) strcpy (password, crypt (password, sl)); umask (0); close(1); fpout = creat(pw_tmp,0600); if (fpout != 1) { std_err("Can't create temporary file\n"); exit (1); } setpwent (); while ((pwd = getpwent ()) != 0) { if (!strcmp (name, pwd->pw_name)) pwd->pw_passwd = password; prints("%s:%s:%s:",pwd->pw_name,pwd->pw_passwd,itoa(pwd->pw_uid)); prints("%s:%s:%s:%s\n", itoa(pwd->pw_gid),pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell ); } endpwent (); close(0); if ((fpin = open (pw_tmp, 0)) != 0) { std_err("Can't reopen temporary file\n"); exit (1); } close (fpout); if ((fpout = open(pwd_file, 2)) < 0) { std_err("Can't recreate password file\n"); unlink (pw_tmp); exit (1); } while (1) { n = read(fpin, buf, 512); if (n <= 0) break; write(1, buf, n); } fclose (fpin); fclose (fpout); unlink (pw_tmp); } /* * Pr - print files * * Author: Michiel Huisjes. * * Usage: pr [+page] [-columns] [-h header] [-w with] [-l length] [-nt] [files] * -t : Do not print the 5 line header and trailer at the page. * -n : Turn on line numbering. * +page : Start printing at page n. * -columns : Print files in n-colums. * -l length: Take the length of the page to be n instead of 66 * -h header: Take next argument as page header. * -w with : Take the width of the page to be n instead of default 72 */ #include "stdio.h" char *colbuf; #define DEF_LENGTH 66 #define DEF_WIDTH 72 typedef char BOOL; #define FALSE 0 #define TRUE 1 #define NIL_PTR ((char *) 0) char *header; BOOL no_header; BOOL number; short columns; short cwidth; short start_page = 1; short width = DEF_WIDTH; short length = DEF_LENGTH; char output[1024]; FILE *fopen(); main(argc, argv) int argc; char *argv[]; { FILE *file; char *ptr; int index = 1; while (argc > index) { ptr = argv[index++]; if (*ptr == '+') { start_page = atoi(++ptr); continue; } if (*ptr != '-') { index--; break; } if (*++ptr >= '0' && *ptr <= '9') { columns = atoi(ptr); continue; } while (*ptr) switch (*ptr++) { case 't': no_header = TRUE; break; case 'n': number = TRUE; break; case 'h': header = argv[index++]; break; case 'w': width = atoi(ptr); *ptr = '\0'; break; case 'l': length = atoi(ptr); *ptr = '\0'; break; default: fprintf(stderr, "Usage: %s [+page] [-columns] [-h header] [-w] [-l] [-nt] [files]\n", argv[0]); exit(1); } } if (!no_header) length -= 10; if (length <= 0) length = DEF_LENGTH; if (columns) { cwidth = width / columns + 1; if (columns > width) { fprintf(stderr, "Too many columns for pagewidth.\n"); exit(1); } if ((colbuf = (char *) sbrk(cwidth * columns * length)) < 0) { fprintf(stderr, "No memory available for a page of %d x %d. Use chmem to allocate more.\n", length, cwidth); exit(1); } } setbuf(stdout, output); if (argc == index) { header = ""; print(stdin); } while (index != argc) { if ((file = fopen(argv[index], "r")) == (FILE *) 0) { fprintf(stderr, "Cannot open %s\n", argv[index++]); continue; } header = argv[index]; if (columns) format(file); else print(file); fclose(file); index++; } if (columns) { if (brk(colbuf) < 0) { fprintf(stderr, "Can't reset memory!\n"); exit(1); } } (void) fflush(stdout); exit(0); } char skip_page(lines, filep) int lines; FILE *filep; { short c; do { while ((c = getc(filep)) != '\n' && c != EOF); lines--; } while (lines && c != EOF); return c; } format(filep) FILE *filep; { short c = '\0'; short index, lines, i; short page_number = 0; short maxcol = columns; do { /* Check printing of page */ page_number++; if (page_number < start_page && c != EOF) { c = skip_page(columns * length, filep); continue; } if (c == EOF) return; lines = columns * length; index = 0; do { for (i = 0; i < cwidth - 1; i++) { if ((c = getc(filep)) == '\n' || c == EOF) break; colbuf[index++] = c; } /* First char is EOF */ if (i == 0 && lines == columns * length && c == EOF) return; while (c != '\n' && c != EOF) c = getc(filep); colbuf[index++] = '\0'; while (++i < cwidth) index++; lines--; if (c == EOF) { maxcol = columns - lines / length; while (lines--) for (i = 0; i < cwidth; i++) colbuf[index++] = '\0'; } } while (c != EOF && lines); print_page(colbuf, page_number, maxcol); } while (c != EOF); } print_page(buf, pagenr, maxcol) char buf[]; short pagenr, maxcol; { short linenr = (pagenr - 1) * length + 1; short pad, i, j, start; if (!no_header) out_header(pagenr); for (i = 0; i < length; i++) { if (number) printf("%d\t", linenr++); for (j = 0; j < maxcol; j++) { start = (i + j * length) * cwidth; for (pad = 0; pad < cwidth - 1 && buf[start + pad]; pad++) putchar (buf[start + pad]); if (j < maxcol - 1) /* Do not pad last column */ while (pad++ < cwidth - 1) putchar (' '); } putchar('\n'); } if (!no_header) printf("\n\n\n\n\n"); } print(filep) FILE *filep; { short c = '\0'; short page_number = 0; short linenr = 1; short lines; do { /* Check printing of page */ page_number++; if (page_number < start_page && c != EOF) { c = skip_page(length, filep); continue; } if (c == EOF) return; if (page_number == start_page) c = getc(filep); /* Print the page */ lines = length; if (!no_header) out_header(page_number); while (lines && c != EOF) { if (number) printf("%d\t", linenr++); while (c != '\n' && c != EOF) { putchar(c); c = getc(filep); } putchar('\n'); lines--; c = getc(filep); } if (lines == length) return; if (!no_header) printf("\n\n\n\n\n"); /* End of file */ } while (c != EOF); /* Fill last page */ if (page_number >= start_page) { while (lines--) putchar('\n'); } } out_header(page) short page; { extern long time(); long t; (void) time (&t); print_time (t); printf(" %s Page %d\n\n\n", header, page); } #define MINUTE 60L #define HOUR (60L * MINUTE) #define DAY (24L * HOUR) #define YEAR (365L * DAY) #define LYEAR (366L * DAY) int mo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; char *moname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* Print the date. This only works from 1970 to 2099. */ print_time(t) long t; { int i, year, day, month, hour, minute; long length, time(), original; year = 1970; original = t; while (t > 0) { length = (year % 4 == 0 ? LYEAR : YEAR); if (t < length) break; t -= length; year++; } /* Year has now been determined. Now the rest. */ day = (int) (t / DAY); t -= (long) day * DAY; hour = (int) (t / HOUR); t -= (long) hour * HOUR; minute = (int) (t / MINUTE); /* Determine the month and day of the month. */ mo[1] = (year % 4 == 0 ? 29 : 28); month = 0; i = 0; while (day >= mo[i]) { month++; day -= mo[i]; i++; } /* At this point, 'year', 'month', 'day', 'hour', 'minute' ok */ printf("\n\n%s %d %0d:%0d %d", moname[month], day + 1, hour + 1, minute, year); } /* printenv - print the current environment Author: Richard Todd */ main () { extern char **environ; char **sptr; for (sptr = environ ; *sptr ; ++sptr) { prints("%s\n",*sptr); } } /* pwd - print working directory Author: Adri Koppes */ #include "stat.h" struct direct { unsigned short d_ino; char d_name[14]; } main() { register int fd; register *n; char name[128]; char *last_index(); struct stat s, st; struct direct d; *name = 0; stat(".", &s); do { if ((fd = open("..",0)) < 0) { prints("Can't open ..\n"); exit(1); } st.st_dev = s.st_dev; st.st_ino = s.st_ino; st.st_mode = s.st_mode; st.st_nlink = s.st_nlink; st.st_uid = s.st_uid; st.st_gid = s.st_gid; st.st_rdev = s.st_rdev; st.st_size = s.st_size; st.st_atime = s.st_atime; st.st_mtime = s.st_mtime; st.st_ctime = s.st_ctime; stat("..", &s); chdir(".."); if (s.st_dev == st.st_dev) do if (read(fd, (char *)&d, sizeof(struct direct)) < sizeof(struct direct)) { prints("Can't read ..\n"); exit(1); } while(d.d_ino != st.st_ino); else do { if (read(fd, (char *)&d, sizeof(struct direct)) < sizeof(struct direct)) { prints("Can't read ..\n"); exit(1); } stat(d.d_name, &s); } while ((s.st_dev != st.st_dev) || (s.st_ino != st.st_ino)); close(fd); if (strcmp(".",d.d_name)) { strcat(name,"/"); strcat(name,d.d_name); } } while ((s.st_ino != st.st_ino) || (s.st_dev != st.st_dev)); if (!*name) prints("/"); else while (n = last_index(name, '/')) { prints(n); *n = 0; } prints(name); prints("\n"); exit(0); } char * last_index (string, ch) register char *string; register char ch; { register char *retval = 0; for (; *string; *string++) if (*string == ch) retval = string; return (retval); } /* rev - reverse an ASCII line Authors: Paul Polderman & Michiel Huisjes */ #include "blocksize.h" #ifndef NULL #define NULL 0 #endif #ifndef EOF #define EOF ((char) -1) #endif int fd; /* File descriptor from file currently being read */ main(argc, argv) int argc; char *argv[]; { register unsigned short i; if (argc == 1) { /* If no arguments given, take stdin as input */ fd = 0; rev(); exit(0); } for (i = 1; i < argc; i++) { /* Reverse each line in arguments */ if ((fd = open(argv[i], 0)) < 0) { std_err("Cannot open "); std_err(argv[i]); std_err("\n"); continue; } rev(); close(fd); } exit(0); } rev() { char output[BLOCK_SIZE]; /* Contains a reversed line */ register unsigned short i; /* Index in output array */ do { i = BLOCK_SIZE - 1; while ((output[i] = nextchar()) != '\n' && output[i] != EOF) i--; write(1, &output[i + 1], BLOCK_SIZE - 1 - i); /* Write reversed line*/ if (output[i] == '\n') /* and write a '\n' */ write(1, "\n", 1); } while (output[i] != EOF); } char buf[BLOCK_SIZE]; nextchar() /* Does a sort of buffered I/O */ { static int n = 0; /* Read count */ static int i; /* Index in input buffer to next character */ if (--n <= 0) { /* We've had this block. Read in next block */ n = read(fd, buf, BLOCK_SIZE); i = 0; /* Reset index in array */ } return((n <= 0) ? EOF : buf[i++]); /* Return -1 on EOF */ } /* rm - remove files Author: Adri Koppes */ #include "stat.h" struct direct { unsigned short d_ino; char d_name[14]; }; int errors = 0; int fflag = 0; int iflag = 0; int rflag = 0; int exstatus; main (argc, argv) int argc; char *argv[]; { char *opt; if (argc < 2) usage (); *++argv; --argc; while (**argv == '-') { opt = *argv; while (*++opt != '\0') switch (*opt) { case 'f': fflag++; break; case 'i': iflag++; break; case 'r': rflag++; break; default: std_err("rm: unknown option\n"); usage (); break; } argc--; *++argv; } if (argc < 1) usage (); while (argc--) remove (*argv++); exstatus = (errors == 0 ? 0 : 1); if (fflag) exstatus = 0; exit(exstatus); } usage () { std_err ("Usage: rm [-fir] file\n"); exit (1); } remove (name) char *name; { struct stat s; struct direct d; char rname[128], *strcpy (), *strcat (); int fd; if (stat (name, &s)) { if (!fflag) stderr3 ("rm: ", name, " non-existent\n"); errors++; return; } if (iflag) { stderr3 ("rm: remove ", name, "? "); if (!confirm ()) return; } if ((s.st_mode & S_IFMT) == S_IFDIR) { if (rflag) { if ((fd = open (name, 0)) < 0) { if (!fflag) stderr3 ("rm: can't open ", name, "\n"); errors++; return; } while (read (fd, (char *) & d, sizeof (struct direct)) > 0) { if (d.d_ino && strcmp ("..", d.d_name) && strcmp (".", d.d_name)) { strcpy (rname, name); strcat (rname, "/"); strcat (rname, d.d_name); remove (rname); } } close(fd); rem_dir (name); } else { if (!fflag) stderr3 ("rm: ", name, " is a directory\n"); errors++; return; } } else { if (access (name, 2) && !fflag) { stderr3 ("rm: remove ", name, " (mode = "); octal(s.st_mode & 0777); std_err(") ? "); if (!confirm ()) return; } if (unlink (name)) { if (!fflag) stderr3 ("rm: ", name, " not removed\n"); errors++; } } } rem_dir (name) char *name; { int status; switch (fork ()) { case -1: std_err ("rm: can't fork\n"); errors++; return; case 0: execl ("/bin/rmdir", "rmdir", name, (char*) 0); execl ("/usr/bin/rmdir", "rmdir", name, (char*) 0); std_err ("rm: can't exec rmdir\n"); exit (1); default: wait (&status); errors += status; } } confirm () { char c, t; read (0, &c, 1); t = c; do read (0, &t, 1); while (t != '\n' && t != -1); return (c == 'y' || c == 'Y'); } octal(num) unsigned int num; { char a[4]; a[0] = (((num>>6) & 7) + '0'); a[1] = (((num>>3) & 7) + '0'); a[2] = ((num & 7) + '0'); a[3] = 0; std_err(a); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); } /* rmdir - remove a directory Author: Adri Koppes * (modified by Paul Polderman) */ #include "../include/signal.h" #include "../include/stat.h" struct direct { unsigned short d_ino; char d_name[14]; }; int error = 0; main (argc, argv) register int argc; register char **argv; { if (argc < 2) { prints ("Usage: rmdir dir ...\n"); exit (1); } signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGTERM, SIG_IGN); while (--argc) remove (*++argv); if (error) exit (1); } extern char *rindex(); remove (dirname) char *dirname; { struct direct d; struct stat s, cwd; register int fd = 0, sl = 0; char dots[128]; register char *p; if (stat (dirname, &s)) { stderr2(dirname, " doesn't exist\n"); error++; return; } if ((s.st_mode & S_IFMT) != S_IFDIR) { stderr2(dirname, " not a directory\n"); error++; return; } if (p = rindex(dirname, '/')) p++; else p = dirname; if (strcmp(p, ".") == 0 || strcmp(p, "..") == 0) { stderr2(dirname, " will not remove \".\" or \"..\"\n"); error++; return; } strcpy (dots, dirname); while (dirname[fd]) if (dirname[fd++] == '/') sl = fd; dots[sl] = '\0'; if (access (dots, 2)) { stderr2(dirname, " no permission\n"); error++; return; } stat ("", &cwd); if ((s.st_ino == cwd.st_ino) && (s.st_dev == cwd.st_dev)) { std_err ("rmdir: can't remove current directory\n"); error++; return; } if ((fd = open (dirname, 0)) < 0) { stderr2("can't read ", dirname); std_err("\n"); error++; return; } while (read (fd, (char *) & d, sizeof (struct direct)) == sizeof (struct direct)) if (d.d_ino != 0) if (strcmp (d.d_name, ".") && strcmp (d.d_name, "..")) { stderr2(dirname, " not empty\n"); close(fd); error++; return; } close (fd); strcpy (dots, dirname); strcat (dots, "/.."); patch_path(dots); for (p = dots; *p; p++) /* find end of dots */ ; unlink(dots); /* dirname/.. */ *(p - 1) = '\0'; unlink(dots); /* dirname/. */ *(p - 3) = '\0'; if (unlink(dots)) { /* dirname */ stderr2("can't remove ", dots); std_err("\n"); error++; return; } } stderr2(s1, s2) char *s1, *s2; { std_err("rmdir: "); std_err(s1); std_err(s2); } patch_path(dir) char *dir; /* pathname ending with "/.." */ { register char *p, *s; struct stat pst, st; if (stat(dir, &pst) < 0) return; p = dir; while (*p == '/') p++; while (1) { s = p; /* remember start of new pathname part */ while (*p && *p != '/') p++; /* find next slash */ if (*p == '\0') return; /* if end of pathname, return */ /* check if this part of pathname == the original pathname */ *p = '\0'; stat(dir, &st); if (st.st_ino == pst.st_ino && st.st_dev == pst.st_dev && strcmp(s, "..") == 0) return; /* if not, try next part */ *p++ = '/'; while (*p == '/') p++; } } /* roff - text justifier Author: George L. Sicherman */ /* * roff - C version. * the Colonel. 19 May 1983. * * Copyright 1983 by G. L. Sicherman. * You may use and alter this software freely for noncommercial ends * so long as you leave this message alone. * * Fix by Tim Maroney, 31 Dec 1984. * .hc implemented, 8 Feb 1985. * Fix to hyphenating with underlining, 12 Feb 1985. * Fixes to long-line hang and .bp by Dave Tutelman, 30 Mar 1985. * Fix to centering valve with long input lines, 4 May 1987. */ #include "sgtty.h" #include "signal.h" #include "stdio.h" #include "stat.h" #define SUFTAB "/usr/lib/suftab" #define TXTLEN (o_pl-o_m1-o_m2-o_m3-o_m4-2) #define IDTLEN (o_ti>=0?o_ti:o_in) #define MAXMAC 64 #define MAXDEPTH 10 #define MAXLENGTH 255 #define UNDERL '\200' char cumbuf[BUFSIZ]; char spacechars[] = " \t\n"; int sflag, hflag, startpage, stoppage; char holdword[MAXLENGTH], *holdp; char assyline[MAXLENGTH]; int assylen; char ehead[100], efoot[100], ohead[100], ofoot[100]; struct macrotype { char mname[3]; long int moff; } macro[MAXMAC]; int n_macros; int depth; int adjtoggle; int isrequest = 0; char o_tr[40][2]; /* OUTPUT TRANSLATION TABLE */ int o_cc = '.'; /* CONTROL CHARACTER */ int o_hc = -1; /* HYPHENATION CHARACTER */ int o_tc = ' '; /* TABULATION CHARACTER */ int o_in = 0; /* INDENT SIZE */ int o_ix = -1; /* NEXT INDENT SIZE */ int o_ta[20] = { 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 113, 121, 129, 137, 145, 153, 161}; int n_ta = 20; /* #TAB STOPS */ int o_ll = 65, o_ad = 1, o_po = 0, o_ls = 1, o_ig = 0, o_fi = 1; int o_pl = 66, o_ro = 0, o_hx = 0, o_bl = 0, o_sp = 0, o_sk = 0; int o_ce = 0, o_m1 = 2, o_m2 = 2, o_m3 = 1, o_m4 = 3, o_ul = 0; int o_li = 0, o_n1 = 0, o_n2 = 0, o_bp = -1, o_hy = 1; int o_ni = 1; /* LINE-NUMBER INDENT */ int o_nn = 0; /* #LINES TO SUPPRESS NUMBERING */ int o_ti = -1; /* TEMPORARY INDENT */ int page_no = -1; int line_no = 9999; int n_outwords; FILE *File, *Macread, *Macwrite; FILE *Save; long int teller[MAXDEPTH], ftell(); char *strcat(), *strcpy(), *strend(), *strhas(); char *sprintf(); char *request[] = { "ad","ar","bl","bp","br","cc","ce","de", "ds","ef","eh","fi","fo","hc","he","hx","hy","ig", "in","ix","li","ll","ls","m1","m2","m3","m4", "n1","n2","na","ne","nf","ni","nn","nx","of","oh", "pa","pl","po","ro","sk","sp","ss","ta","tc","ti", "tr","ul",0}; char *mktemp(), *mfilnam = "/tmp/rtmXXXXXX"; int c; /* LAST CHAR READ */ struct sgttyb tty; FILE *fopen(); main(argc,argv) int argc; char **argv; { if (!isatty(1)) setbuf(stdout, cumbuf); while (--argc) switch (**++argv) { case '+': startpage=atoi(++*argv); break; case '-': ++*argv; if (isdigit(**argv)) stoppage=atoi(*argv); else switch(**argv) { case 's': sflag++; break; case 'h': hflag++; break; default: bomb(); } break; default: argc++; goto endargs; } endargs: if (sflag) ioctl(0, TIOCGETP, &tty); mesg(0); /* BLOCK OUT MESSAGES */ assylen=0; assyline[0]='\0'; if (!argc) { File=stdin; readfile(); } else while (--argc) { File=fopen(*argv,"r"); if (NULL==File) { fprintf(stderr,"roff: cannot read %s\n",*argv); done(1); } readfile(); fclose(File); argv++; } writebreak(); endpage(); for (; o_sk; o_sk--) blankpage(); mesg(1); /* ALLOW MESSAGES */ done(0); } mesg(f) int f; { static int mode; struct stat cbuf; /* This routine is not needed. char *ttyname(); if (!isatty(1)) return; if (!f) { fstat(1,&cbuf); mode = cbuf.st_mode; chmod(ttyname(1),mode & ~022); } else chmod(ttyname(1),mode); * ------- end of mesg */ } readfile() { while (readline()) { if (isrequest) continue; if (o_ce || !o_fi) { if (assylen) writeline(0,1); else blankline(); if (o_ce) o_ce--; } } } readline() { int startline, doingword; isrequest = 0; startline = 1; doingword = 0; c=suck(); if (c == '\n') { o_sp = 1; writebreak(); goto out; } else if (isspace(c)) writebreak(); for (;;) { if (c==EOF) { if (doingword) bumpword(); break; } if (c!=o_cc && o_ig) { while (c!='\n' && c!=EOF) c=suck(); break; } if (isspace(c) && !doingword) { startline=0; switch (c) { case ' ': assyline[assylen++]=' '; break; case '\t': tabulate(); break; case '\n': goto out; } c = suck(); continue; } if (isspace(c) && doingword) { bumpword(); if (c=='\t') tabulate(); else if (assylen) assyline[assylen++]=' '; doingword=0; if (c=='\n') break; } if (!isspace(c)) { if (doingword) *holdp++ = o_ul? c|UNDERL: c; else if (startline && c==o_cc && !o_li) { isrequest=1; return readreq(); } else { doingword=1; holdp=holdword; *holdp++ = o_ul? c|UNDERL: c; } } startline=0; c = suck(); } out: if (o_ul) o_ul--; if (o_li) o_li--; return c!=EOF; } /* * bumpword - add word to current line. */ bumpword() { char *hc; *holdp = '\0'; /* * Tutelman's fix #1, modified by the Colonel. */ if (!o_fi || o_ce) goto giveup; /* * We use a while-loop in case of ridiculously long words with * multiple hyphenation indicators. */ if (assylen + reallen(holdword) > o_ll - IDTLEN) { if (!o_hy) writeline(o_ad,0); else while (assylen + reallen(holdword) > o_ll - IDTLEN) { /* * Try hyphenating it. */ if (o_hc && strhas(holdword,o_hc)) { /* * There are hyphenation marks. Use them! */ for (hc=strend(holdword); hc>=holdword; hc--) { if ((*hc&~UNDERL)!=o_hc) continue; *hc = '\0'; if (assylen + reallen(holdword) + 1 > o_ll - IDTLEN) { *hc = o_hc; continue; } /* * Yay - it fits! */ dehyph(holdword); strcpy(&assyline[assylen],holdword); strcat(assyline,"-"); assylen += strlen(holdword) + 1; strcpy(holdword,++hc); break; /* STOP LOOKING */ } /* for */ /* * It won't fit, or we've succeeded in breaking the word. */ writeline(o_ad,0); if (hcassylen+IDTLEN) { for (; assylen+IDTLEN0) o_bp=page_no+r; else if (s<0) o_bp=page_no-r; else o_bp=r; writebreak(); if (line_no) { endpage(); beginpage(); } break; case 4: /* br */ writebreak(); break; case 5: /* cc */ c=cread(&o_cc); break; case 6: /* ce */ /* * Fix to centering. Set counter _after_ breaking! --G.L.S. */ nread(&r); writebreak(); o_ce = r; break; case 7: /* de */ defmac(); break; case 8NPQRSTUVWXYZ[: /* ds */ o_ls=2; writebreak(); break; case 9: /* ef */ c=tread(efoot); break; case 10: /* eh */ c=tread(ehead); break; case 11: /* fi */ o_fi=1; writebreak(); break; case 12: /* fo */ c=tread(efoot); strcpy(ofoot,efoot); break; case 13: /* hc */ c=cread(&o_hc); break; case 14: /* he */ c=tread(ehead); strcpy(ohead,ehead); break; case 15: /* hx */ o_hx=1; break; case 16: /* hy */ nread(&o_hy); break; case 17: /* ig */ o_ig=1; break; case 18: /* in */ writebreak(); snset(&o_in); o_ix = -1; break; case 19: /* ix */ snset(&o_ix); if (!n_outwords) o_in=o_ix; break; case 20: /* li */ nread(&o_li); break; case 21: /* ll */ snset(&o_ll); break; case 22: /* ls */ snset(&o_ls); break; case 23: /* m1 */ nread(&o_m1); break; case 24: /* m2 */ nread(&o_m2); break; case 25: /* m3 */ nread(&o_m3); break; case 26: /* m4 */ nread(&o_m4); break; case 27: /* n1 */ o_n1=1; break; case 28: /* n2 */ nread(&o_n2); break; case 29: /* na */ o_ad=0; writebreak(); break; case 30: /* ne */ nread(&r); if (line_no+(r-1)*o_ls+1 > TXTLEN) { writebreak(); endpage(); beginpage(); } break; case 31: /* nf */ o_fi=0; writebreak(); break; case 32: /* ni */ snset(&o_ni); break; case 33: /* nn */ snset(&o_nn); break; case 34: /* nx */ do_nx(); c='\n'; /* SO WE DON'T FLUSH THE FIRST LINE */ break; case 35: /* of */ c=tread(ofoot); break; case 36: /* oh */ c=tread(ohead); break; case 38: /* pl */ snset(&o_pl); break; case 39: /* po */ snset(&o_po); break; case 40: /* ro */ o_ro=1; break; case 41: /* sk */ nread(&o_sk); break; case 42: /* sp */ nread(&o_sp); writebreak(); break; case 43: /* ss */ writebreak(); o_ls=1; break; case 44: /* ta */ do_ta(); break; case 45: /* tc */ c=cread(&o_tc); break; case 46: /* ti */ writebreak(); c=snread(&r,&s,0); if (s>0) o_ti=o_in+r; else if (s<0) o_ti=o_in-r; else o_ti=r; break; case 47: /* tr */ do_tr(); break; case 48: /* ul */ nread(&o_ul); break; } reqflsh: while (c!=EOF && c!='\n') c=suck(); return c!=EOF; } snset(par) int *par; { int r, s; c=snread(&r,&s,0); if (s>0) *par+=r; else if (s<0) *par-=r; else *par=r; } tread(s) char *s; { int leadbl; leadbl=0; for (;;) { c=suck(); if (c==' ' && !leadbl) continue; if (c==EOF || c=='\n') { *s = '\0'; return c; } *s++ = c; leadbl++; } } nread(i) int *i; { int f; f=0; *i=0; if (!skipsp()) for (;;) { c=suck(); if (c==EOF) break; if (isspace(c)) break; if (isdigit(c)) { f++; *i = *i*10 + c - '0'; } else break; } if (!f) *i=1; } int snread(i,s,sdef) int *i, *s, sdef; { int f; f = *i = *s = 0; for (;;) { c=suck(); if (c==EOF || c=='\n') break; if (isspace(c)) { if (f) break; else continue; } if (isdigit(c)) { f++; *i = *i*10 + c - '0'; } else if ((c=='+' || c=='-') && !f) { f++; *s = c=='+' ? 1 : -1; } else break; } while (c!=EOF && c!='\n') c=suck(); if (!f) { *i=1; *s=sdef; } return c; } int cread(k) int *k; { int u; *k = -1; for (;;) { u=suck(); if (u==EOF || u=='\n') return u; if (isspace(u)) continue; if (*k < 0) *k=u; } } defmac() { int i; char newmac[3], *nm; if (skipsp()) return; nm=newmac; if (!Macwrite) openmac(); *nm++ = suck(); c=suck(); if (c!=EOF && c!='\n' && c!=' ' && c!='\t') *nm++ = c; *nm = '\0'; /* KILL OLD DEFINITION IF ANY */ for (i=0; i q) { endpage(); beginpage(); } for (; o_bl; o_bl--) blankline(); } else if (o_sp) { if (o_sp + line_no > q) newpage(); else if (line_no) for (; o_sp; o_sp--) blankline(); } } blankline() { if (line_no >= TXTLEN) newpage(); if (o_n2) o_n2++; spit('\n'); line_no++; } writeline(adflag,flushflag) int adflag, flushflag; { int j, q; char lnstring[7]; for (j=assylen-1; j; j--) { if (assyline[j]==' ') assylen--; else break; } q = TXTLEN; if (line_no >= q) newpage(); for (j=0; j=0) o_in=o_ix; o_ix = o_ti = -1; } fillline() { int excess, j, s, inc, spaces; adjtoggle^=1; if (!(excess = o_ll - IDTLEN - assylen)) return; if (excess < 0) { fprintf(stderr,"roff: internal error #2 [%d]\n",excess); done(1); } for (j=2;; j++) { if (adjtoggle) { s=0; inc = 1; } else { s=assylen-1; inc = -1; } spaces=0; while (s>=0 && s0) s++; if (!--excess) return; } spaces=0; } s+=inc; } } } insrt(p) int p; { int i; for (i=assylen; i>p; i--) assyline[i]=assyline[i-1]; assylen++; } newpage() { if (page_no >= 0) endpage(); else page_no=1; for (; o_sk; o_sk--) blankpage(); beginpage(); } beginpage() { int i; if (sflag) waitawhile(); for (i=0; i l) m+=(o_ll-m)/2; else m+=l; n=titlen(++t,d,strlen(pst)); for (j=m; j=400) { strcat(pst,"cd"); i-=400; } while (i>=100) { strcat(pst,"c"); i-=100; } if (i>=90) { strcat(pst,"xc"); i-=90; } if (i>=50) { strcat(pst,"l"); i-=50; } if (i>=40) { strcat(pst,"xl"); i-=40; } while (i>=10) { strcat(pst,"x"); i-=10; } if (i>=9) { strcat(pst,"ix"); i-=9; } if (i>=5) { strcat(pst,"v"); i-=5; } if (i>=4) { strcat(pst,"iv"); i-=4; } while (i--) strcat(pst,"i"); } else sprintf(pst,"%d",page_no); return pst; } int titlen(t,c,k) char *t, c; int k; { int q; q=0; while (*t && *t!=c) q += *t++ == '%' ? k : 1; return q; } spits(s) char *s; { while (*s) spit(*s++); } spit(c) char c; { static int col_no, n_blanks; int ulflag; char *t; ulflag=c&UNDERL; c&=~UNDERL; for (t = (char *)o_tr; *t; t++) if (*t++==c) { /* * fix - last char translates to space. */ c = *t? *t: ' '; break; } if (page_no < startpage || (stoppage && page_no > stoppage)) return; if (c != ' ' && c != '\n' && n_blanks) { if (hflag && n_blanks>1) while (col_no/8 < (col_no+n_blanks)/8) { putc('\t',stdout); n_blanks-= 8 - (col_no & 07); col_no = 8 + col_no & ~07; } for (; n_blanks; n_blanks--) { putc(' ',stdout); col_no++; } } if (ulflag && isalnum(c)) fputs("_\b",stdout); if (c == ' ') n_blanks++; else { putc(c,stdout); col_no++; } if (c == '\n') { col_no=0; n_blanks=0; } } int suck() { for (;;) { c=getc(File); if (islegal(c)) return c; } } /* * strhas - does string have character? Allow UNDERL flag. */ char * strhas(p,c) char *p, c; { for (; *p; p++) if ((*p&~UNDERL)==c) return p; return NULL; } /* * strend - find NULL at end of string. */ char * strend(p) char *p; { while (*p++); return p; } /* * isspace, isalnum, isdigit, islegal - classify a character. * We could just as well use if it didn't vary from * one version of Unix to another. As it is, these routines * must be modified for weird character sets, like EBCDIC and * CDC Scientific. */ int isspace(c) int c; { char *s; for (s=spacechars; *s; s++) if (*s==c) return 1; return 0; } int isalnum(c) int c; { return (c>='A'&&c<='Z') || (c>='a'&&c<='z') || (c>='0'&&c<='9'); } int isdigit(c) int c; { return c>='0' && c<='9'; } int islegal(c) int c; { return c>=' ' && c<='~' || isspace(c) || c=='\n' || c==EOF; } bomb() { fprintf(stderr,"Usage: roff [+00] [-00] [-s] [-h] file ...\n"); done(1); } done(n) int n; { fflush(stdout); _cleanup(); exit(n); } mkdir bin 2>/dev/null for i in *.c do echo Making $i make f=`basename $i .c` done /* shar - make a shell archive Author: Michiel Husijes */ #include "blocksize.h" #define IO_SIZE (10 * BLOCK_SIZE) char input[IO_SIZE]; char output[IO_SIZE]; int index = 0; main(argc, argv) int argc; register char *argv[]; { register int i; int fd; for (i = 1; i < argc; i++) { if ((fd = open(argv[i], 0)) < 0) { write(2, "Cannot open ", 12); write(2, argv[i], strlen(argv[i])); write(2, ".\n", 2); } else { print("echo x - "); print(argv[i]); print("\ngres '^X' '' > "); print(argv[i]); print(" << '/'\n"); cat(fd); } } if (index) write(1, output, index); exit(0); } cat(fd) int fd; { static char *current, *last; register int r = 0; register char *cur_pos = current; putchar('X'); for (; ;) { if (cur_pos == last) { if ((r = read(fd, input, IO_SIZE)) <= 0) break; last = &input[r]; cur_pos = input; } putchar(*cur_pos); if (*cur_pos++ == '\n' && cur_pos != last) putchar('X'); } print("/\n"); (void) close(fd); current = cur_pos; } print(str) register char *str; { while (*str) putchar(*str++); } putchar(c) register char c; { output[index++] = c; if (index == IO_SIZE) { write(1, output, index); index = 0; } } /* size - tell size of an object file Author: Andy Tanenbaum */ #define HLONG 8 /* # longs in the header */ #define TEXT 2 #define DATA 3 #define BSS 4 #define CHMEM 6 #define MAGIC 0x0301 /* magic number for an object file */ #define SEPBIT 0x00200000 /* this bit is set for separate I/D */ int heading; /* set when heading printed */ int error; main(argc, argv) int argc; char *argv[]; { int i; if (argc == 1) { size("a.out"); exit(error); } for (i = 1; i < argc; i++) size(argv[i]); exit(error); } size(name) char *name; { int fd, separate; long head[HLONG], dynam, allmem; if ( (fd = open(name, 0)) < 0) { stderr3("size: can't open ", name, "\n"); return; } if (read(fd, head, sizeof(head)) != sizeof(head) ) { stderr3("size: ", name, ": header too short\n"); error = 1; close(fd); return; } if ( (head[0] & 0xFFFF) != MAGIC) { stderr3("size: ", name, " not an object file\n"); close(fd); return; } separate = (head[0] & SEPBIT ? 1 : 0); dynam = head[CHMEM] - head[TEXT] - head[DATA] - head[BSS]; if (separate) dynam += head[TEXT]; allmem = (separate ? head[CHMEM] + head[TEXT] : head[CHMEM]); if (heading++ == 0) prints(" text\t data\t bss\t stack\tmemory\n"); printf("%6D\t%6D\t%6D\t%6D\t%6D\t%s\n",head[TEXT], head[DATA], head[BSS], dynam, allmem, name); close(fd); } stderr3(s1, s2, s3) char *s1, *s2, *s3; { std_err(s1); std_err(s2); std_err(s3); error = 1; } /* sleep - suspend a process for x sec Author: Andy Tanenbaum */ main(argc, argv) int argc; char *argv[]; { register seconds; register char c; seconds = 0; if (argc != 2) { std_err("Usage: sleep time\n"); exit(1); } while (c = *(argv[1])++) { if (c < '0' || c > '9') { std_err("sleep: bad arg\n"); exit(1); } seconds = 10 * seconds + (c - '0'); } /* Now sleep. */ sleep(seconds); exit(0); } /* sort - sort a file of lines Author: Michiel Huisjes */ /* SYNOPSIS: * sort [-funbirdcmt'x'] [+beg_pos[opts] [-end_pos]] [-o outfile] [file] .. * * [opts] can be any of * -f : Fold upper case to lower. * -n : Sort to numeric value (optional decimal point) implies -b * -b : Skip leading blanks * -i : Ignore chars outside ASCII range (040 - 0176) * -r : Reverse the sense of comparisons. * -d : Sort to dictionary order. Only letters, digits, comma's and points * are compared. * If any of these flags are used in [opts], then they override all global * ordering for this field. * * I/O control flags are: * -u : Print uniq lines only once. * -c : Check if files are sorted in order. * -m : Merge already sorted files. * -o outfile : Name of output file. (Can be one of the input files). * Default is stdout. * - : Take stdin as input. * * Fields: * -t'x' : Field separating character is 'x' * +a.b : Start comparing at field 'a' with offset 'b'. A missing 'b' is * taken to be 0. * -a.b : Stop comparing at field 'a' with offset 'b'. A missing 'b' is * taken to be 0. * A missing -a.b means the rest of the line. */ #include "stat.h" #include "signal.h" #define OPEN_FILES 16 /* Nr of open files per process */ #define MEMORY_SIZE (20 * 1024) /* Total mem_size */ #define LINE_SIZE (1024 >> 1) /* Max length of a line */ #define IO_SIZE (2 * 1024) /* Size of buffered output */ #define STD_OUT 1 /* Fd of terminal */ /* Return status of functions */ #define OK 0 #define ERROR -1 #define NIL_PTR ((char *) 0) /* Compare return values */ #define LOWER -1 #define SAME 0 #define HIGHER 1 /* * Table definitions. */ #define DICT 0x001 /* Alpha, numeric, letters and . */ #define ASCII 0x002 /* All between ' ' and '~' */ #define BLANK 0x004 /* ' ' and '\t' */ #define DIGIT 0x008 /* 0-9 */ #define UPPER 0x010 /* A-Z */ typedef enum { /* Boolean types */ FALSE = 0, TRUE } BOOL; typedef struct { int fd; /* Fd of file */ char *buffer; /* Buffer for reads */ int read_chars; /* Nr of chars actually read in buffer*/ int cnt; /* Nr of chars taken out of buffer */ char *line; /* Contains line currently used */ } MERGE ; #define NIL_MERGE ((MERGE *) 0) MERGE merge_f[OPEN_FILES]; /* Merge structs */ int buf_size; /* Size of core available for each struct */ #define FIELDS_LIMIT 10 /* 1 global + 9 user */ #define GLOBAL 0 typedef struct { int beg_field, beg_pos; /* Begin field + offset */ int end_field, end_pos; /* End field + offset. ERROR == EOLN */ BOOL reverse; /* TRUE if rev. flag set on this field*/ BOOL blanks; BOOL dictionary; BOOL fold_case; BOOL ascii; BOOL numeric; } FIELD; /* Field declarations. A total of FILEDS_LIMIT is allowed */ FIELD fields[FIELDS_LIMIT]; int field_cnt; /* Nr of field actually assigned */ /* Various output control flags */ BOOL check = FALSE; BOOL only_merge = FALSE; BOOL uniq = FALSE; char *mem_top; /* Mem_top points to lowest pos of memory. */ char *cur_pos; /* First free position in mem */ char **line_table; /* Pointer to the internal line table */ BOOL in_core = TRUE; /* Set if input cannot all be sorted in core */ /* Place where temp_files should be made */ char temp_files[] = "/tmp/sort.XXXXX.XX"; char *output_file; /* Name of output file */ int out_fd; /* Fd to output file (could be STD_OUT) */ char out_buffer[IO_SIZE]; /* For buffered output */ char **argptr; /* Pointer to argv structure */ int args_offset; /* Nr of args spilled on options */ int args_limit; /* Nr of args given */ char separator; /* Char that separates fields */ int nr_of_files = 0; /* Nr_of_files to be merged */ int disabled; /* Nr of files done */ char USAGE[] = "Usage: sort [-funbirdcmt'x'] [+beg_pos [-end_pos]] [-o outfile] [file] .."; /* Forward declarations */ char *file_name (), *skip_fields (); MERGE *skip_lines (), *print (); extern char *msbrk (), *mbrk (); /* * Table of all chars. 0 means no special meaning. */ char table[256] = { /* '^@' to space */ 0, 0, 0, 0, 0, 0, 0, 0, 0, BLANK | DICT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* space to '0' */ BLANK | DICT | ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* '0' until '9' */ DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, DIGIT | DICT | ASCII, /* ASCII from ':' to '@' */ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* Upper case letters 'A' to 'Z' */ UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, UPPER | DICT | ASCII, /* ASCII from '[' to '`' */ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* Lower case letters from 'a' to 'z' */ DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, DICT | ASCII, /* ASCII from '{' to '~' */ ASCII, ASCII, ASCII, ASCII, /* Stuff from -1 to -177 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0