		page	66,132
;====================================================================
;
; BOOTPW - A program to password protect a disk
;
; Copyright (c) 1993 Douglas Boling
;
;====================================================================
		code	segment
		assume	cs:code

		org	100h
;====================================================================
;BOOTPW Boot record
;
; Entry:     
;   CS:IP - 0:7C00h
;      DL - boot drive
;   ES:SI - Ptr to partition table boot entry (if hard disk.)
;   All other registers undefined
;====================================================================

root_offset	equ	500h
boot_buffer	equ	offset end_of_code + 512
pw_nonres	equ	offset password_size - offset entry


data_startl     equ     word ptr [bp]
data_starth     equ     word ptr [bp+2]
boot_disk       equ     byte ptr [bp+4]

bytes_per_sec   equ     word ptr [bp+0bh]
sec_per_cluster equ     byte ptr [bp+0dh]
reserved_sec    equ     word ptr [bp+0eh]
number_of_fats  equ     byte ptr [bp+10h]
root_size       equ     word ptr [bp+11h]
total_sec       equ     word ptr [bp+13h]
media_des_byte  equ     byte ptr [bp+15h]
sec_per_fat     equ     word ptr [bp+16h]
sec_per_track   equ     word ptr [bp+18h]
number_of_heads equ     word ptr [bp+1ah]
num_hidden_sec  equ     word ptr [bp+1ch]
boot_flag	equ	word ptr [bp+3feh]

oldboot_name	equ	7c00h + offset oldboot_nameo - offset entry
boot_initmsg	equ	7c00h + offset program - offset entry
boot_pwmsg	equ	7c00h + offset pw_msg - offset entry
boot_perrmsg 	equ	7c00h + offset pwerror_msg - offset entry
boot_rerrmsg 	equ	7c00h + offset readerr_msg - offset entry
boot_ferrmsg	equ	7c00h + offset finderr_msg - offset entry
boot_pw		equ	7c00h + offset password - offset entry
boot_pwsize	equ	7c00h + offset password_size - offset entry

;--------------------------------------------------------------------
;Boot sector code
;--------------------------------------------------------------------
entry:		jmp	initialize
oem_field	db	"BootPW10"
bpb_data	db	24 dup (0)		;Leave room for rest of BPB
bpb_dataend	=	$
boot_1:
	        cli				;Disable interrupts
	        cld                             ;Set direction UP.
	        mov     ax,7c00h
	        xor     bx,bx
	        mov     ss,bx                   ;SS:SP = 790:0
	        mov     sp,ax
	        sti				;Interrupts OK
		mov	ds,bx
		mov	es,bx
		push	si			;Save Part table ptr
		push	bp
		mov	bp,ax
		mov	boot_disk,dl

		mov     al,number_of_fats       ;Compute the sector of the
		cbw				;  roor directory.
	        mul     sec_per_fat
	        mov     cx,reserved_sec
	        add     cx,num_hidden_sec
	        adc     dx,num_hidden_sec[2]
	        add     cx,ax
	        adc     dx,bx                   ;BX = 0
		push	cx			;Save root sector low
		push	dx			;Save root sector high
	        mov     data_startl,cx
	        mov     data_starth,dx

	        mov     ax,32                   ;Get length of dir entry
	        mul     root_size               ;Compute the size -in sectors-
	        mov     si,bytes_per_sec        ;  of the Root Directory.
	        add     ax,si
	        dec     ax
	        div     si
	        add     data_startl,ax
	        adc     data_starth,bx
		push	ax
		pop	cx

		pop	dx			;Get root directory 
		pop	ax			;  starting sector
		mov	bx,root_offset		;Read the root dir
		push	bx			;Save ptr to Root dir
