home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / GLEN / TSRSRC32.ZIP / DISABLE.PAS < prev    next >
Pascal/Delphi Source File  |  1991-11-22  |  17KB  |  514 lines

  1. {**************************************************************************
  2. *   DISABLE - Activates or deactivates TSRs.                              *
  3. *   Copyright (c) 1987,1991 Kim Kokkonen, TurboPower Software.            *
  4. *   May be freely distributed and used but not sold except by permission. *
  5. ***************************************************************************
  6. *   Version 2.3 5/4/87                                                    *
  7. *     first release. version number matches other TSR Utilities           *
  8. *   :                                                                     *
  9. *   long intervening history                                              *
  10. *   :                                                                     *
  11. *   Version 3.0 9/24/91                                                   *
  12. *     update for DOS 5                                                    *
  13. *     add Quiet option                                                    *
  14. *     add support for high memory                                         *
  15. *   Version 3.1 11/4/91                                                   *
  16. *     update for new WATCH detection method                               *
  17. *   Version 3.2 11/22/91                                                  *
  18. *     change method of accessing high memory                              *
  19. ***************************************************************************
  20. *   telephone: 719-260-6641, CompuServe: 76004,2611.                      *
  21. *   requires Turbo Pascal version 6 to compile.                           *
  22. ***************************************************************************}
  23.  
  24. {$R-,S-,I-,V-,B-,F-,A-,E-,N-,G-,X-}
  25. {$M 2048,0,655360}
  26.  
  27. program DisableTSR;
  28.   {-Deactivate and reactivate memory resident programs}
  29.   {-Leaving them in memory all the while}
  30.  
  31. uses
  32.   Dos,
  33.   MemU;
  34.  
  35. var
  36.   Blocks : BlockArray;
  37.   BlockMax : BlockType;
  38.   WatchPsp : Word;
  39.   CommandSeg : Word;
  40.   HiMemSeg : Word;
  41.   Changes : ChangeArray;
  42.   ChangeMax, ActualMax, PspHex, StartMCB : Word;
  43.   Action : (aDeactivate, aActivate, aCheckFor);
  44.   Override : Boolean;
  45.   Quiet : Boolean;
  46.   ShowHiMem : Boolean;
  47.   TsrName : PathStr;
  48.  
  49.   procedure Abort(msg : String; ErrorLevel : Byte);
  50.     {-Halt in case of error}
  51.   begin
  52.     WriteLn(msg);
  53.     Halt(ErrorLevel);
  54.   end;
  55.  
  56.   function ExecutableBlock(PspHex : Word) : Boolean;
  57.     {-Return true if psphex corresponds to an executable code block}
  58.   var
  59.     b : BlockType;
  60.   begin
  61.     for b := BlockMax downto 1 do
  62.       {Search back to find executable rather than environment block}
  63.       if Blocks[b].psp = PspHex then begin
  64.         ExecutableBlock := True;
  65.         Exit;
  66.       end;
  67.     ExecutableBlock := False;
  68.   end;
  69.  
  70.   procedure InitChangeArray(WatchPsp : Word);
  71.     {-Initialize information regarding the WATCH data block}
  72.   var
  73.     watchindex : Word;
  74.     p : ^ChangeBlock;
  75.   begin
  76.     {Maximum offset in WATCH data area}
  77.     ActualMax := MemW[WatchPsp:NextChange];
  78.  
  79.     {Transfer changes from WATCH into a buffer array}
  80.     watchindex := 0;
  81.     ChangeMax := 0;
  82.     while watchindex < ActualMax do begin
  83.       p := Ptr(WatchPsp, ChangeVectors+watchindex);
  84.       Move(p^, Changes[ChangeMax], SizeOf(ChangeBlock));
  85.       Inc(watchindex, SizeOf(ChangeBlock));
  86.       if watchindex < ActualMax then
  87.         inc(ChangeMax);
  88.     end;
  89.   end;
  90.  
  91.   procedure PutWatch(chg : ChangeBlock; var watchindex : Word);
  92.     {-Put a change block back into WATCH}
  93.   var
  94.     p : ^ChangeBlock;
  95.   begin
  96.     p := Ptr(WatchPsp, ChangeVectors+watchindex);
  97.     Move(chg, p^, SizeOf(ChangeBlock));
  98.     Inc(watchindex, SizeOf(ChangeBlock));
  99.   end;
  100.  
  101.   procedure ActivateTSR(PspHex : Word);
  102.     {-Patch out the active interrupt vectors of a specified TSR}
  103.   var
  104.     nextchg, chg, watchindex : Word;
  105.     checking, didsomething : Boolean;
  106.   begin
  107.     didsomething := False;
  108.     watchindex := 0;
  109.     chg := 0;
  110.  
  111.     {Scan looking for the specified PSP}
  112.     while chg <= ChangeMax do begin
  113.       with Changes[chg] do
  114.         case ID of
  115.  
  116.           $FF :               {This record starts a new PSP}
  117.             begin
  118.               checking := (PspAdd = PspHex);
  119.               nextchg := Succ(chg);
  120.               if checking then
  121.                 {Turn off interrupts}
  122.                 inline($FA)
  123.               else
  124.                 {Turn on interrupts}
  125.                 inline($FB);
  126.             end;
  127.  
  128.           $01 :               {This record has an inactive vector redefinition}
  129.             if checking then begin
  130.               {We're in the proper PSP}
  131.               didsomething := True;
  132.               {Change the ID to indicate that vector is active}
  133.               ID := 0;
  134.               {Put the original vector code back in place}
  135.               nextchg := Succ(chg);
  136.               if (Changes[nextchg].ID <> 2) or (Changes[nextchg].VecNum <> VecNum) then
  137.                 Abort('Program error in Activate, patch record not found', 255);
  138.               {Restore the patched over code}
  139.               Move(Changes[nextchg].SaveCode, Mem[VecSeg:VecOfs], 6);
  140.               {Don't output the following patch record}
  141.               inc(nextchg);
  142.             end else
  143.               nextchg := Succ(chg);
  144.  
  145.         else
  146.           nextchg := Succ(chg);
  147.         end;
  148.  
  149.       {Put the change block back into WATCH}
  150.       PutWatch(Changes[chg], watchindex);
  151.       {Advance to the next change record}
  152.       chg := nextchg;
  153.     end;
  154.  
  155.     {Store the count back into WATCH}
  156.     MemW[WatchPsp:NextChange] := watchindex;
  157.  
  158.     if not(didsomething) then
  159.       Abort('No changes were needed to activate '+HexW(PspHex), 1);
  160.  
  161.   end;
  162.  
  163.   procedure DeactivateTSR(PspHex : Word);
  164.     {-Patch out the active interrupt vectors of a specified TSR}
  165.   var
  166.     newchange : ChangeBlock;
  167.     chg, watchindex, curpsp : Word;
  168.     putrec, checking, didsomething : Boolean;
  169.  
  170.     procedure PutPatch(vecn : Byte; vecs, veco, curpsp : Word);
  171.       {-Patch vector entry point with JMP to previous controlling vector}
  172.     label
  173.       ExitPoint;
  174.     var
  175.       vec : ^Word;
  176.       chg : Word;
  177.     begin
  178.       {Get the original vector from WATCH}
  179.       Move(Mem[WatchPsp:(OrigVectors+(vecn shl 2))], vec, 4);
  180.  
  181.       {Scan the Changes array to look for redefinition of this vector}
  182.       for chg := 0 to ChangeMax do begin
  183.         with Changes[chg] do
  184.           case ID of
  185.             0, 1 :            {This is or was a redefined vector}
  186.               if vecn = VecNum then
  187.                 {It's the vector we're interested in}
  188.                 {Store the latest value of the vector}
  189.                 Move(VecOfs, vec, 4);
  190.             $FF :             {This record starts a new PSP}
  191.               if PspAdd = curpsp then
  192.                 {Stop when we get to the PSP that is being disabled}
  193.                 goto ExitPoint;
  194.           end;
  195.       end;
  196. ExitPoint:
  197.       {Patch the vector entry point into a JMP FAR vec}
  198.       Mem[vecs:veco] := $EA;
  199.       Move(vec, Mem[vecs:Succ(veco)], 4);
  200.     end;
  201.  
  202.     function CountVecs(chg : Word) : Word;
  203.       {-Return count of vectors taken over by the PSP starting at changeblock chg}
  204.     var
  205.       count : Word;
  206.       ID : Byte;
  207.     begin
  208.       count := 0;
  209.       repeat
  210.         {Skip over the first one, which defines the current PSP}
  211.         inc(chg);
  212.         ID := Changes[chg].ID;
  213.         if (ID = 0) and (chg <= ChangeMax) then
  214.           inc(count);
  215.       until (ID = $FF) or (chg >= ChangeMax);
  216.       CountVecs := count;
  217.     end;
  218.  
  219.     function ValidToPatch(chg : Word) : Boolean;
  220.       {-Assure that there is space to place 6-byte patches}
  221.     var
  222.       First : Word;
  223.       Next : Word;
  224.       I : Word;
  225.       J : Word;
  226.       IAddr : LongInt;
  227.       JAddr : LongInt;
  228.     begin
  229.       ValidToPatch := True;
  230.       if Override then
  231.         Exit;
  232.  
  233.       {First vector to patch}
  234.       First := chg+1;
  235.  
  236.       {Last vector to patch}
  237.       Next := First;
  238.       while (Next <= ChangeMax) and (Changes[Next].ID <> $FF) do
  239.         inc(Next);
  240.  
  241.       {Any to patch?}
  242.       if Next = First then
  243.         Exit;
  244.  
  245.       {Compare each pair to assure enough space for patch}
  246.       for I := First to Next-1 do begin
  247.         with Changes[I] do
  248.           IAddr := (LongInt(VecSeg) shl 4)+VecOfs;
  249.         for J := First to Next-1 do
  250.           if I <> J then begin
  251.             with Changes[J] do
  252.               JAddr := (LongInt(VecSeg) shl 4)+VecOfs;
  253.             if Abs(IAddr-JAddr) < 6 then begin
  254.               ValidToPatch := False;
  255.               Exit;
  256.             end;
  257.           end;
  258.       end;
  259.     end;
  260.  
  261.   begin
  262.  
  263.     {Scan looking for the specified PSP}
  264.     didsomething := False;
  265.     watchindex := 0;
  266.  
  267.     for chg := 0 to ChangeMax do begin
  268.       putrec := True;
  269.       with Changes[chg] do
  270.         case ID of
  271.  
  272.           $FF :               {This record starts a new PSP}
  273.             begin
  274.               checking := (PspAdd = PspHex);
  275.               if checking then begin
  276.                 {Store the current PSP}
  277.                 curpsp := PspAdd;
  278.                 {Make sure WATCH has room for the extra changes}
  279.                 if watchindex+(CountVecs(chg)*SizeOf(ChangeBlock)) >
  280.                 MaxChanges*SizeOf(ChangeBlock) then
  281.                   Abort('Insufficient space in WATCH data area', 255);
  282.                 {Make sure the patches will be valid}
  283.                 if not ValidToPatch(chg) then
  284.                   Abort('Insufficient space between vectors to patch TSR', 255);
  285.                 {Turn off interrupts}
  286.                 inline($FA);
  287.               end else
  288.                 {Turn on interrupts}
  289.                 inline($FB);
  290.             end;
  291.  
  292.           $00 :               {This record has an active vector redefinition}
  293.             if checking then begin
  294.               {We're in the proper PSP}
  295.               didsomething := True;
  296.  
  297.               {Change the ID to indicate that vector is inactive}
  298.               ID := 1;
  299.               {Output the record now so that the new record can immediately follow}
  300.               PutWatch(Changes[chg], watchindex);
  301.               putrec := False;
  302.  
  303.               {Output a new change record so we can reactivate later}
  304.               {Indicate this is a patch record}
  305.               newchange.ID := 2;
  306.               {Save which vector it goes with}
  307.               newchange.VecNum := VecNum;
  308.               {Save the code we'll patch over}
  309.               Move(Mem[VecSeg:VecOfs], newchange.SaveCode, 6);
  310.               {Output the record to the WATCH area}
  311.               PutWatch(newchange, watchindex);
  312.               {Patch in a JMP to the previous vector}
  313.               PutPatch(VecNum, VecSeg, VecOfs, curpsp);
  314.             end;
  315.  
  316.         end;
  317.       if putrec then
  318.         {Put the change block back into WATCH}
  319.         PutWatch(Changes[chg], watchindex);
  320.     end;
  321.  
  322.     {Store the count back into WATCH}
  323.     MemW[WatchPsp:NextChange] := watchindex;
  324.  
  325.     if not(didsomething) then
  326.       Abort('No changes were needed to deactivate '+tsrname, 1);
  327.  
  328.   end;
  329.  
  330.   procedure CheckUpperOption;
  331.     {-Set ShowHiMem option}
  332.   var
  333.     arg : String[127];
  334.     i : Word;
  335.   begin
  336.     ShowHiMem := False;
  337.     for I := 1 to ParamCount do begin
  338.       arg := StUpcase(ParamStr(i));
  339.       if (arg = '-U') or (arg = '/U') then begin
  340.         ShowHiMem := True;
  341.         Exit;
  342.       end;
  343.     end;
  344.   end;
  345.  
  346.   procedure GetOptions;
  347.     {-Analyze command line for options}
  348.   var
  349.     arg : String[127];
  350.     arglen : Byte absolute arg;
  351.     i, code : Word;
  352.  
  353.     procedure WriteCopyright;
  354.     begin
  355.       WriteLn('DISABLE ', Version, ', Copyright 1991 TurboPower Software');
  356.     end;
  357.  
  358.     procedure WriteHelp;
  359.       {-Show the options}
  360.     begin
  361.       WriteCopyright;
  362.       WriteLn;
  363.       WriteLn('DISABLE allows you to selectively disable and reenable a TSR while leaving it');
  364.       WriteLn('in memory. To run DISABLE, you must have previously installed the TSR utility');
  365.       WriteLn('WATCH.');
  366.       WriteLn;
  367.       WriteLn('DISABLE is command-line driven. You specify a single TSR by its name (if you');
  368.       WriteLn('are running DOS 3.0 or later) or by its address as determined from a MAPMEM');
  369.       WriteLn('report. Addresses must be preceded by a dollar sign "$" and specified in hex.');
  370.       WriteLn;
  371.       WriteLn('DISABLE accepts the following command line syntax:');
  372.       WriteLn;
  373.       WriteLn('  DISABLE TSRname|$PSPaddress [Options]');
  374.       WriteLn;
  375.       WriteLn('Options may be preceded by either / or -. Valid options are as follows:');
  376.       WriteLn;
  377.       WriteLn('     /A     reactivate the specified TSR.');
  378.       WriteLn('     /C     check whether TSR is installed.');
  379.       WriteLn('     /O     disable the TSR even if dangerous (Override).');
  380.       WriteLn('     /Q     write no screen output.');
  381.       WriteLn('     /U     work with upper memory blocks.');
  382.       WriteLn('     /?     write this help screen.');
  383.       Halt(1);
  384.     end;
  385.  
  386.     function FindOwner(name : String) : Word;
  387.       {-Return segment of executable block with specified name}
  388.     var
  389.       b : BlockType;
  390.     begin
  391.       name := StUpcase(name);
  392.       {Scan the blocks in reverse order}
  393.       for b := BlockMax downto 1 do
  394.         with Blocks[b] do
  395.           if Succ(mcb) = psp then
  396.             {This block is an executable block}
  397.             if NameFromEnv(Ptr(mcb, 0)) = name then begin
  398.               {Found it}
  399.               FindOwner := psp;
  400.               Exit;
  401.             end else if DosV >= 5 then
  402.               if NameFromMcb(Ptr(Mcb, 0)) = name then begin
  403.                 {Found it}
  404.                 FindOwner := psp;
  405.                 Exit;
  406.               end;
  407.       FindOwner := $FFFF;
  408.     end;
  409.  
  410.   begin
  411.     {Initialize defaults}
  412.     PspHex := 0;
  413.     Action := aDeactivate;
  414.     Override := False;
  415.     Quiet := False;
  416.  
  417.     i := 1;
  418.     while i <= ParamCount do begin
  419.       arg := ParamStr(i);
  420.       if (arg[1] = '?') then
  421.         WriteHelp
  422.       else if (arg[1] = '-') or (arg[1] = '/') then
  423.         case arglen of
  424.           1 : Abort('Missing command option following '+arg, 254);
  425.           2 : case UpCase(arg[2]) of
  426.                 '?' : WriteHelp;
  427.                 'A' : Action := aActivate;
  428.                 'C' : Action := aCheckFor;
  429.                 'E' : Action := aActivate;
  430.                 'O' : Override := True;
  431.                 'Q' : Quiet := True;
  432.                 'U' : ; {ignore, but allow, here}
  433.               else
  434.                 Abort('Unknown command option: '+arg, 254);
  435.               end;
  436.         else
  437.           Abort('Unknown command option: '+arg, 254);
  438.         end
  439.       else begin
  440.         {TSR to change}
  441.         if arg[1] = '$' then begin
  442.           {Treat as hex address}
  443.           Val(arg, PspHex, code);
  444.           if code <> 0 then
  445.             Abort('Invalid hex address specification: '+arg, 254);
  446.         end else if DosV >= 3 then
  447.           {Treat as PSP owner name - scan to find proper PSP}
  448.           PspHex := FindOwner(arg)
  449.         else
  450.           Abort('Must have DOS 3.0+ to find TSRs by name', 254);
  451.         TsrName := StUpcase(arg);
  452.       end;
  453.       inc(i);
  454.     end;
  455.  
  456.     if not Quiet then
  457.       WriteCopyright;
  458.     if PspHex = 0 then
  459.       Abort('No TSR name or address specified', 254)
  460.     else if PspHex = $FFFF then
  461.       Abort('No such TSR found', 2);
  462.   end;
  463.  
  464. begin
  465.   {Determine whether upper memory control is desired}
  466.   CheckUpperOption;
  467.  
  468.   {Initialize for high memory access}
  469.   if ShowHiMem then begin
  470.     HiMemSeg := FindHiMemStart;
  471.     if HiMemSeg = 0 then
  472.       Abort('No upper memory blocks found', 255);
  473.   end else
  474.     HiMemSeg := 0;
  475.  
  476.   {Get all allocated memory blocks in normal memory}
  477.   {Must do first to support TSRs by name in GetOptions}
  478.   FindTheBlocks(HiMemSeg, Blocks, BlockMax, StartMcb, CommandSeg);
  479.  
  480.   {Analyze command line for options}
  481.   GetOptions;
  482.  
  483.   {Find the watch block}
  484.   WatchPsp := WatchPspSeg;
  485.   if WatchPsp = 0 then
  486.     Abort('WATCH must be installed in order to use DISABLE', 255);
  487.  
  488.   {Assure PspHex corresponds to an executable block}
  489.   if not ExecutableBlock(PspHex) then
  490.     Abort('No such TSR found', 2);
  491.  
  492.   {Initialize information regarding the WATCH data block}
  493.   InitChangeArray(WatchPsp);
  494.  
  495.   {Activate or deactivate the TSR}
  496.   case Action of
  497.     aDeactivate:DeactivateTSR(PspHex);
  498.     aActivate:ActivateTSR(PspHex);
  499.   end;
  500.  
  501.   {Write success message}
  502.   if not Quiet then begin
  503.     case Action of
  504.       aDeactivate:Write('Deactivated');
  505.       aActivate:Write('Activated');
  506.       aCheckFor:Write('Found');
  507.     end;
  508.     Write(' ');
  509.     if TsrName[1] = '$' then
  510.       Write('TSR at ');
  511.     WriteLn(TsrName);
  512.   end;
  513. end.
  514.