home *** CD-ROM | disk | FTP | other *** search
- {**************************************************************************
- * MARKNET - stores system information in a file for later restoration. *
- * Copyright (c) 1986,1989 Kim Kokkonen, TurboPower Software. *
- * May be distributed freely, but not for a profit except with written *
- * permission from TurboPower Software. *
- ***************************************************************************
- * Version 2.7 3/4/89 *
- * first public release *
- * (based on FMARK 2.6) *
- * Version 2.8 3/10/89 *
- * store the DOS environment *
- * store information about the async ports *
- * Version 2.9 5/4/89 *
- * for consistency *
- ***************************************************************************
- * Telephone: 408-438-8608, CompuServe: 72457,2131. *
- * Requires Turbo version 5 to compile. *
- ***************************************************************************}
-
- {$R-,S-,I-}
- {.$DEFINE Debug} {Activate for status messages}
-
- program MarkNet;
-
- uses
- Dos;
-
- const
- Version = '2.9';
- NmarkID = 'MN2.9 TSR'; {Marking string for TSR file mark}
- NetMarkID = 'MN29'; {ID at start of net mark file}
-
- NmarkOffset = $60; {Where NmarkID is found in MARKNET TSR}
-
- MaxHandles = 32; {Max number of EMS allocation blocks supported}
- EMSinterrupt = $67; {The vector used by the expanded memory manager}
-
- MarkFOpen : Boolean = False; {True while mark file is open}
-
- Digits : array[0..$F] of Char = '0123456789ABCDEF';
-
- RBR = 0; {Receiver buffer register offset}
- THR = 0; {Transmitter buffer register offset}
- BRL = 0; {Baud rate low}
- BRH = 1; {Baud rate high}
- IER = 1; {Interrupt enable register}
- IIR = 2; {Interrupt identification register}
- LCR = 3; {Line control register}
- MCR = 4; {Modem control register}
- LSR = 5; {Line status register}
- MSR = 6; {Modem status register}
-
- type
- DeviceHeader =
- record
- NextHeaderOffset : Word; {Offset address of next device in chain}
- NextHeaderSegment : Word; {Segment address of next device in chain}
- Attributes : Word; {Device attributes}
- StrategyEntPt : Word; {Offset in current segment - strategy}
- InterruptEntPt : Word; {Offset in current segment - interrupt}
- DeviceName : array[1..8] of Char; {Name of the device}
- end;
-
- SO =
- record
- O, S : Word;
- end;
-
- FileRec =
- record
- OpenCnt : Word;
- OpenMode : Word;
- Attribute : Byte;
- Unknown1 : Word;
- DCB : Pointer;
- InitCluster : Word;
- Time : Word;
- Date : Word;
- Size : LongInt;
- Pos : LongInt;
- BeginCluster : Word;
- CurCluster : Word;
- Block : Word;
- Unknown2 : Byte; {Varies with DOS version below here}
- Name : array[0..7] of Char;
- Ext : array[0..2] of Char;
- Unknown3 : array[0..5] of Byte;
- Owner : Word;
- Unknown4 : Word;
- end;
-
- SftRecPtr = ^SftRec;
- SftRec =
- record
- Next : SftRecPtr;
- Count : Word;
- Files : array[1..255] of FileRec;
- end;
-
- DosRec =
- record
- McbSeg : Word;
- FirstDPB : Pointer;
- FirstSFT : SftRecPtr;
- ClockDriver : Pointer;
- ConDriver : Pointer;
- MaxBlockBytes : Word;
- CachePtr : Pointer;
- DriveTable : Pointer;
- Unknown2 : Pointer;
- Unknown3 : Word;
- BlockDevices : Byte;
- LastDrive : Byte;
- NullDevice : DeviceHeader;
- end;
-
- HandlePageRecord =
- record
- Handle : Word;
- NumPages : Word;
- end;
-
- PageArray = array[1..MaxHandles] of HandlePageRecord;
- PageArrayPtr = ^PageArray;
-
- var
- MarkName : String[79]; {Name of mark file}
-
- Regs : Registers; {Machine registers for MS-DOS calls}
- DevicePtr : ^DeviceHeader; {Pointer to the next device header}
- DeviceSegment : Word; {Current device segment}
- DeviceOffset : Word; {Current device offset}
- MarkF : file; {Dump file}
- DosPtr : ^DosRec; {Pointer to internal DOS table}
- DosTableSize : Word; {Bytes saved in DOS table}
- CommandSeg : Word; {PSP segment of primary COMMAND.COM}
- CommandPsp : array[1..$100] of Byte;
- FileTableA : array[1..5] of SftRecPtr;
- FileTableCnt : Word;
- FileRecSize : Word;
- EmsHandles : Word;
- EmsPages : PageArrayPtr;
-
- SaveExit : Pointer;
-
- {$F+}
- procedure ExitHandler;
- begin
- ExitProc := SaveExit;
- if MarkFOpen then begin
- Close(MarkF);
- if IoResult = 0 then
- Erase(MarkF);
- end;
- {Turbo will swap back, so undo what we've done already}
- SwapVectors;
- end;
- {$F-}
-
- procedure Abort(Msg : String);
- {-Halt in case of error}
- begin
- WriteLn(Msg);
- Halt(255);
- end;
-
- function HexW(W : Word) : string;
- {-Return hex string for word}
- begin
- HexW[0] := #4;
- HexW[1] := Digits[hi(W) shr 4];
- HexW[2] := Digits[hi(W) and $F];
- HexW[3] := Digits[lo(W) shr 4];
- HexW[4] := Digits[lo(W) and $F];
- end;
-
- function HexPtr(P : Pointer) : string;
- {-Return hex string for pointer}
- begin
- HexPtr := HexW(SO(P).S)+':'+HexW(SO(P).O);
- end;
-
- function StUpcase(S : String) : string;
- {-Return uppercase for string}
- var
- I : Integer;
- begin
- for I := 1 to Length(S) do
- S[I] := Upcase(S[I]);
- StUpcase := S;
- end;
-
- procedure GetDosPtr;
- {-Return pointer to DOS internal variables table}
- begin
- with Regs do begin
- AH := $52;
- MsDos(Regs);
- Dec(BX, 2);
- DosPtr := Ptr(ES, BX);
- end;
- end;
-
- procedure FindDevChain;
- {-Return segment, offset and pointer to NUL device}
- begin
- GetDosPtr;
- DevicePtr := @DosPtr^.NullDevice;
- DeviceSegment := SO(DevicePtr).S;
- DeviceOffset := SO(DevicePtr).O;
- end;
-
- procedure CheckWriteError;
- {-Check for errors writing to mark file}
- begin
- if IoResult = 0 then
- Exit;
- Abort('Error writing to '+MarkName);
- end;
-
- function EMSpresent : Boolean;
- {-Return true if EMS memory manager is present}
- var
- F : file;
- begin
- {"file handle" defined by the expanded memory manager at installation}
- Assign(F, 'EMMXXXX0');
- Reset(F);
- if IoResult = 0 then begin
- EMSpresent := True;
- Close(F);
- end else
- EMSpresent := False;
- end;
-
- procedure EMSpageMap(var PageMap : PageArray; var EmsHandles : Word);
- {-Return an array of the allocated EMS memory blocks}
- begin
- Regs.AH := $4D;
- Regs.ES := Seg(PageMap);
- Regs.DI := Ofs(PageMap);
- Regs.BX := 0;
- Intr(EMSinterrupt, Regs);
- if Regs.AH <> 0 then
- EmsHandles := 0
- else
- EmsHandles := Regs.BX;
- end;
-
- procedure SaveStandardInfo;
- {-Save the ID string, the vectors, and so on}
- type
- IDArray = array[1..4] of Char;
- var
- ID : IDArray;
- begin
- {Write the ID string}
- {$IFDEF Debug}
- WriteLn('Writing mark file ID string');
- {$ENDIF}
- ID := NetMarkID;
- BlockWrite(MarkF, ID, SizeOf(IDArray));
- CheckWriteError;
-
- {Write the start address of the device chain}
- {$IFDEF Debug}
- WriteLn('Writing null device address');
- {$ENDIF}
- BlockWrite(MarkF, DevicePtr, SizeOf(Pointer));
- CheckWriteError;
-
- {Write the vector table}
- {$IFDEF Debug}
- WriteLn('Writing interrupt vector table');
- {$ENDIF}
- BlockWrite(MarkF, Mem[0:0], 1024);
- CheckWriteError;
-
- {Write miscellaneous save areas}
- {$IFDEF Debug}
- WriteLn('Writing EGA save table');
- {$ENDIF}
- BlockWrite(MarkF, Mem[$40:$A8], 8); {EGA save table}
- CheckWriteError;
- {$IFDEF Debug}
- WriteLn('Writing interapplications communication area');
- {$ENDIF}
- BlockWrite(MarkF, Mem[$40:$F0], 16); {Interapplications communication area}
- CheckWriteError;
- {$IFDEF Debug}
- WriteLn('Writing parent PSP segment');
- {$ENDIF}
- BlockWrite(MarkF, Mem[PrefixSeg:$16], 2); {Parent's PSP segment}
- CheckWriteError;
-
- {Write EMS information}
- if EMSpresent then begin
- GetMem(EmsPages, 2048);
- EMSpageMap(EmsPages^, EmsHandles);
- end else
- EmsHandles := 0;
- {$IFDEF Debug}
- WriteLn('Writing EMS handle information');
- {$ENDIF}
- BlockWrite(MarkF, EmsHandles, SizeOf(Word));
- if EmsHandles <> 0 then
- BlockWrite(MarkF, EmsPages^, 4*EmsHandles);
- CheckWriteError;
- end;
-
- procedure SaveDevChain;
- {-Save the device driver chain}
- begin
- {$IFDEF Debug}
- WriteLn('Saving device driver chain');
- {$ENDIF}
- while SO(DevicePtr).O <> $FFFF do begin
- BlockWrite(MarkF, DevicePtr^, SizeOf(DeviceHeader));
- CheckWriteError;
- with DevicePtr^ do
- DevicePtr := Ptr(NextHeaderSegment, NextHeaderOffset);
- end;
- end;
-
- procedure BufferFileTable;
- {-Save an image of the system file table}
- var
- S : SftRecPtr;
- Size : Word;
- begin
- with DosPtr^ do begin
- S := FirstSFT;
- FileTableCnt := 0;
- while SO(S).O <> $FFFF do begin
- Inc(FileTableCnt);
- Size := 6+S^.Count*FileRecSize;
- GetMem(FileTableA[FileTableCnt], Size);
- Move(S^, FileTableA[FileTableCnt]^, Size);
- S := S^.Next;
- end;
- end;
- end;
-
- procedure SaveDOSTable;
- {-Save the DOS internal variables table}
- var
- DosBase : Pointer;
- Size : Word;
- begin
- {$IFDEF Debug}
- WriteLn('Saving DOS data area at 0050:0000');
- {$ENDIF}
- BlockWrite(MarkF, mem[$50:$0], $200);
- CheckWriteError;
- DosBase := Ptr(SO(DosPtr).S, 0);
- {$IFDEF Debug}
- WriteLn('Saving DOS variables table at ', HexPtr(DosBase));
- {$ENDIF}
- Size := SO(DosPtr^.FirstSFT).O;
- BlockWrite(MarkF, Size, SizeOf(Word));
- BlockWrite(MarkF, DosBase^, Size);
- CheckWriteError;
- end;
-
- procedure SaveFileTable;
- {-Save the state of the file table}
- var
- I : Word;
- Size : Word;
- begin
- {$IFDEF Debug}
- WriteLn('Saving DOS file table at ', HexPtr(DosPtr^.FirstSFT));
- {$ENDIF}
- BlockWrite(MarkF, FileTableCnt, SizeOf(Word));
- for I := 1 to FileTableCnt do begin
- Size := 6+FileTableA[I]^.Count*FileRecSize;
- BlockWrite(MarkF, FileTableA[I]^, Size);
- end;
- CheckWriteError;
- end;
-
- procedure BufferCommandPSP;
- {-Save the PSP of COMMAND.COM}
- type
- McbRec =
- record
- ID : Char;
- PSPSeg : Word;
- Len : Word;
- end;
- var
- McbPtr : ^McbRec;
- PspPtr : Pointer;
- begin
- {First block}
- McbPtr := Ptr(DosPtr^.McbSeg, 0);
- {Next block, which is COMMAND.COM}
- McbPtr := Ptr(SO(McbPtr).S+McbPtr^.Len+1, 0);
- CommandSeg := McbPtr^.PSPSeg;
- PspPtr := Ptr(CommandSeg, 0);
- Move(PspPtr^, CommandPsp, $100);
- end;
-
- procedure SaveCommandPSP;
- begin
- {$IFDEF Debug}
- WriteLn('Saving COMMAND.COM PSP at ', HexW(CommandSeg), ':0000');
- {$ENDIF}
- BlockWrite(MarkF, CommandPsp, $100);
- CheckWriteError;
- end;
-
- procedure SaveCommandPatch;
- {-Restore the patch that NetWare applies to command.com}
- label
- ExitPoint;
- const
- Patch : array[0..14] of Char = ':/'#0'_______.___'#0;
- var
- Segm : Word;
- Ofst : Word;
- Indx : Word;
- begin
- for Segm := CommandSeg to PrefixSeg do
- for Ofst := 0 to 15 do begin
- Indx := 0;
- while (Indx <= 14) and (Patch[Indx] = Char(Mem[Segm:Ofst+Indx])) do
- Inc(Indx);
- if Indx > 14 then begin
- {$IFDEF Debug}
- WriteLn('Saving COMMAND patch address at ', HexW(Segm), ':', HexW(Ofst));
- {$ENDIF}
- goto ExitPoint;
- end;
- end;
- Segm := 0;
- Ofst := 0;
- ExitPoint:
- BlockWrite(MarkF, Ofst, SizeOf(Word));
- BlockWrite(MarkF, Segm, SizeOf(Word));
- CheckWriteError;
- end;
-
- procedure FindEnv(CommandSeg : Word; var EnvSeg, EnvLen : Word);
- {-Return the segment and length of the master environment}
- var
- Mcb : Word;
- begin
- Mcb := CommandSeg-1;
- EnvSeg := MemW[CommandSeg:$2C];
- if EnvSeg = 0 then
- {Master environment is next block past COMMAND}
- EnvSeg := Commandseg+MemW[Mcb:3]+1;
- EnvLen := MemW[(EnvSeg-1):3] shl 4;
- end;
-
- procedure SaveDosEnvironment;
- {-Save the master copy of the DOS environment}
- var
- EnvSeg : Word;
- EnvLen : Word;
- P : Pointer;
- begin
- FindEnv(CommandSeg, EnvSeg, EnvLen);
- {$IFDEF Debug}
- WriteLn('Saving master environment, ', EnvLen, ' bytes at ', HexW(EnvSeg), ':0000');
- {$ENDIF}
- P := Ptr(EnvSeg, 0);
- BlockWrite(MarkF, EnvLen, SizeOf(Word));
- BlockWrite(MarkF, P^, EnvLen);
- CheckWriteError;
- end;
-
- procedure SaveCommState;
- {-Save the state of the communications controllers}
- var
- PicMask : Byte;
- Com : Byte;
- LCRSave : Byte;
- Base : Word;
- ComPortBase : array[1..2] of Word absolute $40:0; {Com port base addresses}
-
- procedure SaveReg(Offset : Byte);
- {-Save one communications register}
- var
- Reg : Byte;
- begin
- Reg := Port[Base+Offset];
- BlockWrite(MarkF, Reg, SizeOf(Byte));
- CheckWriteError;
- end;
-
- begin
- {$IFDEF Debug}
- WriteLn('Saving communications environment');
- {$ENDIF}
-
- {Save the 8259 interrupt enable mask}
- PicMask := Port[$21];
- BlockWrite(MarkF, PicMask, SizeOf(Byte));
- CheckWriteError;
-
- for Com := 1 to 2 do begin
- Base := ComPortBase[Com];
-
- {Save the Com port base address}
- BlockWrite(MarkF, Base, SizeOf(Word));
- CheckWriteError;
-
- if Base <> 0 then begin
- {Save the rest of the control state}
- SaveReg(IER); {Interrupt enable register}
- SaveReg(LCR); {Line control register}
- SaveReg(MCR); {Modem control register}
- LCRSave := Port[Base+LCR]; {Save line control register}
- Port[Base+LCR] := LCRSave or $80; {Enable baud rate divisor registers}
- SaveReg(BRL); {Baud rate divisor low}
- SaveReg(BRH); {Baud rate divisor high}
- Port[Base+LCR] := LCRSave; {Restore line control register}
- end;
- end;
- end;
-
- function CompaqDOS30 : Boolean;
- {-Return true if Compaq DOS 3.0}
- begin
- with Regs do begin
- AH := $34;
- MsDos(Regs);
- CompaqDOS30 := (BX = $19C);
- end;
- end;
-
- procedure ValidateDosVersion;
- {-Assure supported version of DOS and compute size of DOS internal filerec}
- var
- DosVer : Word;
- begin
- DosVer := DosVersion;
- case Lo(DosVer) of
- 3 : if (Hi(DosVer) < $0A) and not CompaqDOS30 then
- {IBM DOS 3.0}
- FileRecSize := 56
- else
- {DOS 3.1+ or Compaq DOS 3.0}
- FileRecSize := 53;
- 4 : FileRecSize := 59;
- else
- Abort('Requires DOS 3.x or 4.x');
- end;
- end;
-
- procedure SaveIDStrings;
- {-Save identification strings within the PSP}
- var
- ID : String[10];
- begin
- Move(MarkName, Mem[PrefixSeg:$80], Length(MarkName)+1);
- Mem[PrefixSeg:$80+Length(MarkName)+1] := 13;
- ID := NmarkID;
- Move(ID[1], Mem[PrefixSeg:NmarkOffset], Length(ID));
- end;
-
- procedure CloseStandardFiles;
- {-Close all standard files}
- var
- H : Word;
- begin
- with Regs do
- for H := 0 to 4 do begin
- AH := $3E;
- BX := H;
- MsDos(Regs);
- end;
- end;
-
- begin
- {Must run with standard DOS vectors}
- SwapVectors;
- SaveExit := ExitProc;
- ExitProc := @ExitHandler;
-
- WriteLn('MARKNET ', Version, ', by TurboPower Software');
-
- {Assure supported version of DOS}
- ValidateDosVersion;
-
- {Assure mark file specified}
- if ParamCount = 0 then
- Abort('Usage: MARKNET NetMarkFile');
-
- {Find the device driver chain and the DOS internal table}
- FindDevChain;
-
- {Save PSP region of COMMAND.COM}
- BufferCommandPSP;
-
- {Buffer the DOS file table}
- BufferFileTable;
-
- {Open the mark file}
- MarkName := StUpcase(ParamStr(1));
- Assign(MarkF, MarkName);
- Rewrite(MarkF, 1);
- if IoResult <> 0 then
- Abort('Error creating '+MarkName);
- MarkFOpen := True;
-
- {Save ID string, interrupt vectors and other standard state information}
- SaveStandardInfo;
-
- {Save the device driver chain}
- SaveDevChain;
-
- {Save the DOS internal variables table}
- SaveDOSTable;
-
- {Save the DOS internal file management table}
- SaveFileTable;
-
- {Save the PSP of COMMAND.COM}
- SaveCommandPSP;
-
- {Save the location that NetWare may patch in COMMAND.COM}
- SaveCommandPatch;
-
- {Save the master copy of the DOS environment}
- SaveDosEnvironment;
-
- {Save the state of the communications controllers}
- SaveCommState;
-
- {Close mark file}
- Close(MarkF);
- CheckWriteError;
-
- {Move ID strings into place}
- SaveIDStrings;
-
- {Deallocate environment}
- with Regs do begin
- ES := MemW[PrefixSeg:$2C];
- AH := $49;
- MsDos(Regs);
- end;
-
- WriteLn('Stored mark information in ', MarkName);
- Flush(Output);
-
- {Close file handles}
- CloseStandardFiles;
-
- {Go resident}
- with Regs do begin
- dx := ($90+Length(MarkName)) shr 4;
- ax := $3100;
- MsDos(Regs);
- end;
- end.