boot_3:
		push	cx
		push	ax
		push	dx
		call	boot_read_disk		;Loop on read_disk to
		pop	dx			;  read in all sectors
		pop	ax			;  of the root dir
		pop	cx
		jc	boot_error
		add	bx,bytes_per_sec
		add	ax,1
		adc	dx,0
		loop	boot_3

	        mov     si,boot_initmsg		;Identify ourselves 
		call	bootprint_msg
	        mov     si,boot_pwmsg		;Prompt for PW
		call	bootprint_msg
		mov	di,7c00h
		call	read_line		;Get password
		mov	si,boot_pwsize
		lodsb
		cmp	cl,al
		jne	boot_badpw
		rep	cmpsb
		jne	boot_badpw
		
		pop	si			;Get back Root ptr
		mov	bx,root_size
boot_4:
		mov	di,oldboot_name		;Find old boot record
		mov	cx,8			;  in root directory
		push	si
		repe	cmpsb
		pop	si
		je	boot_5
		add	si,32
		dec	bx
		jne	boot_4
	        mov     si,boot_ferrmsg
		jmp	short boot_error
boot_5:
		mov	cx,word ptr [si+1ah] 	;Get start clust
	        dec     cx			;Compensate for 1st to FAT
	        dec     cx			;  entries not being used.
	        mov     al,sec_per_cluster	;Get sectors per cluster
		cbw
	        mul     cx
	        add     ax,data_startl		
	        adc     dx,data_starth
		
		mov	bx,7e00h		;To address 0:7E00
		call	boot_read_disk
		jc	boot_error
		xor	ax,ax
		cwd
		call	boot_write_disk
		pop	bp
		pop	si
		int	19h			;Reboot
boot_badpw:
		mov	si,boot_perrmsg
boot_error:
		call	bootprint_msg
boot_halt:
		jmp	boot_halt

;-----------------------------------------------------------------------
; Write/Read disk - Writes or reads one sector from the disk
; Entry: DX,AX - Absolute sector to write/read
;        BX - address of buffer.
; Exit:  CF - Clear if read successful.
;-----------------------------------------------------------------------
boot_write_disk	proc	near
		mov	cx,0301h
		jmp	short read_1
boot_read_disk	proc	near
		mov	cx,0201h
read_1:
		push	cx
		push    bx
		div	sec_per_track		;Get sectors per track
	        inc     dx
read_2:
		mov	bx,dx			;Save sector
	        cwd
	        div     number_of_heads         ;Compute head and cylinder
	        xchg    ah,al                   ;Swap cyl low and high bytes
	        mov     cl,6
	        shl     al,cl                   ;Shift high cyl bits
	        xchg    cx,ax                   ;Copy cyl into CX
	        or      cl,bl                   ;Combine cyl with sector
	        mov     dh,dl                   ;Move head number
	        mov     si,5                    ;Try to read 5 times.
	        pop     bx			;Get dest buff offset
		pop	ax			;Get Read/Write cmd
read_3:
	        mov     dl,boot_disk            ;Get disk to read
		push	ax
	        int     13h                     ;Read/Write disk.
		pop	ax
	        jnc     read_exit               ;No error, exit
	        xor     ax,ax                   ;Reset disk before reading
	        int     13h
		dec	si
		jnz	read_3
	        mov     si,boot_rerrmsg
		stc
read_exit:							    
	        ret
boot_read_disk	endp
boot_write_disk	endp

;--------------------------------------------------------------------
; Print Msg - Prints a message to the screen
; Entry: DS:SI - Points to ASCIIZ message
;--------------------------------------------------------------------
bootprint_msg	proc	near
		push	bx
		push	bp
bprint_msg1:
		lodsb
		or	al,al
		je	bprint_exit
		mov	ah,0eh
		mov	bx,7h
		push	si
		int	10h
		pop	si
		jmp	short bprint_msg1
bprint_exit:
		mov	ax,0e0dh		;Append CR - LF
		int	10h
		mov	ax,0e0ah
		int	10h
		pop	bp
		pop	bx
		ret
bootprint_msg	endp
password_size	db	0
password	db	4eh,75h,0f0h,0beh,7dh,0b4h,0f9h,0c3h
;--------------------------------------------------------------------
; Read Line - Reads upto 8 charagers from the keyboard - No echo
; Entry: DS:DI - Points to buffer
; Exit:     CX - Number of characters in buffer
;--------------------------------------------------------------------
read_line	proc	near
		push	di
		mov	cx,8
