tmh@bigfoot.first.gmd.de (Thomas Hoberg) (11/17/90)
This is about a month late by now, sorry! Part 1 of 2 (sources) ---- Thomas M. Hoberg | UUCP: tmh@prosun.first.gmd.de or tmh%gmdtub@tub.UUCP c/o GMD Berlin | ...!unido!tub!gmdtub!tmh (Europe) or D-1000 Berlin 12 | ...!unido!tub!tmh Hardenbergplatz 2 | ...!pyramid!tub!tmh (World) Germany | BITNET: tmh%DB0TUI6.BITNET@DB0TUI11 or +49-30-254 99 160 | tmh@tub.BITNET 8-< -------------------------------------------------------------- #!/bin/sh # This is a shell archive (shar 3.43) # made 11/16/1990 18:33 UTC by tmh@sparci1 # Source directory /home/doppel/tmh/pboot/dist # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 4285 -rw-r----- pboot.doc # 7852 -rw-r----- pboot.asm # 4448 -rw-r----- install.c # 239 -rw-r----- makefile # # ============= pboot.doc ============== if test -f 'pboot.doc' -a X"$1" != X"-c"; then echo 'x - skipping pboot.doc (File already exists)' else echo 'x - extracting pboot.doc (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pboot.doc' && PBOOT.ASM and INSTALL.C: partition booter and intallation utility for FDISK compatible disks. X +++ you may ignore this +++ X I am sorry, I took so long to get this posted on the net, but I had a stroke of bad luck the last two weeks. First I had to go search for the sources (some hours), just as I had it I got bitten by a virus (that took the rest of the day to get rid off). Next day 386/ix's mkdosfs command decided to trash the root filesystem on a 'mkdosfs' on /dev/dsk/0p3, which I thought should point to the third partition (0p1 pointed to C: and 0p2 to D: so why doen't 0p3 point to E:?), but wrecked havok on the fourth (containing UNIX). That gave me a couple of evenings worth of work (I do real work during the day). Now if that weren't enough, just the next day I tried some benchmark programs written by Roy Neese of Adaptec (quite well known around here, I believe): GREAD and GWRITE. GREAD gave me times far better than CORETEST (I liked that) and GWRITE's times weren't bad either. When I tried to call up GDRIVE I got something like 'file allocation table corrupted', a reboot yielded a very silent system. As it turns out, GWRITE had written the setup portion of my BIOS all over the first cylinder of the disk, invalidating the boot block, DOS boot and both FAT's. Now I read the documentation, I didn't interrupt the the program or anything, I had it run to completion and it caused great dammage. I must say, that I wouldn't have run the program if it hadn't been written by Roy Neese, but I guess to run ANY program that uses int 0x13 to write on the disk without a current backup is foolish at least. ARE YOU LISTENING? My installation utility ALSO uses int 0x13 to access the master boot block. Have you made a backup yet? I also upgraded my system to an i486 the other day, so now you know were all the time went.... X +++ the intersting stuff starts here +++ X PBOOT.ASM contains the source code for a partition booter small enough to fit on the master boot block with the partition table and should thus be compatible with just about any operating system and hardware (old Microport Unix systems are an exception, as they sometimes wrote the physical disk parameters in the boot block for disks not supported by the BIOS). X PBOOT reads the embedded partition tables of the first two disks on the first controller, displays a menu of partitions with the names of the operating systems it knows about (e.g. DOS, 386/ix, and AX) along with the value of the operating system marker. It then asks you to enter the number of the desired boot from partition (1-4 for one disk, 1-8 for two), loads the first block of that partition and gives control to it (the normal booting procedure). X PBOOT doesn't really care which partition is actually active, though most UNIX versions require the UNIX partition containing the boot code to be active. Thus for UNIX you will want to leave the UNIX partition active at all times. On actuall boot up though you will be able to boot any partition. X You will probably want to modify PBOOT to recognize the markers of the operating systems that you actually use. Note that you will have to modify the appropriate values at several places in the code (I didn't want to invest any time in cleaning up that code). Note, though, that you do not inadvertently increase the size of the code. It's a very tight fit (currently, I believe, there is ONE byte left over). X PBOOT was originally written by Reinhard Baier for AX (= Advanced Unix), a research operating system developed at the Technical University of Berlin, featureing a tiny message passing kernel with an extremely low context switch overhead, run-time installable device drivers, file systems (DOS, UNIX, QNX), system call emulators (DOS, UNIX, QNX) running on Intel processors in real and protected mode. X Due to the greedyness and narrowmindedness of the professor overseeing the project, who wanted to keep it to himself and market it embedded into products that a company owned by him sold, it was never actively distributed among universities or other interested parties (although it is in the public domain). X The installation utility I wrote myself in a hurry. It seems to work on my system, but you may want to look at it real hard. X I hope it helps! X :-) Thomas X SHAR_EOF chmod 0640 pboot.doc || echo 'restore of pboot.doc failed' Wc_c="`wc -c < 'pboot.doc'`" test 4285 -eq "$Wc_c" || echo 'pboot.doc: original size 4285, current size' "$Wc_c" fi # ============= pboot.asm ============== if test -f 'pboot.asm' -a X"$1" != X"-c"; then echo 'x - skipping pboot.asm (File already exists)' else echo 'x - extracting pboot.asm (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pboot.asm' && ; pboot.asm ; ; originally written by Rainhard Baier of the Berlin Technical University ; converted from QNX ASM to TASM format by Thomas Hoberg ; view with tabs set to four spaces ; NOTE: you will want to adapt the operating system markers to your own taste. ; Make sure you don't increase the size of the code, it's a very tight squeeze! ; ; $Revision: 1.2 $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Fixed disk M A S T E R B O O T R O U T I N E ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; If the system is unable to boot from diskette, it loads ; ; the master boot record from the first fixed disk ; ; and gives control to it. Then this routine copies ; ; itselves to 0000:0600 and tries to read the partition ; ; table of an eventually installed second disk. ; ; If there is an active bootable partition defined, ; ; the corresponding boot record will be loaded and ; ; executed. If an error occurs the user will be asked ; ; to enter the partition number which he wants to boot. ; ; This happens also if there is no active partition. ; ; To give the user some hints, a table is displayed ; ; containing the most important dates about the four or ; ; eight possible partitions. ; ; This routine does not check if there is more than one ; ; active partition - the first one found will be booted. ; ; The search order is from one to the last as described in ; ; the "DOS Version 3.00 Technical Reference Manual". ; ; It is just a little bit surprising that the DOS-command ; ; "FDISK" counts in reverse order... ; ; With this booter it is also possible to load an OS from ; ; the second disk. But it is necessary that all OS-Booters ; ; determine the contents of register DL to see ; ; on what physical disk they are. In this way ; ; all disks may be used as first or second device in any ; ; system. It should be avoided to boot an OS from a disk ; ; different from that the booter was on. ; ; ; ; -- 14.12.85 RaB -- ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; new_seg = 060h new_off = 00000h X part_tab = 1beh num_entries = 4 entry_size = 010h signature = 1feh last_byte = 1ffh X boot_dev = 80h X boot_ind = 00h head_b = 01h sector_b = 02h cyl_b = 03h syst_ind = 04h head_e = 05h sector_e = 06h cyl_e = 07h rel_sect_l = 08h rel_sect_l = 0ah num_sect_l = 0ch num_sect_l = 0eh X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X org new_off X .model tiny X .code X align 1 boot: X call get_ip ; stack MUST be ready get_ip: X pop si ; get IP to this instruction X sub si,3 ; IP to boot: X push cs X pop ds ; get current CS to DS X X xor di,di X mov ax,new_seg X mov es,ax X cld X mov cx,100h X repnz movsw ; copy 512 Bytes DS:SI -> ES:DI ; abs jmp loader, newseg X db 0eah X dw loader, new_seg ; -------------- X ; | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | X ; | loader: ; <------------- X mov bx,si X sub bx,200h ; use same buffer for 2nd partition block X push ds X pop es ; ES:BX points to buffer X X mov cx,1 ; 1st sector X mov dx,81h ; 2nd drive X call read_sector ; initialize register dh with value 4 17.08.89 X jnc drive2_ok X mov dh,'4' ; last valid partition (1 drive) X jmp menu X drive2_ok: X cmp signature[bx],0aa55h ;test for valid signature X jne menu X lea si,part_tab[bx] X X push cs X pop es X mov di,signature X mov cx,num_entries * entry_size / 2 X X repnz movsw ; copy second partition table after X ; the first one X X mov dh,'8' ; last valid partion (2 drives active) X menu: X push cs X pop ds X xor cl,cl ; active partition X mov bx,part_tab X mov dl,'1' X X mov si, offset header X call prstr X check_entry: X mov al,dl X call prchar X mov si,offset blank X call prstr X X mov ch,syst_ind[bx] X mov si,offset type_0 X cmp ch,0 X je show_it X mov si,offset type_dos X cmp ch,1 X je show_it X cmp ch,4 X je show_it X mov si,offset type_ax X cmp ch,7 X je show_it X mov si,offset type_sys5 X cmp ch,063h X je show_it X mov si,offset type_swap X cmp ch,6 X je show_it X mov si,offset type_X show_it: X call prstr X mov al,'(' X call prchar X mov al,ch X add al,'0' X call prchar X mov al,')' X call prchar X cmp ch,063h X je linefeed X cmp byte ptr boot_ind[bx],80h X jne linefeed X mov cl,dl ; save number of active entry linefeed: X mov si,offset crlf X call prstr X X add bx,entry_size X inc dl X cmp dl,dh X jle check_entry X X mov si,offset crlf X call prstr ;;; If the following statements are uncommented PBOOT will boot the active ;;; partition if no key is pressed. ;;; I find it hard to press the right key just in time (my BIOS flushes the ;;; keyboard queue immediately before executing this code) that's why I don't ;;; use it. If you need automatic reboots or something like that you might ;;; want to reenable it (watch out for code size!) ; mov ah,1 ;if no key is pressed use the active ; int 16h ;partition stored in cl (doesn't work ; jnz get_key ;for the first because cl is zero) ; or cl,cl ; jz get_key ; no active partition ; mov al,cl ; restore active partition ; jmp get_part get_key: X mov si,offset what_part X call prstr X xor ah,ah X int 16h X cmp al,'0' X jle error X cmp al,dh X ja error X get_part: X sub al,31h X mov dl,boot_dev X cmp al,4 X jl drive_1 X inc dl drive_1: X xor ah,ah X mov bl,entry_size X mul bl X mov bx,part_tab X add bx,ax X cmp byte ptr syst_ind[bx],0 X jne boot_it X jmp error boot_it: X push dx ; save last valid partition in dh X mov cx,sector_b[bx] X mov dh,head_b[bx] X xor ax,ax ; addr = ES:BX X mov es,ax X mov bx,7c00h X call read_sector X pop dx ; restore dh X jnc read_ok X mov si,offset load_error X call prstr X jmp error X read_ok: X cmp signature[es:bx],0aa55h ;test for valid signature X je boot_ok X mov si,offset sig_missing X call prstr error: X mov si,offset err_crlf X call prstr X jmp get_key ; try again X boot_ok: ; 17.8.89 it's better to print \n X mov si,offset crlf X call prstr ; 17.08.89 don't clear the screen ; mov ah,#15 ; get card type ; int 010h ; returned in al X ; xor ah,ah ; set mode clears screen ; int 10h ; and positions cursor home X X ; DL contains boot - drive ; abs jmp 7c00h,0000h ; goto partition boot record just loaded X db 0eah X dw 7c00h, 0000h X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X prstr: ; si = "string" X lodsb X or al,al X jz end_prstr X call prchar X jmp prstr end_prstr: X ret X prchar: ; al = 'char' X push bx X xor bl,bl ; foreground color graphics mode X mov ah,14 X int 10h X pop bx X ret X read_sector: X mov si,5 ; retry_count retry: X mov ax,0201h ; read 1 sector X int 13h X jnc end_read_sector X dec si X jnz retry X stc end_read_sector: X ret X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X .data header: X db "Part. OS(type)", 0dh, 0ah, 0 blank: X db " ", 0 type_0: X db "--- ", 0 type_dos: X db "DOS ", 0 type_ax: X db "AX ", 0 type_sys5: X db "SysV ", 0 type_swap: X db "Swap ", 0 type_X: ; db "??? ", 0 sig_missing: X db "No OS", 0 X err_crlf: X db 7 crlf: X db 0dh, 0ah, 0 X what_part: X db "Partition? ",0 load_error: X db "Error", 0 X X end SHAR_EOF chmod 0640 pboot.asm || echo 'restore of pboot.asm failed' Wc_c="`wc -c < 'pboot.asm'`" test 7852 -eq "$Wc_c" || echo 'pboot.asm: original size 7852, current size' "$Wc_c" fi # ============= install.c ============== if test -f 'install.c' -a X"$1" != X"-c"; then echo 'x - skipping install.c (File already exists)' else echo 'x - extracting install.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'install.c' && /* X * install.c -- install new boot code preserving the old partition table and X * saving the old boot block (whatever for?) X * X * Nov 1st, 1990 Thomas Hoberg tmh%gmdtub@tub.UUCP X * X * Unlimited Warranty: I hereby guarantee, that this program may or may not X * do what you think it does, and that it might or might not destroy your data. X * (I hate Disclaimers and Limited Warranties, let's stand up for our code!) X */ X #include <stdio.h> #include <dos.h> #include <string.h> X #define BLKSIZE 512 /* sizes in bytes */ #define PTBLSIZE 16*4 #define SIGNSIZE 2 #define BOOTSIZE BLKSIZE - (PTBLSIZE + SIGNSIZE) #define SIGNATURE 0xAA55U X typedef struct mbb { X char bootcode[BOOTSIZE]; X char ptable[PTBLSIZE]; X unsigned short int signature; } mbbT; X char *Usage = "Partition booter installation program. See source and documantation for usage\n" "details. It will basically copy a file to the disk\'s boot block while maintain-\n" "ing the partition table (hopefully). If your master boot block was not instal-\n" "led by DOS FDISK you better don\'t use this...\n" "It will also write a copy of the old boot block, which can be restored via\n" "the \'-r\' option. You will want to run the programm off an emergency boot disk\n" "(*NOT* write protected).\n\n" "USAGE: install <name-of-bootfile-to-install> <file-to-save-old-boot-code-into>\n" " OR: install -r <file-containing-old-boot-code>\n" "NOTE : All parameters are mandatory (this is a hack, not a program).\n" ; X char *NoSignature = "The block read does not contain a valid signature which means, that either\n" "this program ain\'t working, or your system doesn\'t at this time contain\n" "a valid boot block. If you are sure you want to go on, press <ENTER>,\n" "otherwise hit <Ctrl-C>, <Ctrl-Break> or *RESET*, to abort.\n\b" ; X char *CodeTooBig = "Your boot block is too big (> %d bytes). It would overwrite the embedded\n" "partition table. Installation aborted.\n\b" ; X char *wrongSizeForBoot = "A valid boot block should be exactly %d bytes in size. The one you supplied in" "\'%s\' has an invalid size of %d. Hit <ENTER> now to continue with the install-" "ation (risky) or <Ctrl-C>, <Ctrl-Break> or *RESET* to abort.\n\b" ; X X mbbT oldMbb, newMbb; FILE *inFile, *outFile; char *inName; union REGS regs; struct SREGS sregs; int install; X X FILE * doOpen(char *name, char *mode) { X X FILE *aFile; X X if ((aFile = fopen(name, mode)) < 0) { X perror(name); X fprintf(stderr, "%s\b", Usage); X exit(1); X } X return aFile; } X X int main (int argc, char *argv[]) { X X size_t fc; X X if (argc != 3) { X fprintf(stderr, "%s\b", Usage); X return 1; X } X install = strcmp(argv[1], "-r") != 0; X if (install) { X inName = argv[1]; X inFile = doOpen(inName, "rb"); X outFile = doOpen(argv[2], "wb"); X } else { X inName = argv[2]; X inFile = doOpen(inName, "rb"); X } X if ((fc = fread(&newMbb, 1, BLKSIZE, inFile)) < 0) { X perror(inName); X fprintf(stderr, "%s\b", Usage); X return 2; X } X close(inFile); X if (install) { X if (fc > BOOTSIZE) { X fprintf(stderr, CodeTooBig, BOOTSIZE); X return 9; X } X regs.x.ax = 0; /* reset disk */ X regs.x.dx = 0x80; X int86(0x13, ®s, ®s); X if (regs.h.ah != 0) { X fprintf(stderr, "couldn\'t reset disk drive!\b\n"); X return 3; X } X segread(&sregs); X regs.x.ax = 0x0201; /* read first sector */ X regs.x.cx = 1; X regs.x.dx = 0x80; X regs.x.bx = (unsigned int) &oldMbb; X sregs.es = sregs.ds; X int86x(0x13, ®s, ®s, &sregs); X if (regs.h.ah != 0) { X fprintf(stderr, "couldn\'t read boot block!\b\n"); X return 4; X } X if (oldMbb.signature != SIGNATURE) { X fprintf(stderr, NoSignature); X getchar(); X } X fwrite(&oldMbb, BLKSIZE, 1, outFile); X close(outFile); X memcpy(newMbb.ptable, oldMbb.ptable, PTBLSIZE); X newMbb.signature = SIGNATURE; X } else { /* restore */ X if (fc != BLKSIZE) { X fprintf(stderr, wrongSizeForBoot, BLKSIZE, argv[2], fc); X getchar(); X } X } /* endif */ X segread(&sregs); X regs.x.ax = 0x0301; /* write first sector */ X regs.x.cx = 1; X regs.x.dx = 0x80; /* first fixed disk */ X regs.x.bx = (unsigned int) &newMbb; X sregs.es = sregs.ds; X int86x(0x13, ®s, ®s, &sregs); X if (regs.h.ah != 0) { X fprintf(stderr, "Write of new boot block failed for some reason!\b\n"); X return 8; X } X if (install) { X printf("New boot block \'%s\' installed, old block saved to \'%s\'\n", X argv[1], argv[2]); X } else { X printf("Boot block restored from \'%s\'\n", argv[2]); X } X printf("Sure hope it worked...\n"); X return 0; } SHAR_EOF chmod 0640 install.c || echo 'restore of install.c failed' Wc_c="`wc -c < 'install.c'`" test 4448 -eq "$Wc_c" || echo 'install.c: original size 4448, current size' "$Wc_c" fi # ============= makefile ============== if test -f 'makefile' -a X"$1" != X"-c"; then echo 'x - skipping makefile (File already exists)' else echo 'x - extracting makefile (Text)' sed 's/^X//' << 'SHAR_EOF' > 'makefile' && # make macros don't seem to be portable... X all: pboot.bin install.exe X pboot.bin: pboot.exe X exe2bin pboot.exe pboot.bin X pboot.exe: pboot.obj X tlink pboot.obj X pboot.obj: pboot.asm X tasm pboot.asm; X install.exe: install.c X tcc install.c SHAR_EOF chmod 0640 makefile || echo 'restore of makefile failed' Wc_c="`wc -c < 'makefile'`" test 239 -eq "$Wc_c" || echo 'makefile: original size 239, current size' "$Wc_c" fi exit 0
tmh@bigfoot.first.gmd.de (Thomas Hoberg) (11/17/90)
Part 2/2: (binaries, uuencoded) ---- Thomas M. Hoberg | UUCP: tmh@prosun.first.gmd.de or tmh%gmdtub@tub.UUCP c/o GMD Berlin | ...!unido!tub!gmdtub!tmh (Europe) or D-1000 Berlin 12 | ...!unido!tub!tmh Hardenbergplatz 2 | ...!pyramid!tub!tmh (World) Germany | BITNET: tmh%DB0TUI6.BITNET@DB0TUI11 or +49-30-254 99 160 | tmh@tub.BITNET 8-< ----------------------------------------------------------- #!/bin/sh # This is a shell archive (shar 3.43) # made 11/16/1990 18:10 UTC by tmh@sparci1 # Source directory /home/doppel/tmh/pboot/dist # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 17539 -rw-r----- install.com.uu # 663 -rw-r----- pboot.bin.uu # # ============= install.com.uu ============== if test -f 'install.com.uu' -a X"$1" != X"-c"; then echo 'x - skipping install.com.uu (File already exists)' else echo 'x - extracting install.com.uu (Text)' sed 's/^X//' << 'SHAR_EOF' > 'install.com.uu' && X begin 666 install.com MC,HNB18-`[0PS2&++@(`BQXL`([:H\<BC`;%(HD>P2*)+MTBZ!8!Q#Z_(HO'V MB]BY_W_\\J[C84,F.`5U]H#-@/?9B0Z_(KD!`-/C@\,(@^/XB1[#(HS:*^J+. M/G8L@?\``G,'OP`"B3YV+(''SC%R*`,^.BIR(K$$T^]'.^]R&8,^=BP`=`>#T M/CHJ`'4.OP`0.^]W!XO]ZP/I70&+WP/:B1[5(HD>V2*AQ2(KV([`M$I7S2%?; MT^?ZCM*+Y_LSP"Z.!@T#OUHMN<XQ*\_\\ZJT`,T:B1;+(HD.S2(S[;Y`(K],/ M(NC(`"Z.'@T#_S:](O\VNR+_-KDBZ%$!+L8&OP)R+L8&K@(`4.A%!+Y,(K],[ M(NB;`"Z.'@T#_Q;(*/\6RBC_%LPH+HX>#0/H50"+[+1,BD8"S2&Y#@"Z?2+I+ MP0`>N``US2&)'JDBC`:K(K@$-<TAB1ZM(HP&KR*X!37-(8D>L2*,!K,BN`8UW MS2&)'K4BC`:W(K@`)8S*CMJZ-`+-(1_#'K@`)<46J2+-(1\>N`0EQ1:M(LTAW M'QZX!27%%K$BS2$?'K@&)<46M2+-(1_#M/^+UXO>.]]T%(`__W0*.&<!=P6*? M9P&+TX/#!NOH.]=T((O:'@<&@#\`Q@?_+HX>#0-T!R;_7P(?Z\4F_U<"'^N^F MP[1`NP(`S2'#N1X`NHLB+HX>#0/HZO^X`P!0Z!;_`````%6+[%;_=@;_=@3HD M\`5968OP"\!S'?]V!.CG"%G_-N`B:-\G:.XHZ#X&@\0&:@'H#`-9B\;K`%Y=T MPU6+[%97BW8&@WX$`W06_S;@(FC?)VCN*.@3!H/$!K@!`.E7`FCC)_]T`NBO_ M%5E9"\!T!;@!`.L",\"C>#&#/G@Q`'0EBT0"HW8Q:.8G_S9V,>AS_UE9HW0QS M:.DG_W0$Z&7_65FC:C'K%8M$!*-V,6CF)_\V=C'H3O]96:-T,?\V=#%H``)JV M`6AJ+^B=!H/$"(OX"\!S'O\V=C'H+`A9_S;@(FC?)VCN*.B#!8/$!K@"`.G'6 M`?\V=#'H'0)9@SYX,0!U`^D``8'_O@%V%FB^`?\VY")H[BCH506#Q`:X"0#IK MF0''!EHO``#'!F`O@`!H6B]H6B]J$^B_#X/$!H`^6R\`=!%H["=H[BCH(@59< M6;@#`.EG`6AL,>AT%%G'!EHO`0+'!EXO`0#'!F`O@`#'!EPO6BVA<C&C;#%H. M;#%H6B]H6B]J$^B6#X/$"(`^6R\`=!%H"2AH[BCHU`196;@$`.D9`8$^6"]5( MJG0L_S;B(FCN*.BZ!%E9H<XH2*/.*`O`?`Z+'M@H_P;8*(H'M`#K!VC.*.ACT M#EG_-FHQ:@%H``)H6BWHVP:#Q`C_-FHQZ"D!66I`:!@O:"@QZ#\1@\0&QP9HB M,56JZSJ!_P`"=#17_W0$:``"_S;F(FCN*.A1!(/$"J'.*$BCSB@+P'P.BQ[8. M*/\&V"B*![0`ZP=HSBCH^0U9:&PQZ(@36<<&6B\!`\<&7B\!`,<&8"^``,<&( M7"]J+Z%R,:-L,6AL,6A:+VA:+VH3Z*H.@\0(@#Y;+P!T$&@E*&CN*.CH`UE9_ MN`@`ZRZ#/G@Q`'01_W0$_W0":%<HZ)X&@\0&ZPO_=`1HCRCHD`9966BN*.B(> M!EDSP.L`7UY=PU6+[%8SP%#_=@3H30Q968OP/?__=0+K&O=&!@(`=`;WQ@$`: M=00SP.L)QP;)(@4`N/__7EW#58OL@S[&*"!U!;@!`.L3BQ[&*-'CBT8$B8=Z' M,?\&QB@SP%W#58OL5HMV!`OV?`6#_A1\";@&`%#HL0[K#XO>T>/'APXJ__]6@ MZ/4+65Y=P\-5B^SK"HL>QBC1X_^7>C&AQBC_#L8H"\!UZ_]V!.B;^UE=PU6+4 M[%97BW8$O___.70.=`+K8(-\!@!T'H,\`'T+5NA7`%D+P'0"ZTKW1`($`'0'5 M_W0(Z.H768!\!`!\"XI$!)A0Z&W_68OXQT0"``#'1`8``,<$``#&1`3_@WP,O M`'03,\!0_W0,Z#$)4.AX$EG'1`P``(O'7UY=PU6+[%97BW8$"_9U!>AS`.MKV M.70.=`6X___K8X,\`'PI]T0""`!U"HO&!04`.40*=1;'!```B\8%!0`Y1`IUO M"(M$"(E$"NLUZS.+1`8#!$"+^(L$*\>)!%>+1`B)1`I0BD0$F%#H,PF#Q`8[< MQW0.]T0"``)U!X%,`A``ZYHSP%]>7<-5B^Q,3%97QT;^``"_%`"^SBCK$O=$3 M`@,`=`A6Z%__6?]&_H/&$(O'3PO`=>>+1OY?7HOE7<-5B^Q,3%97BW8(,__') M1OX``#/)B]Y&B@>*T#QR=0B_`0"Y`0#K((#Z=W4%OP(#ZPB`^F%U#;\""<=&@ M_H``N0(`ZP0SP.MOB@2*T$8\*W0-@#PK=2,\='0$/&)U&X#Z*W4$B@2*T(O'X M)?S_#00`B_C'1OZ``;D#`(#Z='4&@<\`0.L>@/IB=0:!SP"`ZP^A-BHE`,`+0 M^(O'J0"`=`2!R4``QP;**'(1BUX&B3^+7@2+1OZ)!XO!7UZ+Y5W"!@!5B^R#G M[`16BW8(_W8$C4;^4(U&_%#H*_^)1`(+P'0<@'P$`'TC_W;\_W;^_W8&Z`$.Z M@\0&B$0$"L!]#<9$!/_'1`(``#/`ZS^*1`284.AY#%D+P'0%@4P"``*X``)0' MA40"=`6X`0#K`C/`4#/`4%;H5@:#Q`@+P'0'5NB6_5GKQ,=$#```B\9>B^5=+ MP@8`5K[.*(!\!`!\"HO&@\80/0XJ<O"`?`0`?`0SP.L"B\9>PU6+[%;HU_^+6 M\`O`=00SP.L*5O]V!/]V!N@U_UY=PU6+[%:+=@@Y=`YT!#/`ZP]6Z#']65;_E M=@3_=@;H$_]>7<-5B^Q6@WX$`'P)Z)'_B_`+P'4$,\#K$(I&!(A$!%8SP%#_Z M=@;HZ?Y>7<-5B^RXCPU0_W8$_W8&C48(4.CW#UW#58OL3$Q65XM^".G%`/]&[ M!HM>!(M'!CM&!G8%BT8&ZP:+7@2+1P:+\(M>!/='`D``=%Z#?P8`=%B+1P8[[ M1@9S4(,_`'5+_TX&,_;K#(M>!`-W!HM'!BE&!HM>!(M'!CM&!G;I5E>*1P28# M4.C##H/$!HE&_@/X.\9T68O&*T;^`48&BUX$@T\"(.M1BD;^B`5'_TX&BT8&B M"\!T,$YT+8M>!(L'2(D'"\!\$E.+7PJ+PUO_1PJ+V(H'M`#K!_]V!.CS"%F)F M1OX]__]UP(-^_O]U`NNO@WX&`'0#Z3+_BT8&7UZ+Y5W"!@!5B^R#[`16BW8&@ M"_9U`NLVB]XSR8M&"#/2Z',6B4;\B5;^@_H!=Q]R!`O`<QG_=@3_=OS_=@KHG MX?Y0BT;\6BO",]+W]NL",\!>B^5=PU6+[%97BUX$@S\`?0B+1P8#!T#K"HM>P M!(L'F3/"*\*+\(O(BUX$]T<"0`!T`NLOBUX$BW\*@S\`?1WK"4^+WX`_"G4!E M08O&3@O`=?#K$(O?1X`_"G4!08O&3@O`=?"+P5]>7<("`%6+[%:+=@16Z+?[, M60O`=`6X___K2H-^"@%U$(,\`'X+5NAV_YDI1@895@B!9`)?_L<$``"+1`B)( M1`K_=@K_=@C_=@:*1`284.C&"8/$"(/Z_W4*/?__=06X___K`C/`7EW#58OL5 M@^P$5HMV!(I$!)A0Z%<$68E&_(E6_H,\`'T-5N@6_YD!1OP15O[K"U;H"?^9^ M*4;\&5;^BU;^BT;\7HOE7<-5B^R#[`16BW8&"_9U!8M&".LQB]XSR8M&"#/2! MZ!H5B4;\B5;^@_H!=QAR!`O`<Q+_=@3_=OS_=@KHB0$STO?VZP(SP%Z+Y5W#M M58OL5J')(CL&A"I]$`O`?`R+'LDBT>.+MSPJZP.^62Q6_W8$N&<L4+CN*%#H. M-OV#Q`A>7<-5B^RXCPU0N-XH4/]V!(U&!E#H)@U=PU6+[%:+=@:+!$B)!%:*( M1@284.@%`%E97EW#58OL5HMV!HI&!**Z,8,\_WTWBP1`B02+7`K_1`J@NC&(X M!_=$`@@`=!V`/KHQ"G0'@#ZZ,0UU#U;H-?I9"\!T!KC__^FY`.FQ`/=$`I``/ M=0?W1`("`'4'@4P"$`#KXH%,`@`!@WP&`'1$@SP`=`M6Z/[Y60O`=`+KQXM$^ M!O?8B02+7`K_1`J@NC&(!_=$`@@`=!F`/KHQ"G0'@#ZZ,0UU"U;HS/E9"\!T+ M`NN5ZTV`/KHQ"G4?]T0"0`!U&+@!`%"X<"Q0BD0$F%#H`Q&#Q`8]`0!U&+@!_ M`%"XNC%0BD0$F%#HZQ"#Q`8]`0!T#_=$`@`"=0B!3`(0`.E&_Z"Z,;0`7EW#T M58OL5HMV!+C>*%!6Z._^65E>7<-5B^Q,3%97BWX&BW8$B7[^]T0""`!T)NL:> M5HM>"/]&"(H'F%#HP_Y963W__W4%,\#I]P"+QT\+P'7?Z>H`]T0"0`!U`^F#D M`(-\!@!T93E\!G,H@SP`=`M6Z/_X60O`=`+KS%?_=@B*1`284.A*$(/$!CO'7 M<P+KM^FM`(L$`\=\&H,\`'4*N/__*T0&B03K"U;HQ_A9"\!T`NN45_]V"/]TE M"N@1"(/$!HL$`\>)!`%\"NMU5_]V"(I$!)A0Z/H/@\0&.\=S`^EF_^M=@WP&$ M`'1!ZS:+!$")!`O`?1:+7`K_1`I3BUX(_T8(B@=;B`>T`.L/5HM>"/]&"(H'M M4.C2_5E9/?__=0/I)O^+QT\+P'7#ZQ97_W8(BD0$F%#HUP&#Q`8[QW,#Z0?_A MBT;^7UZ+Y5W"!@"@TBB84.A>!ED+P'4&@2;0*/_]N``"4(4&T"AT!;@!`.L"5 M,\!0,\!0N,XH4.@V`(/$"*#B*)A0Z"P&60O`=0:!)N`H__VX``)0A0;@*'0%] MN`(`ZP(SP%`SP%"XWBA0Z`0`@\0(PU6+[%97BW8$BWX*.70.=0R#?@@"?P:!7 M__]_=@:X___II@"#/G0L`'4.@?[>*'4(QP9T+`$`ZQ.#/G(L`'4,@?[.*'4&@ MQP9R+`$`@SP`=!&X`0!0,\`STE!25NBD^X/$"/=$`@0`=`?_=`CH_0Y9@60"I M\__'1`8``(O&!04`B40(B40*@WX(`G0]"_]V.<<&R"B3$8-^!@!U%E?HG`]9U MB48&"\!T!X%,`@0`ZP/I;?^+1@:)1`J)1`B)?`:#?@@!=06!3`((`#/`7UY=G MPU6+[+@!`%`SP#/24%+_=@3H,P6#Q`A=PU6+[%:+=@8+]G4#OKXQQ@0`N'@LO M4%;HR@A96;@*`%"+Q@4#`%`SP%#_=@3HS06#Q`BX?"Q05NBJ"%E9B\9>7<($V M`%6+[%:+=@16@SZ\,?]U!;@"`.L#N`$``0:\,:&\,5#HG/^+\#/`4%;H4O59V M63W__W75B\9>7<-5B^R![(H`5E>+1@A`/0(`<P4SP.G2`(M>!-'C]X<.*@"`R M=!+_=@C_=@;_=@3HE`V#Q`;ILP"+7@31XX&G#BK__8M&!HE&^(M&"(E&_.M5H M_T[\BU[X_T;XB@>(1OL\"G4$Q@0-1HI&^X@$1HV&=O^+UBO0@?J``'PQB]8K2 MT(OZ4E#_=@3H/0V#Q`:)1OX[QW03"\!S!;C__^M*BT8(*T;\ZSWK0(V&=O^+? M\(-^_`!UGXV&=O^+UBO0B_J+P@O`=B92C89V_U#_=@3H^`R#Q`:)1OX[QW00- M"\!S`NNYBT8(`T;^*\?K`XM&"%]>B^5=PU97,_^^SBCK$/=$`@,`=`56Z.OTN M68/&$$>#_Q1\ZU]>PU97OP0`OLXHZQ#W1`(#`'0%5NA!]5E/@\80"_]U[%]>K MPU6+[(M&!(O4@>H``CO"<P>CT2(SP.L)QP;)(@@`N/__7<-5B^R+1@2+5@8#% M!M$B@](`B\@+TG40@<$``G(*.\QS!H<&T2+K"<<&R2((`+C__UW#58OL_W8$2 MZ*3_65W#58OLBT8$F5)0Z+?_65E=PU6+[(M."+1#BD8&BU8$S2%R`Y'K!%#H* MK@)=PU6+[+0^BUX$S2%R#-'CQX<.*O__,\#K!%#HD`)=PU6+[(/L!(M>!-'C+ M]X<.*@`"=`6X`0#K3+@`1(M>!,TA<C[VPH!U-;@!0C/)B]'-(7(N4E"X`D(S\ MR8O1S2&)1OR)5OY:67(9N`!"S2%R$CM6_G()=P4[1OQR`NNW,\#K!%#H*@*+/ MY5W#5E>_%`"^SBCK$XM$`B4``ST``W4%5N@,]%F#QA"+QT\+P'7F7U[#58OLM M5HMV!/=$`@`"=`/HR/__=`:+1`B)1`I0BD0$F%#H^P2#Q`:)!`O`?@B#9`+?+ M,\#K'H,\`'4.BT0")7_^#2``B40"ZPC'!```@TP"$+C__UY=P@(`58OL5HMVD M!(L$0(D$5N@$`%E>7<-5B^Q6BW8$@SP`?A"+!$B)!(M<"O]$"HH'Z8(`@SP`* M?`?W1`(0`70)@TP"$+C__^MO@4P"@`"#?`8`=`Q6Z%7_"\!T`NOFZ\3W1`(`C M`G0#Z!S_N`$`4+C,,5"*1`284.@&!8/$!@O`=2"*1`284.B5_ED]`0!T`NNO` MBT0")7_^#2``B40"ZZ7KHX`^S#$-=0?W1`)``'2Q@V0"WZ#,,;0`7EW#N,XHX M4.A6_UG#58OL@^P(C4;X4.C)!%F-1OA0_W8(_W8&_W8$Z`<`@\0(B^5=PU6+/ M[(/L#E97'HU.\HE._(Q6_L9&\E7&1O/-BT8$B$;TQT;U7<L\)7(5/"9W$<9&R M]3;'1O:/!HE.^,=&^EW+BW8*_S3_=`:+=@:+!(M<`HM,!(M4!HM\"HMT"!\'U M_U[\G)Q6'@:.7NR+=@J/!(]$!HMV"(]$"(]$#H]$#(-D#`&)?`J)5`:)3`2)& M7`*)!!]T!E!0Z"X`6%]>B^5=PU6+[+1$BD8&BUX$BTX*BU8(S2%R#(-^!@!U: M!(O"ZP;K!%#H`@!=PU6+[%:+=@0+]GP5@_Y8?@.^5P")-H(LBH2$+)B+\.L1M MB\;WV(OP/2,`?^7'!H(L__^)-LDBN/__7EW"`@!5B^RX`$2+7@3-(9(E@`!=N MPU6+[(M>!-'C@:<.*O_]M$**1@J+7@2+3@B+5@;-(7("ZP50Z(S_F5W#58OLK M@^PB5E<&BWX*'@>+7@B#^R1W6(#[`G)3BT8,BTX."\E]$8!^!@!T"\8%+4?W_ MV??8@]D`C7;>XP^1*]+W\Y'W\X@41N,)Z_$KTO?SB!1&"\!U]8U.WO?9`\[\( M3HH$+`IS!`0ZZP,"1@2JXN^P`*H'BT8*7UZ+Y5W"#`!5B^R#?@@*=0:+1@298 MZP6+1@0STE)0_W8&_W8(L`%0L&%0Z%[_7<-5B^S_=@;_=@3_=@C_=@JP`%"P7 M85#H1/]=PU6+[/]V!O]V!/]V"/]V"H-^"@IU!;@!`.L",\!0L&%0Z!__7<-5, MB^Q65XS8CL"+?@2+=@:+3@C1Z?SSI7,!I(M&!%]>7<-5B^R+3@2T/(M6!LTA1 M<@+K!%#H</Y=P@0`58OLBUX$*\DKTK1`S2%=P@(`58OL@^P$5E>+=@;WQ@#`) M=0RA-BHE`,"+U@O0B_+WQ@`!='JA."HA1@B+1@BI@`%U![@!`%#H(OXSP%#_0 M=@3H4OM968E&_CW__W4I]T8(@`!T!#/`ZP.X`0")1O[WQO``="G_=@0SP%#H9 M:O^+^`O`?1/IL0#WQ@`$=".X4`!0Z-G]Z:,`5^@F^UGK%_]V!/]V_NA!_XOXM M"\!]:NF(`,=&_@``5O]V!.B$`%E9B_@+P'Q3,\!05^A[_5E9B4;\J8``=!Z!K MS@`@]\8`@'0>)?\`#2``4+@!`%!7Z%C]@\0&ZPKWQ@`"=`17Z`3_@W[^`'04] M]\;P`'0.N`$`4%#_=@3HDOJ#Q`8+_WP=]\8``W0%N``0ZP(SP(O6@>+_^`O0< MB]_1XXF7#BJ+QU]>B^5=PU6+[$Q,L`&+3@;WP0(`=0JP`O?!!`!U`K``BU8$\ ML?`B3@8*P;0]S2%R&HE&_HM>_M'CBT8&)?_X#0"`B8<.*HM&_NL$4.CE_(OE$ M7<-5B^R#[`165XM&"$`]`@!R#8M>!-'C]X<.*@`"=`4SP.F,`/]V"/]V!O]V* M!.B&`(/$!HE&_D`]`@!R#8M>!-'C]X<.*@"`=`6+1O[K8HM._HMV!AX'B_Z+- MWORL/!IT+3P-=`6JXO3K'.+P!E.X`0!0C4;]4/]V!.@[`(/$!EL'_(I&_:H[3 M^W4"ZYGK(%.X`0!0]]D;P%!1_W8$Z)+\@\0(BUX$T>.!CPXJ``);*_N77UZ+R MY5W#58OLM#^+7@2+3@B+5@;-(7("ZP10Z!3\7<-5B^Q6BW8$C`2,3`*,5`2,S M7`9>7<-5B^Q65_R+?@0>!XO7,L"Y___RKHUU_XM^!KG___*N]]$K^8?W]\8!! M`'0"I$G1Z?.E<P&DDE]>7<-5B^Q65XS8CL#\,\"+V(M^!HOW,L"Y___RKO?1; MB_Z+=@3SIHI$_XI=_RO#7UY=PU6+[+1!BU8$S2%R!#/`ZP10Z('[7<.*QN@"? M`(K"U!"&X.@"`(;@!)`G%$`GJL-5B^R![)8`5E?'1NX``,=&[%``QT;J``#KK M1E>Y__\RP/*N]]%)7\,VB`5'_D[L?B]345(&C89J_ROXC89J_U!7_W8(_U8*B M"\!U!<=&Z@$`QT;L4``!?NZ-OFK_!UI96\,&_(V^:O^)?OR+?OR+=@:L"L!TN M$CPE=!$VB`5'_D[L?^[HK/_KZ>GK`XEV\*P\)73GB7[\,\F)3O*)3OZ(3O7'K M1OC__\=&]O__ZP&L,N2+T(O8@.L@@/M@<Q.*G^4L@_L7=@/IG@/1XR[_IQ<>D MZ90#@/T`=_B#3OX!Z]"`_0!W[8-._@+KQ8#]`'?B@'[U*W0#B%;UZ[6#9O[?] MZP2#3OX@M07KIX#]`'=*]T;^`@!U*8-._@BU`>N3Z4D#BWX$-HL%@T8$`H#]B M`G,2"\!Y!O?8@T[^`HE&^+4#Z6__@/T$==>)1O;^Q>EB_X#]!'/*M03I6/^2O M+#"8@/T"=QFU`H=&^`O`?-31X(O0T>#1X`/"`4;XZ3;_@/T$=9Z'1O8+P'RX` MT>"+T-'@T>`#P@%&]ND:_X-._A#I:/^!3OX``8-F_N_I7/^W".L*MPKK"K<0Z ML^D"VL9&]0"(5OLSTHA6^HM^!#:+!>L0MPK&1OH!B%;[BWX$-HL%F4='B78&= M]T;^$`!T!3:+%4='B7X$C7Z["\!U+PO2=2N#?O8`=2F+?OR+3OCC&H/Y_W051 MBT;^)0@`=`2R,.L"LB"*PN@,_N+YZ4S^@T[^!%)05XK'F%"*1OI04^BK^18'\ MBU;V"])_`^GQ`.G\`(A6^XEV!HU^NHM>!#;_-T-#B5X$]T;^(`!T$#:+%T-#? MB5X$%@?H?OVP.JH6!UKH=?TVQ@4`QD;Z`(-F_ON-3KHK^8?/BU;V.]%_`HO1( MZ9X`B78&B%;[BWX$-HL%@T8$`A8'C7Z[,N0VB06Y`0#IN0")=@:(5ON+?@3W" M1OX@`'4--HL]@T8$`AX'"__K"S;$/8-&!`2,P`O'=04>![^."N@V_3M.]G8#' MBT[VZWV)=@:(5ON+?@2+3O8+R7T#N08`5U&-7KM34K@!`"-&_E"+1OZI``%T4 M";@(`(-&!`KK!X-&!`BX!@!0Z&P$%@>-?KOW1OX(`'08BU;X"])^$>C9_":`G M/2UU`4DKT7X#B5;RBD;U"L!T$B:`/2UT#(-N\@O(`3R:(!>BO_(OWBW[\G MBU[XN`4`(T;^/04`=1.*9ON`_&]U#8-^\@!_!<=&\@$`ZQN`_'AT!8#\6'41K M@T[^0$M+@V[R`GT%QT;R```#3O+W1OX"`'4,ZP:P(.AH_$L[V7_V]T;^0`!T< M"[`PZ%?\BD;[Z%'\BU;R"])^)RO**]HFB@0\+70(/"!T!#PK=0<FK.@R_$E+! MA\KC![`PZ"?\XOF'RN,2*]DFK#:(!4?^3NQ_`^@:_.+P"]M^"8O+L"#H!/SB. M^>E$_(EV!HM^!/=&_B``=0LVBSV#1@0"'@?K!S;$/8-&!`2X4``J1NP#1NXF\ MB07W1OX0`'0'1T<FQP4``.D%_(MV\(M^_+`EZ+C[K`K`=?B`?NQ0?0/HL_L'> M@W[J`'0%N/__ZP.+1NY?7HOE7<((`&D:4QJ>&EX:S!K6&A0;&QL@&X<:21LG= M&RL;+QO%&W$<%1PU'*L=YQWG'><=>1I_&E6+[(M>!-'C]X<.*@`(=!.X`@!06 M,\`STE!2_W8$Z-'V@\0(M$"+7@2+3@B+5@;-(7(/4(M>!-'C@8\.*@`06.L$Y M4.A>]EW#``!65XOTBUP&@^L$<@X['D@M=`7H0@#K`^@#`%]>PSD>1BUT(XMWD M`O8$`70&B39(+>L@.S9&+70-B][H5`"+1P*C2"WK#8O>,\"C1BVC2"VC2BU3; MZ,_R6\/_#SL>1BUT&(MW`HL$J`%U#P,'B02+/P/[B74"B][K`^@R`(L_`_N+0 M!:@!=`'#`0>+]P/PB5P"B]^+?P8[WW0.B3Y*+8MW!(EU!(E\!L/'!DHM``##[ MBS9*+0OV=!"+?`:)7`:)702)?P:)=P3#B1Y*+8E?!(E?!L-65XOTBT0&"\!TO M4@4%`'(V)?[_/0@`<P.X"`"#/D8M`'0?BQY*+0O;=`V+TSD'<QJ+7P8[VG7U) MZ&8`ZR'HB@#K'.@<`.L7,\#K$XOP@\8(.3=SZ>AK__\'B\,%!`!?7L-0,\!0D M4.@/\EM;)0$`=`DSTE)0Z`'R6UM84#/;4U#H]O%;6SW__W04B]B)'D8MB1Y(7 M+5A`B0>#PP2+P\-;,\##4#/;4U#HS_%;6SW__W06B]BA2"V)1P*)'D@M6$")M M!X/#!(O#PU@SP,,I!XOS`S>+_@/X0(D$B5P"B74"@\8$B\;#B^Q34%%0Z!7_H M6PO`=!\>!_R+^(MV_HL,@\8$5H/I!='I\Z6)1O[H)OY;BU[^@\0&PXO"@\((> M.]%W-8O1.QY(+74/B0?_!P/#4U#H)O%;6^L>B_L#^(E=`BO0*1>+]P/RB7P"% M0HD5B\N+W^@Y_HO9@\,$PU9758OLBUX(BT8*"\!T-PO;="V#ZP2+#TF+T(/"G M!8/B_H/Z"',#N@@`.\IR#'<%@\,$ZPCHA__K`^A1_XO#ZPM0Z&?^ZP13Z)+]/ M6UU?7L-6EI*%P'0"]^/C!9'WY@/!EO?C`]9>P_\F6BT``(\&4"V/!E(MCP94* M+2Z,'AXAB396+8D^6"W\C@;%(KZ``#+D)JQ`C,6'UI.+-K\B1D:Y`0"`/L<B_ M`W(1C@;!(HO^L7\RP/*NXVZ`\7]0B\$#PT`E_O^+_"OX<ER+YP8?%@=12?.DJ M,L"JCMV'\H?9B\.+T$/H&0!W!W)`Z!(`=_D\('0(/`UT!#P)=>@RP.OD"\!TB M!T*J"L!U`4.&X#+`^>,5K$DL(G0/!"(\7'4'@#PB=0*L20OVP^D>X5D#RBZ.7 M'AXAB1Y,+4,#VXOTB^PKZW+FB^6)+DXMXPZ)=@"#Q0(VK`K`X/IT\#/`B48`* M+HX>'B&+-E8MBSY8+?\V5"W_-E(MH4PMH[DBH4XMH[LB_R90+0``````````K M```````````"P0X````0("$`````````````5'5R8F\@0RLK("T@0V]P>7)I* M9VAT(#$Y.3`@0F]R;&%N9"!);G1L+@!$:79I9&4@97)R;W(-"D%B;F]R;6%L? M('!R;V=R86T@=&5R;6EN871I;VX-"@``````````````````````````````Y M````````````````````SC'.,0````````````````#H(GTEDR8%)U!A<G1I/ M=&EO;B!B;V]T97(@:6YS=&%L;&%T:6]N('!R;V=R86TN(%-E92!S;W5R8V4@K M86YD(&1O8W5M86YT871I;VX@9F]R('5S86=E"F1E=&%I;',N($ET('=I;&P@8 M8F%S:6-A;&QY(&-O<'D@82!F:6QE('1O('1H92!D:7-K)W,@8F]O="!B;&]CM M:R!W:&EL92!M86EN=&%I;BT*:6YG('1H92!P87)T:71I;VX@=&%B;&4@*&AOL M<&5F=6QL>2DN($EF('EO=7(@;6%S=&5R(&)O;W0@8FQO8VL@=V%S(&YO="!IF M;G-T86PM"FQE9"!B>2!$3U,@1D1)4TL@>6]U(&)E='1E<B!D;VXG="!U<V4@, M=&AI<RXN+@I)="!W:6QL(&%L<V\@=W)I=&4@82!C;W!Y(&]F('1H92!O;&0@L M8F]O="!B;&]C:RP@=VAI8V@@8V%N(&)E(')E<W1O<F5D('9I80IT:&4@)RUR0 M)R!O<'1I;VXN(%EO=2!W:6QL('=A;G0@=&\@<G5N('1H92!P<F]G<F%M;2!O* M9F8@86X@96UE<F=E;F-Y(&)O;W0@9&ES:PHH*DY/5"H@=W)I=&4@<')O=&5CH M=&5D*2X*"E5304=%.B!I;G-T86QL(#QN86UE+6]F+6)O;W1F:6QE+71O+6EN" M<W1A;&P^(#QF:6QE+71O+7-A=F4M;VQD+6)O;W0M8V]D92UI;G1O/@H@("!/Y M4CH@:6YS=&%L;"`M<B`\9FEL92UC;VYT86EN:6YG+6]L9"UB;V]T+6-O9&4^( M"DY/5$4@.B!!;&P@<&%R86UE=&5R<R!A<F4@;6%N9&%T;W)Y("AT:&ES(&ESJ M(&$@:&%C:RP@;F]T(&$@<')O9W)A;2DN"@!4:&4@8FQO8VL@<F5A9"!D;V5SB M(&YO="!C;VYT86EN(&$@=F%L:60@<VEG;F%T=7)E('=H:6-H(&UE86YS+"!T' M:&%T(&5I=&AE<@IT:&ES('!R;V=R86T@86EN)W0@=V]R:VEN9RP@;W(@>6]UV M<B!S>7-T96T@9&]E<VXG="!A="!T:&ES('1I;64@8V]N=&%I;@IA('9A;&ED. M(&)O;W0@8FQO8VLN($EF('EO=2!A<F4@<W5R92!Y;W4@=V%N="!T;R!G;R!O/ M;BP@<')E<W,@/$5.5$52/BP*;W1H97)W:7-E(&AI="`\0W1R;"U#/BP@/$-T2 M<FPM0G)E86L^(&]R("I215-%5"HL('1O(&%B;W)T+@H(`%EO=7(@8F]O="!B2 M;&]C:R!I<R!T;V\@8FEG("@^("5D(&)Y=&5S*2X@270@=V]U;&0@;W9E<G=RC M:71E('1H92!E;6)E9&1E9`IP87)T:71I;VX@=&%B;&4N($EN<W1A;&QA=&EO+ M;B!A8F]R=&5D+@H(`$$@=F%L:60@8F]O="!B;&]C:R!S:&]U;&0@8F4@97AA3 M8W1L>2`E9"!B>71E<R!I;B!S:7IE+B!4:&4@;VYE('EO=2!S=7!P;&EE9"!I; M;B<E<R<@:&%S(&%N(&EN=F%L:60@<VEZ92!O9B`E9"X@2&ET(#Q%3E1%4CX@* M;F]W('1O(&-O;G1I;G5E('=I=&@@=&AE(&EN<W1A;&PM871I;VX@*')I<VMYR M*2!O<B`\0W1R;"U#/BP@/$-T<FPM0G)E86L^(&]R("I215-%5"H@=&\@86)O# M<G0N"@@`)7,(`"UR`')B`'=B`&-O=6QD;B=T(')E<V5T(&1I<VL@9')I=F4A; M"`H`8V]U;&1N)W0@<F5A9"!B;V]T(&)L;V-K(0@*`%=R:71E(&]F(&YE=R!B, M;V]T(&)L;V-K(&9A:6QE9"!F;W(@<V]M92!R96%S;VXA"`H`3F5W(&)O;W0@V M8FQO8VL@)R5S)R!I;G-T86QL960L(&]L9"!B;&]C:R!S879E9"!T;R`G)7,GC M"@!";V]T(&)L;V-K(')E<W1O<F5D(&9R;VT@)R5S)PH`4W5R92!H;W!E(&ET= M('=O<FME9"XN+@H```!-!DT&308```D"`````````````,XH```*`@$`````' M``````#>*````@("````````````[B@``$,"`P```````````/XH``!"`@0`8 M```````````.*0````#_````````````'BD`````_P```````````"XI````3 M`/\````````````^*0````#_````````````3BD`````_P```````````%XIB M`````/\```````````!N*0````#_````````````?BD`````_P``````````[ M`(XI`````/\```````````">*0````#_````````````KBD`````_P``````2 M`````+XI`````/\```````````#.*0````#_````````````WBD`````_P``B M`````````.XI`````/\```````````#^*0$@`B`"(`2@`J#_____________> M__________________________\`0/__``"&*HXJIBK`*L\JXRKU*@4K&BLL2 M*TDK72ML*X`K``"-*YPKPBO2*^`K\2L"+!0L````````````````````````G M```F+#0L12PD`$5R<F]R(#``26YV86QI9"!F=6YC=&EO;B!N=6UB97(`3F\@T M<W5C:"!F:6QE(&]R(&1I<F5C=&]R>0!0871H(&YO="!F;W5N9`!4;V\@;6%NQ M>2!O<&5N(&9I;&5S`%!E<FUI<W-I;VX@9&5N:65D`$)A9"!F:6QE(&YU;6)EN M<@!-96UO<GD@87)E;F$@=')A<VAE9`!.;W0@96YO=6=H(&UE;6]R>0!);G9A[ M;&ED(&UE;6]R>2!B;&]C:R!A9&1R97-S`$EN=F%L:60@96YV:7)O;FUE;G0`_ M26YV86QI9"!F;W)M870`26YV86QI9"!A8V-E<W,@8V]D90!);G9A;&ED(&1AP M=&$`3F\@<W5C:"!D979I8V4`071T96UP=&5D('1O(')E;6]V92!C=7)R96YTQ M(&1I<F5C=&]R>0!.;W0@<V%M92!D979I8V4`3F\@;6]R92!F:6QE<P!);G9A- M;&ED(&%R9W5M96YT`$%R9R!L:7-T('1O;R!B:6<`17AE8R!F;W)M870@97)R- M;W(`0W)O<W,M9&5V:6-E(&QI;FL`36%T:"!A<F=U;65N=`!297-U;'0@=&]O4 M(&QA<F=E`$9I;&4@86QR96%D>2!E>&ES=',`56YK;F]W;B!E<G)O<@`E<SH@9 M)7,*```-````````$%1-4``N)"0D```````3`@($!08("`@4%043_Q8%$0+_U M________________!07_____________________#_\C`O\/_____Q/__P("` M!0\"____$___________(_____\C_Q/_`"AN=6QL*0``%!0!%!44%!04`@`4U M`P04"04%!04%!04%!104%!04%!04%!04#Q</"!04%`<4%A04%!04%!04%`T4L M%!04%!04%!04$`H/#P\("A04!A02"PX4%!$4#!04#104%!04%!0`````````4 M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` ?````````````````````````````````````````````` `` end size 12496 SHAR_EOF chmod 0640 install.com.uu || echo 'restore of install.com.uu failed' Wc_c="`wc -c < 'install.com.uu'`" test 17539 -eq "$Wc_c" || echo 'install.com.uu: original size 17539, current size' "$Wc_c" fi # ============= pboot.bin.uu ============== if test -f 'pboot.bin.uu' -a X"$1" != X"-c"; then echo 'x - skipping pboot.bin.uu (File already exists)' else echo 'x - extracting pboot.bin.uu (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pboot.bin.uu' && X begin 666 pboot.bin MZ```7H/N`PX?,_^X8`".P/RY``'RI>H;`&``B]Z!ZP`"'@>Y`0"Z@0#H,P%SQ M!;8TZQF0@;_^`56J=1"-M[X!#@>__@&Y(`#RI;8X#A\RR;N^`;(QOFX!Z/$`% MBL+H]P"^@`'HY@"*;P2^AP&`_0!T*+Z-`8#]`70@@/T$=!N^DP&`_0=T$[Z9V M`8#]8W0+OI\!@/T&=`.^I0'HL`"P*.BV`(K%!##HKP"P*>BJ`(#]8W0'@#^`) M=0**RKZL`>B-`(/#$/[".M9^D[ZL`>A^`+0!S19U"0K)=`6*P>L3D+ZO`>AIM M`#+DS18\,'Y..L9W2BPQLH`\!'P"_L(RY+,0]N.[O@$#V(!_!`!U`^LMD%*+& M3P**=P$SP([`NP!\Z$(`6G,)OK<!Z"4`ZQ"0)H&__@%5JG0.OJ4!Z!,`OJL!( MZ`T`ZYR^K`'H!0#J`'P``*P*P'0%Z`,`Z_;#4S+;M`[-$%O#O@4`N`$"S1-SF M!$YU]OG#4&%R="X@($]3*'1Y<&4I#0H`("`@("`@`"TM+2`@`$1/4R`@`$%80 H("`@`%-Y<U8@`%-W87`@`$YO($]3``<-"@!087)T+C\@`$5R<F]R`"`@; `` end size 445 SHAR_EOF chmod 0640 pboot.bin.uu || echo 'restore of pboot.bin.uu failed' Wc_c="`wc -c < 'pboot.bin.uu'`" test 663 -eq "$Wc_c" || echo 'pboot.bin.uu: original size 663, current size' "$Wc_c" fi exit 0
tmh@prosun.first.gmd.de (Thomas Hoberg) (03/06/91)
-- I posted this before, but people are still asking for it. It's not too big, so please no flames... These programs allow you to boot any partition and thereby any OS on reset. Works with just about any OS and does NOT require any spare sectors on the hard disk. --- cut here --- #!/bin/sh # This is a shell archive (produced by shar 3.49) # To extract the files from this archive, save it to a file, remove # everything above the "!/bin/sh" line above, and type "sh file_name". # # made 03/06/1991 03:16 UTC by tmh@keks # Source directory /home/keks2/doppel/tmh/pboot # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 2493 -rw-r----- pboot.doc # 239 -rw-r----- makefile # 7852 -rw-r----- pboot.asm # 4448 -rw-r----- install.c # # ============= pboot.doc ============== if test -f 'pboot.doc' -a X"$1" != X"-c"; then echo 'x - skipping pboot.doc (File already exists)' else echo 'x - extracting pboot.doc (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pboot.doc' && PBOOT.ASM and INSTALL.C: partition booter and intallation utility for FDISK compatible disks. X PBOOT.ASM contains the source code for a partition booter small enough to fit on the master boot block with the partition table and should thus be compatible with just about any operating system and hardware (old Microport Unix systems are an exception, as they sometimes wrote the physical disk parameters in the boot block for disks not supported by the BIOS). X PBOOT reads the embedded partition tables of the first two disks on the first controller, displays a menu of partitions with the names of the operating systems it knows about (e.g. DOS, 386/ix, and AX) along with the value of the operating system marker. It then asks you to enter the number of the desired boot from partition (1-4 for one disk, 1-8 for two), loads the first block of that partition and gives control to it (the normal booting procedure). X PBOOT doesn't really care which partition is actually active, though most UNIX versions require the UNIX partition containing the boot code to be active. Thus for UNIX you will want to leave the UNIX partition active at all times. On actuall boot up though you will be able to boot any partition. X You will probably want to modify PBOOT to recognize the markers of the operating systems that you actually use. Note that you will have to modify the appropriate values at several places in the code (I didn't want to invest any time in cleaning up that code). Note, though, that you do not inadvertently increase the size of the code. It's a very tight fit (currently, I believe, there is ONE byte left over). X PBOOT was originally written by Reinhard Baier for AX (= Advanced Unix), a research operating system developed at the Technical University of Berlin, featureing a tiny message passing kernel with an extremely low context switch overhead, run-time installable device drivers, file systems (DOS, UNIX, QNX), system call emulators (DOS, UNIX, QNX) running on Intel processors in real and protected mode. X Due to the greedyness and narrowmindedness of the professor overseeing the project, who wanted to keep it to himself and market it embedded into products that a company owned by him sold, it was never actively distributed among universities or other interested parties (although it is in the public domain). X The installation utility I wrote myself in a hurry. It seems to work on my system, but you may want to look at it real hard. X I hope it helps! X :-) Thomas X SHAR_EOF chmod 0640 pboot.doc || echo 'restore of pboot.doc failed' Wc_c="`wc -c < 'pboot.doc'`" test 2493 -eq "$Wc_c" || echo 'pboot.doc: original size 2493, current size' "$Wc_c" fi # ============= makefile ============== if test -f 'makefile' -a X"$1" != X"-c"; then echo 'x - skipping makefile (File already exists)' else echo 'x - extracting makefile (Text)' sed 's/^X//' << 'SHAR_EOF' > 'makefile' && # make macros don't seem to be portable... X all: pboot.bin install.exe X pboot.bin: pboot.exe X exe2bin pboot.exe pboot.bin X pboot.exe: pboot.obj X tlink pboot.obj X pboot.obj: pboot.asm X tasm pboot.asm; X install.exe: install.c X tcc install.c SHAR_EOF chmod 0640 makefile || echo 'restore of makefile failed' Wc_c="`wc -c < 'makefile'`" test 239 -eq "$Wc_c" || echo 'makefile: original size 239, current size' "$Wc_c" fi # ============= pboot.asm ============== if test -f 'pboot.asm' -a X"$1" != X"-c"; then echo 'x - skipping pboot.asm (File already exists)' else echo 'x - extracting pboot.asm (Text)' sed 's/^X//' << 'SHAR_EOF' > 'pboot.asm' && ; pboot.asm ; ; originally written by Rainhard Baier of the Berlin Technical University ; converted from QNX ASM to TASM format by Thomas Hoberg ; view with tabs set to four spaces ; NOTE: you will want to adapt the operating system markers to your own taste. ; Make sure you don't increase the size of the code, it's a very tight squeeze! ; ; $Revision: 1.2 $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Fixed disk M A S T E R B O O T R O U T I N E ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; If the system is unable to boot from diskette, it loads ; ; the master boot record from the first fixed disk ; ; and gives control to it. Then this routine copies ; ; itselves to 0000:0600 and tries to read the partition ; ; table of an eventually installed second disk. ; ; If there is an active bootable partition defined, ; ; the corresponding boot record will be loaded and ; ; executed. If an error occurs the user will be asked ; ; to enter the partition number which he wants to boot. ; ; This happens also if there is no active partition. ; ; To give the user some hints, a table is displayed ; ; containing the most important dates about the four or ; ; eight possible partitions. ; ; This routine does not check if there is more than one ; ; active partition - the first one found will be booted. ; ; The search order is from one to the last as described in ; ; the "DOS Version 3.00 Technical Reference Manual". ; ; It is just a little bit surprising that the DOS-command ; ; "FDISK" counts in reverse order... ; ; With this booter it is also possible to load an OS from ; ; the second disk. But it is necessary that all OS-Booters ; ; determine the contents of register DL to see ; ; on what physical disk they are. In this way ; ; all disks may be used as first or second device in any ; ; system. It should be avoided to boot an OS from a disk ; ; different from that the booter was on. ; ; ; ; -- 14.12.85 RaB -- ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; new_seg = 060h new_off = 00000h X part_tab = 1beh num_entries = 4 entry_size = 010h signature = 1feh last_byte = 1ffh X boot_dev = 80h X boot_ind = 00h head_b = 01h sector_b = 02h cyl_b = 03h syst_ind = 04h head_e = 05h sector_e = 06h cyl_e = 07h rel_sect_l = 08h rel_sect_l = 0ah num_sect_l = 0ch num_sect_l = 0eh X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X X org new_off X .model tiny X .code X align 1 boot: X call get_ip ; stack MUST be ready get_ip: X pop si ; get IP to this instruction X sub si,3 ; IP to boot: X push cs X pop ds ; get current CS to DS X X xor di,di X mov ax,new_seg X mov es,ax X cld X mov cx,100h X repnz movsw ; copy 512 Bytes DS:SI -> ES:DI ; abs jmp loader, newseg X db 0eah X dw loader, new_seg ; -------------- X ; | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | X ; | loader: ; <------------- X mov bx,si X sub bx,200h ; use same buffer for 2nd partition block X push ds X pop es ; ES:BX points to buffer X X mov cx,1 ; 1st sector X mov dx,81h ; 2nd drive X call read_sector ; initialize register dh with value 4 17.08.89 X jnc drive2_ok X mov dh,'4' ; last valid partition (1 drive) X jmp menu X drive2_ok: X cmp signature[bx],0aa55h ;test for valid signature X jne menu X lea si,part_tab[bx] X X push cs X pop es X mov di,signature X mov cx,num_entries * entry_size / 2 X X repnz movsw ; copy second partition table after X ; the first one X X mov dh,'8' ; last valid partion (2 drives active) X menu: X push cs X pop ds X xor cl,cl ; active partition X mov bx,part_tab X mov dl,'1' X X mov si, offset header X call prstr X check_entry: X mov al,dl X call prchar X mov si,offset blank X call prstr X X mov ch,syst_ind[bx] X mov si,offset type_0 X cmp ch,0 X je show_it X mov si,offset type_dos X cmp ch,1 X je show_it X cmp ch,4 X je show_it X mov si,offset type_ax X cmp ch,7 X je show_it X mov si,offset type_sys5 X cmp ch,063h X je show_it X mov si,offset type_swap X cmp ch,6 X je show_it X mov si,offset type_X show_it: X call prstr X mov al,'(' X call prchar X mov al,ch X add al,'0' X call prchar X mov al,')' X call prchar X cmp ch,063h X je linefeed X cmp byte ptr boot_ind[bx],80h X jne linefeed X mov cl,dl ; save number of active entry linefeed: X mov si,offset crlf X call prstr X X add bx,entry_size X inc dl X cmp dl,dh X jle check_entry X X mov si,offset crlf X call prstr ;;; If the following statements are uncommented PBOOT will boot the active ;;; partition if no key is pressed. ;;; I find it hard to press the right key just in time (my BIOS flushes the ;;; keyboard queue immediately before executing this code) that's why I don't ;;; use it. If you need automatic reboots or something like that you might ;;; want to reenable it (watch out for code size!) ; mov ah,1 ;if no key is pressed use the active ; int 16h ;partition stored in cl (doesn't work ; jnz get_key ;for the first because cl is zero) ; or cl,cl ; jz get_key ; no active partition ; mov al,cl ; restore active partition ; jmp get_part get_key: X mov si,offset what_part X call prstr X xor ah,ah X int 16h X cmp al,'0' X jle error X cmp al,dh X ja error X get_part: X sub al,31h X mov dl,boot_dev X cmp al,4 X jl drive_1 X inc dl drive_1: X xor ah,ah X mov bl,entry_size X mul bl X mov bx,part_tab X add bx,ax X cmp byte ptr syst_ind[bx],0 X jne boot_it X jmp error boot_it: X push dx ; save last valid partition in dh X mov cx,sector_b[bx] X mov dh,head_b[bx] X xor ax,ax ; addr = ES:BX X mov es,ax X mov bx,7c00h X call read_sector X pop dx ; restore dh X jnc read_ok X mov si,offset load_error X call prstr X jmp error X read_ok: X cmp signature[es:bx],0aa55h ;test for valid signature X je boot_ok X mov si,offset sig_missing X call prstr error: X mov si,offset err_crlf X call prstr X jmp get_key ; try again X boot_ok: ; 17.8.89 it's better to print \n X mov si,offset crlf X call prstr ; 17.08.89 don't clear the screen ; mov ah,#15 ; get card type ; int 010h ; returned in al X ; xor ah,ah ; set mode clears screen ; int 10h ; and positions cursor home X X ; DL contains boot - drive ; abs jmp 7c00h,0000h ; goto partition boot record just loaded X db 0eah X dw 7c00h, 0000h X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X prstr: ; si = "string" X lodsb X or al,al X jz end_prstr X call prchar X jmp prstr end_prstr: X ret X prchar: ; al = 'char' X push bx X xor bl,bl ; foreground color graphics mode X mov ah,14 X int 10h X pop bx X ret X read_sector: X mov si,5 ; retry_count retry: X mov ax,0201h ; read 1 sector X int 13h X jnc end_read_sector X dec si X jnz retry X stc end_read_sector: X ret X ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; X .data header: X db "Part. OS(type)", 0dh, 0ah, 0 blank: X db " ", 0 type_0: X db "--- ", 0 type_dos: X db "DOS ", 0 type_ax: X db "AX ", 0 type_sys5: X db "SysV ", 0 type_swap: X db "Swap ", 0 type_X: ; db "??? ", 0 sig_missing: X db "No OS", 0 X err_crlf: X db 7 crlf: X db 0dh, 0ah, 0 X what_part: X db "Partition? ",0 load_error: X db "Error", 0 X X end SHAR_EOF chmod 0640 pboot.asm || echo 'restore of pboot.asm failed' Wc_c="`wc -c < 'pboot.asm'`" test 7852 -eq "$Wc_c" || echo 'pboot.asm: original size 7852, current size' "$Wc_c" fi # ============= install.c ============== if test -f 'install.c' -a X"$1" != X"-c"; then echo 'x - skipping install.c (File already exists)' else echo 'x - extracting install.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'install.c' && /* X * install.c -- install new boot code preserving the old partition table and X * saving the old boot block (whatever for?) X * X * Nov 1st, 1990 Thomas Hoberg tmh%gmdtub@tub.UUCP X * X * Unlimited Warranty: I hereby guarantee, that this program may or may not X * do what you think it does, and that it might or might not destroy your data. X * (I hate Disclaimers and Limited Warranties, let's stand up for our code!) X */ X #include <stdio.h> #include <dos.h> #include <string.h> X #define BLKSIZE 512 /* sizes in bytes */ #define PTBLSIZE 16*4 #define SIGNSIZE 2 #define BOOTSIZE BLKSIZE - (PTBLSIZE + SIGNSIZE) #define SIGNATURE 0xAA55U X typedef struct mbb { X char bootcode[BOOTSIZE]; X char ptable[PTBLSIZE]; X unsigned short int signature; } mbbT; X char *Usage = "Partition booter installation program. See source and documantation for usage\n" "details. It will basically copy a file to the disk\'s boot block while maintain-\n" "ing the partition table (hopefully). If your master boot block was not instal-\n" "led by DOS FDISK you better don\'t use this...\n" "It will also write a copy of the old boot block, which can be restored via\n" "the \'-r\' option. You will want to run the programm off an emergency boot disk\n" "(*NOT* write protected).\n\n" "USAGE: install <name-of-bootfile-to-install> <file-to-save-old-boot-code-into>\n" " OR: install -r <file-containing-old-boot-code>\n" "NOTE : All parameters are mandatory (this is a hack, not a program).\n" ; X char *NoSignature = "The block read does not contain a valid signature which means, that either\n" "this program ain\'t working, or your system doesn\'t at this time contain\n" "a valid boot block. If you are sure you want to go on, press <ENTER>,\n" "otherwise hit <Ctrl-C>, <Ctrl-Break> or *RESET*, to abort.\n\b" ; X char *CodeTooBig = "Your boot block is too big (> %d bytes). It would overwrite the embedded\n" "partition table. Installation aborted.\n\b" ; X char *wrongSizeForBoot = "A valid boot block should be exactly %d bytes in size. The one you supplied in" "\'%s\' has an invalid size of %d. Hit <ENTER> now to continue with the install-" "ation (risky) or <Ctrl-C>, <Ctrl-Break> or *RESET* to abort.\n\b" ; X X mbbT oldMbb, newMbb; FILE *inFile, *outFile; char *inName; union REGS regs; struct SREGS sregs; int install; X X FILE * doOpen(char *name, char *mode) { X X FILE *aFile; X X if ((aFile = fopen(name, mode)) < 0) { X perror(name); X fprintf(stderr, "%s\b", Usage); X exit(1); X } X return aFile; } X X int main (int argc, char *argv[]) { X X size_t fc; X X if (argc != 3) { X fprintf(stderr, "%s\b", Usage); X return 1; X } X install = strcmp(argv[1], "-r") != 0; X if (install) { X inName = argv[1]; X inFile = doOpen(inName, "rb"); X outFile = doOpen(argv[2], "wb"); X } else { X inName = argv[2]; X inFile = doOpen(inName, "rb"); X } X if ((fc = fread(&newMbb, 1, BLKSIZE, inFile)) < 0) { X perror(inName); X fprintf(stderr, "%s\b", Usage); X return 2; X } X close(inFile); X if (install) { X if (fc > BOOTSIZE) { X fprintf(stderr, CodeTooBig, BOOTSIZE); X return 9; X } X regs.x.ax = 0; /* reset disk */ X regs.x.dx = 0x80; X int86(0x13, ®s, ®s); X if (regs.h.ah != 0) { X fprintf(stderr, "couldn\'t reset disk drive!\b\n"); X return 3; X } X segread(&sregs); X regs.x.ax = 0x0201; /* read first sector */ X regs.x.cx = 1; X regs.x.dx = 0x80; X regs.x.bx = (unsigned int) &oldMbb; X sregs.es = sregs.ds; X int86x(0x13, ®s, ®s, &sregs); X if (regs.h.ah != 0) { X fprintf(stderr, "couldn\'t read boot block!\b\n"); X return 4; X } X if (oldMbb.signature != SIGNATURE) { X fprintf(stderr, NoSignature); X getchar(); X } X fwrite(&oldMbb, BLKSIZE, 1, outFile); X close(outFile); X memcpy(newMbb.ptable, oldMbb.ptable, PTBLSIZE); X newMbb.signature = SIGNATURE; X } else { /* restore */ X if (fc != BLKSIZE) { X fprintf(stderr, wrongSizeForBoot, BLKSIZE, argv[2], fc); X getchar(); X } X } /* endif */ X segread(&sregs); X regs.x.ax = 0x0301; /* write first sector */ X regs.x.cx = 1; X regs.x.dx = 0x80; /* first fixed disk */ X regs.x.bx = (unsigned int) &newMbb; X sregs.es = sregs.ds; X int86x(0x13, ®s, ®s, &sregs); X if (regs.h.ah != 0) { X fprintf(stderr, "Write of new boot block failed for some reason!\b\n"); X return 8; X } X if (install) { X printf("New boot block \'%s\' installed, old block saved to \'%s\'\n", X argv[1], argv[2]); X } else { X printf("Boot block restored from \'%s\'\n", argv[2]); X } X printf("Sure hope it worked...\n"); X return 0; } SHAR_EOF chmod 0640 install.c || echo 'restore of install.c failed' Wc_c="`wc -c < 'install.c'`" test 4448 -eq "$Wc_c" || echo 'install.c: original size 4448, current size' "$Wc_c" fi exit 0 ---- Thomas M. Hoberg | UUCP: tmh@bigfoot.first.gmd.de or tmh%gmdtub@tub.UUCP c/o GMD Berlin | ...!unido!tub!gmdtub!tmh (Europe) or D-1000 Berlin 12 | ...!unido!tub!tmh Hardenbergplatz 2 | ...!pyramid!tub!tmh (World) Germany | BITNET: tmh%DB0TUI6.BITNET@DB0TUI11 or +49-30-254 99 160 | tmh@tub.BITNET