readl_1:
		xor	ax,ax			;Get key
		int	16h
		cmp	al,13
		je	readl_exit
		cmp	al,8
		je	readl_2
		not	al
		stosb
		loop	readl_1
readl_exit:
		sub	cx,8
		neg	cx
		pop	di
		ret
readl_2:
		cmp	cx,8
		je	readl_1
		dec	di
		inc	cx
		jmp	short readl_1
read_line	endp
program		db	13,10,"BOOTPW 1.0 "
		db	"Copyright 1993 Douglas Boling",0
pw_msg		db	13,10,10,"Enter Password",0
pwerror_msg	db	"Wrong password",0
readerr_msg	db	"Read Error",0
finderr_msg	db	"Can",39,"t find "
oldboot_nameo	db	"OLDBOOT BIN",0

bootcode_end	=	$
		org	2feh
		dw	0AA55h			;Boot signature
boot_end	=	$
;====================================================================
;Start of nonresident install code
;====================================================================
program1        db      "First published in PC Magazine, "
		db	"March 30, 1993",13,10,10,0

infomsg1	db	"USAGE: BOOTPW d:",13,10
		db	"d: is the target diskette to "
		db	"password protect",0

infomsg3	db	"Please enter password, up to 8 characters",0
infomsg4	db	"Please reenter password for verification",0
infomsg5	db	13,10,"Disk "
infomsg5_dsk	db	" : Password protected.",0
infomsg6	db	13,10,"Password removed",0
infomsg7	db	"Disk password protected",0
infomsg8       	db	13,10,"Please remove the disk from the drive "
		db	"and press <Enter>",13,10
        	db	"or if the disk is a hard drive, turn off the system.",0

errmsg0		db	"This program requires DOS 2.0 or greater",0
errmsg1		db	"Target drive letter not specified",0
errmsg2  	db	"Target diskette not a DOS formatted "
		db	"disk",0
errmsg3 	db	"Unable to fit BOOTPW code on "
		db	"target disk",0
errmsg4		db	"Passwords do not match",0
errmsg5		db	"No password entered, disk not modified",0
errmsg6		db	"The password doesn't match the disk "
		db	"password",0
errmsg7		db	"Unable to find old DOS boot record",0

dos_version	dw	0
crit_vec	dd	0			;Critical err vector
targ_disk	db	0			;Disk to modify

oldboot_fname	db	"C:\OLDBOOT.BIN",0

doserr_tbl	dw	offset	doserr_00
	 	dw	offset	doserr_01
		dw	offset	doserr_02
		dw	offset	doserr_03
		dw	offset	doserr_04
		dw	offset	doserr_05
		dw	offset	doserr_06
		dw	offset	doserr_07
		dw	offset	doserr_08
		dw	offset	doserr_09
		dw	offset	doserr_10
		dw	offset	doserr_11
		dw	offset	doserr_12
		dw	offset	doserr_unk
doserr_tblend	=	$

doserr_00	db	"Disk Write Protected",0
doserr_01	db	"Unknown Unit",0
doserr_02	db	"Drive not ready",0
doserr_03	db	"Unknown Command",0
doserr_04	db	"CRC Data Error",0
doserr_05	db	"Bad request structure",0
doserr_06	db	"Disk Seek error",0
doserr_07	db	"Not a DOS disk",0
doserr_08	db	"Sector not found",0
doserr_09	db	"Printer out of paper",0
doserr_10	db	"Disk Write fault",0
doserr_11	db	"Disk Read fault",0
doserr_12	db	"General failure",0
doserr_unk	db	"Unknown DOS error",0

;--------------------------------------------------------------------
; INITIALIZE - Entry point of nonresident code
;--------------------------------------------------------------------
initialize:
		cld				;String ops UP
		mov	ah,30h			;Get DOS version
		int	21h
		xchg	al,ah
		mov	si,offset errmsg0
		cmp	ax,200h
		jb      init_jmperror
		mov	dos_version,ax
		mov	si,offset program	;Print copyright msg	
		call	print_msg
		mov	si,offset program1
		call	print_msg
		call	set_crit_vec		;Set crit vec to int routine

		mov	si,offset infomsg1     	;Syntax msg text
		cmp	byte ptr ds:[80h],0
		je	init_jmperror
		mov	si,offset 81h
		call	get_drive		;Get target disk
		jc	init_jmperror
		mov	targ_disk,al		;Save drive number
		mov	oldboot_fname,ah	;Save drive letter

		mov	bx,boot_buffer
		call	read_boot		;Read current boot record
		jc	init_jmperror

		call	check4bpw		;See if BOOTPW protected
		jnz	init_3

		mov	si,offset infomsg7	;Tell user disk protected
		call	print_msg
		mov	si,offset infomsg3	;Password prompt
		call	print_msg
		mov	di,offset end_of_code
		call	read_line
		mov	si,boot_buffer
		add	si,pw_nonres
		lodsb	
		cmp	al,cl
		jne	init_1			;PW lengths don't match
		rep	cmpsb 		
		jne	init_1			;PWs don't match
		call	uninstall
		jc	init_error
		jmp	short init_exit
init_1:
		mov	si,offset errmsg6	;Bad password
init_jmperror:
		jmp	short init_error
init_3:
		mov	si,offset infomsg3	;Password prompt
		call	print_msg
		mov	di,offset end_of_code
		call	read_line
		mov	si,offset errmsg5	;Password not entered
		jcxz	init_error
		push	cx
		mov	si,offset infomsg4	;Password verify prompt
		call	print_msg
		mov	di,offset end_of_code+16
		call	read_line
		mov	si,offset errmsg4	;Passwords don't match
		pop	bx
		cmp	cx,bx
		jne	init_error
		mov	si,offset end_of_code
		mov	di,offset end_of_code+16
		push	cx
		rep	cmpsb
		pop	cx
		mov	si,offset errmsg4	;Passwords don't match
		jne	init_error
		mov	si,offset end_of_code
		mov	di,offset password
		mov	password_size,cl
		rep	movsb			;Copy password

		call	install
init_4:		
		mov	si,offset infomsg8	;Make user remove the disk
		call	print_msg
		
		mov	ah,7			;DOS read key
		int	21h
		or	al,al
		jne	init_5
		mov	ah,7
		int	21h
init_5:
		cmp	al,27
		je	init_6
		mov	ah,1ch			;Get allocation info
		mov	dl,targ_disk
		inc	dl
		int	21h
		jnc	init_4
init_6:		
		xor	ax,ax			;Clear return code
init_exit:
		push	ax
	        call    reset_crit_vec		;Restore critical error vec
		pop	ax
		mov	ah,4ch
		int	21h
init_error:
		call	print_msg
		mov	al,1
		jmp	short init_exit

;--------------------------------------------------------------------
;GET DRIVE - Returns a disk number for a letter on the command line
; Entry: SI - Ptr to command line
; Exit:  AL - Drive number
;        AH - Drvie letter
;        SI - Points to character after :
;        CF - Set if error
;        DX - Offset of error message if CF set
;--------------------------------------------------------------------
get_drive	proc	near
		lodsb
		cmp	al,13			;See if end of line
		je	getdisk_err
		cmp	al,20h			;If space, keep looking
		jbe	get_drive
		mov	ah,al			;Save letter in AH
		and	ah,0dfh			;Convert to upper case
		or	al,20h			;Convert to lower case
		sub	al,'a'			;See if between a - z
		jb	getdisk_err
		cmp	al,25
		ja	getdisk_err
		mov	bl,al
		lodsb				;See if trailing :
		cmp	al,":"			;  present.
		jne	getdisk_err
		mov	al,bl			;Get back drv letter
		cmp	al,2
		jb	getdisk_1
		mov	al,80h
getdisk_1:
		clc
getdisk_exit:
		ret
getdisk_err:
		mov	si,offset errmsg1
		stc
		jmp	short getdisk_exit
get_drive	endp

;--------------------------------------------------------------------
;INSTALL - Installs the BOOTPW boot record on the target diskette
; Exit:  CF - Set if error
;        DX - Offset of error message if CF set
;--------------------------------------------------------------------
install		proc	near
		mov	di,offset entry
		mov	ax,0eb90h		;NOP + JMP short opcode
 		stosw
 		mov	ax,offset boot_1 - offset bpb_data
 		stosb

		mov	si,boot_buffer		;Get ptr to boot rec
		lodsb
		mov	bl,al			;Get opcode
		lodsw
		cmp	bl,0ebh			;See if short JMP opcode
		jne	install_1
			
		xor	ah,ah			;If short JMP, clear 
		jmp	install_2		;  high byte
install_1:
		mov	si,offset errmsg2
		cmp	bl,0e9h			;Check for long JMP
		jne	install_error
install_2:
		mov	si,boot_buffer+11
		mov	di,offset bpb_data	;Copy BIOS Param Blk
		mov	cx,offset bpb_dataend - offset bpb_data - 8
		rep	movsb

		mov	ah,3ch			;Create file
		mov	cx,2			;Make hidden
		mov	dx,offset oldboot_fname
		push	ds
		int	21h
		pop	ds
		mov	si,offset errmsg3
		jc	install_exit
		mov	bx,ax			;Copy file handle
		mov	ah,40h
		mov	cx,512			;Write 512 bytes
		mov	dx,boot_buffer
		int	21h
		mov	si,offset errmsg3
		jc	install_exit
		mov	ah,3eh			;Close file
		int	21h
		mov	si,offset errmsg3
		jc	install_exit

		mov	al,targ_disk		;Get target disk
		mov	bx,offset entry		;Point to BootPW rec
		call	write_boot		;Write new boot rec
		jc	install_exit

		mov	al,oldboot_fname
		mov	infomsg5_dsk,al
		mov	si,offset infomsg5	;Indicate installed 
		call	print_msg
		clc
install_exit:
		ret
install_error:
		stc
		jmp	short install_exit
install		endp

;--------------------------------------------------------------------
;UNINSTALL - Uninstalls BOOTPW from the target disk
; Exit:  CF - Set if error
;        DX - Offset of error message if CF set
;--------------------------------------------------------------------
uninstall	proc	near

		mov	di,boot_buffer
		mov	al,0ebh			;JMP short opcode
 		stosb
 		mov	al,offset boot_1 - offset bpb_data + 1
 		stosb
		mov	al,90h
 		stosb

		mov	al,targ_disk		;Get target disk
		mov	bx,boot_buffer		;Point to BootPW rec
		call	write_boot		;Write new boot rec
		jc	uninstall_error

		mov	ah,0dh			;Reset disks
		int	21h

		mov	ax,3d00h		;Open file
		mov	dx,offset oldboot_fname	;Open file that has
		int	21h			;  old boot rec
		mov	si,offset errmsg7
		jc	uninstall_exit
		mov	bx,ax			;Copy file handle
		mov	ah,3fh
		mov	cx,512			;Read 512 bytes
		mov	dx,boot_buffer
		int	21h
		mov	si,offset errmsg7
		jc	uninstall_exit
		mov	ah,3eh			;Close file
		int	21h
		mov	si,offset errmsg7
		jc	uninstall_exit

		mov	al,targ_disk		;Get target disk
		mov	bx,boot_buffer		;Point to DOS rec
		call	write_boot		;Write DOS boot rec
		jc	uninstall_exit
		mov	si,offset infomsg6	;Tell user, disk 
		call	print_msg		;  unprotected.
uninstall_exit:
		ret
uninstall_error:
		stc
		jmp	short uninstall_exit
uninstall	endp

;--------------------------------------------------------------------
; CHECK4BPW - Check boot record to see if it is a BootPW boot rec
; Exit:  ZF - Set if BootPW record
;--------------------------------------------------------------------
check4bpw	proc	near
		mov	si,boot_buffer
		add	si,3
		mov	di,offset oem_field
		mov	cx,8
		rep	cmpsb
		ret
check4bpw	endp

;--------------------------------------------------------------------
; READ BOOT - Reads the boot sector of a disk
; Entry: AL - Disk number (0=A, 1=B,...)
;        BX - Points to buffer
; Exit:  CF - Set if error
;        DX - Points to error message
;--------------------------------------------------------------------
read_boot	proc	near
		mov	al,targ_disk		;Get target disk

		mov 	cx,1			;read 1 sector
		mov	dx,0			;Sector 0
		call	read_absolute		;Read current boot rec
		ret
read_boot	endp

;--------------------------------------------------------------------
; WRITE BOOT - Wrotes the boot sector of a disk
; Entry: AL - Disk number (0=A, 1=B,...)
;        BX - Points to buffer
; Exit:  CF - Set if error
;        DX - Points to error message
;--------------------------------------------------------------------
write_boot	proc	near
		mov	al,targ_disk		;Get target disk
		mov 	cx,1			;read 1 sector
		mov	dx,0			;Sector 0
		call	write_absolute		;Read current boot rec
		ret
write_boot	endp

;--------------------------------------------------------------------
; READ ABSOLUTE - Reads sectors from the disk.
; Entry:   AL - Letter of drive to read
;          CX - Number of sectors to read.  
;       SI,DX - Sector to start read (SI only used on huge disks)
;       DS:BX - Pointer to data buffer. 
;--------------------------------------------------------------------
read_abs_hstruc	=	$			;Needed for >32M disks
read_abs_start	dd	0			;Starting sector
read_abs_cnt	dw	0			;Number of sectors to read
read_abs_dbp	dd	0			;Data buffer ptr

read_absolute   proc    near
		push	bx
		push	cx
		push	ds
		call	huge_disk_check
		jc	read_abs_2
		je	read_abs_1
		push	ds			;Save ptr to data buffer
		push	bx
		push	cs
		pop	ds
		mov	bx,offset read_abs_hstruc
		mov	[bx],dx			;More than 64K sectors
		mov	[bx+2],si		;  -> huge disk uses a
		mov	[bx+4],cx		;  different format
		pop	[bx+6]			;  than std int 25h.	
		pop	[bx+8]
		mov	cx,-1
read_abs_1:
	        int     25h                     ;DOS Absolute Disk Read
	        pop     bx                      ;Clean off old flags
		call	seterrmsg
	        cld
read_abs_2:
		pop	ds
		pop	cx
		pop	bx
	        ret
read_absolute   endp

;--------------------------------------------------------------------
; WRITE ABSOLUTE - Writes sectors to the disk.
; Entry:   AL - Letter of drive to write
;          CX - Number of sectors to write  
;       SI,DX - Sector to start write (SI only used on huge disks)
;       DS:BX - Pointer to data buffer. 
;--------------------------------------------------------------------
write_absolute  proc    near
		push	bx
		push	cx
		push	ds
		call	huge_disk_check
		jc	write_abs_2	
		je	write_abs_1
		push	ds			;Save data buffer pointer
		push	bx
		push	cs
		pop	ds
		mov	bx,offset read_abs_hstruc
		mov	[bx],dx			;More than 64K sectors
		mov	[bx+2],si		;  -> huge disk uses a
		mov	[bx+4],cx		;  different format
		pop	[bx+6]			;  than std int 26h.	
		pop	[bx+8]
		mov	cx,-1				
write_abs_1:
	        int     26h                     ;DOS Absolute Disk Write
	        pop     bx                      ;Clean off old flags
		call	seterrmsg
	        cld
write_abs_2:
		pop	ds
		pop	cx
		pop	bx
	        ret
write_absolute  endp

;--------------------------------------------------------------------
; HUGE DISK CHECK - Checks if disk is greater than 32 Meg
; Entry: AL - Disk to check
; Exit:  ZF - Clear if > 32 Meg disk
;        CF - Set if error
;        DI - Sectors per cluster
;--------------------------------------------------------------------
last_disk_read	db	-1
last_disk_huge	db	0
last_disk_spc 	dw	0
huge_disk_check	proc	near
		push	ax
		push	bx
		push	cx
		push	dx
		cmp	al,last_disk_read	;Save last disk checked, if
		jne	huge_disk_check_1	;  same as last disk, just
		mov	di,last_disk_spc	;  get saved answer.
		cmp	last_disk_huge,0	
		jmp	short huge_disk_check_3
huge_disk_check_1:
		mov	last_disk_read,al
		mov	last_disk_huge,0
		mov	dl,al			;Copy disk number
		inc	dl
		mov	ah,36h			;DOS Get Free disk space
		int	21h		
		cmp	ax,-1
		jne	huge_disk_check_2
		mov	last_disk_read,-1
		jmp	short huge_disk_check_4
huge_disk_check_2:
		mov	di,ax			;Save sectors per cluster
		mov	last_disk_spc,di
		mul	dx
		or	dx,dx			;See if more than 64K sectors
		je	huge_disk_check_3
		mov	last_disk_huge,1
huge_disk_check_3:
		clc
huge_disk_check_4:
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		ret
huge_disk_check	endp

;--------------------------------------------------------------------
; SET CRIT VEC - Sets the critical error vector to an internal routine
;                to avoid the abort, retry, ignore message.
;--------------------------------------------------------------------
set_crit_vec	proc	near
		push	es
	        mov     ax,3524h                ;Get crititcal error vector
	        int     21h                      
	        mov     word ptr crit_vec,bx    ;Save vector
		mov	word ptr crit_vec[2],es
	        mov     dx,offset crit_error    ;Set to internal routine.
	        mov     ax,2524h                
	        int     21h
		pop	es
		ret
set_crit_vec	endp

;--------------------------------------------------------------------
; RESET CRIT VEC - Resets the critical error vector to its original
;                  state.
;--------------------------------------------------------------------
reset_crit_vec	proc	near
		push	ds
	        lds     dx,crit_vec             ;Get old vector
	        mov     ax,2524h                ;Set vector
	        int     21h
		pop	ds
		ret
reset_crit_vec	endp

;--------------------------------------------------------------------
; SETERRMSG - Assigns a DOS error message to the value in AL
; Entry: AL - Error code
;        CF - Set if error
; Exit:  SI - Points to error message
;--------------------------------------------------------------------
seterrmsg	proc	near
		push	bx
		pushf
		jnc	seterrmsg_exit
		mov	bx,ax
		xor	bh,bh
		shl	bx,1
		cmp	bx,offset doserr_tblend - offset doserr_tbl
		jbe	seterrmsg_1
		mov	bx,26
seterrmsg_1:
		mov	si,[bx+doserr_tbl]
seterrmsg_exit:
		popf
		pop	bx
		ret
seterrmsg	endp

;--------------------------------------------------------------------
; Print Msg - Prints a message to the screen
; Entry: DS:SI - Points to ASCIIZ message
;--------------------------------------------------------------------
crlf_msg	db	13,10,"$"
print_msg	proc	near
print_msg1:
		lodsb
		or	al,al
		je	print_exit
		mov	dl,al
		mov	ah,02
		int	21h
		jmp	short print_msg1
print_exit:
		mov	dx,offset crlf_msg
		mov	ah,9
		int	21h
		ret
print_msg	endp

;-----------------------------------------------------------------------------
; Prevent Abort,Retry,Ignore error msg with this dummy crit. error routine
;-----------------------------------------------------------------------------
crit_error      proc    far
	        mov     al,0                    ;Ignore critical error.
	        cmp	cs:dos_version,300h
	        jb	crit_1
		mov	al,3
crit_1:			        
	        iret
crit_error      endp

		even	
end_of_code	=	$
code		ends
end		entry
