home *** CD-ROM | disk | FTP | other *** search
- /* >>> this is file LOADLINX.C
- compile it with TURBO-C in large model
- ============================================================================
- LOADLIN v1.4 (C) 1994 Hans Lermen (lermen@elserv.ffm.fgan.de)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ----------------------------------------------------------------------------
- Comments and bug reports are welcome and may be sent to:
- E-Mail: lermen@elserv.ffm.fgan.de
- SnailMail: Hans Lermen
- Am Muehlenweg 38
- D53424 REMAGEN-Unkelbach
- GERMANY
-
- ============================================================================
-
- This program has to be used as a "preprocessor" for LOADLIN,
- it does translation of DOSish drive numbering (C:,D:...)
- to Linux device names (/dev/...).
- In addition to "root=X:" LOADLINX accepts the same parameters as LOADLIN
- and passes them to it.
- But translation is NOT supported for parameter files (@param).
- === ========= ======
- It can even be executed via shell= in CONFIG.SYS, but must reside
- in the same directory, where LOADLIN is located.
-
- Jacques Gelinas (jacques@solucorp.qc.ca) is the author of this
- algorithm ( I just implemented and enhanced it for LOADLIN
- and adapted it to the exact behavior of DOS ).
- It's use is intended for UMSDOS-users only
- (others do not have a DOS-partition for "root").
-
-
- It is (at the time of LOADLIN-1.4) restricted to
- to systems with all drives AT-type or maximum 2 SCSI-drives over BIOS,
- mixed usage it not (yet) supported.
-
-
- USAGE:
-
- LOADLINX [--dv] loadlin_command_line
-
- --dv debug verbose, did't exec LOADLIN
-
-
- ============================================================================ */
-
- #define DEBUGGING 0
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <process.h>
- #include <string.h>
- #include <dos.h>
- #include <bios.h>
- #include <ctype.h>
- #include <io.h>
- #include <fcntl.h>
-
-
- enum {
- I13_reset_drive,I13_drive_status,I13_read_sector,I13_write_sector,
- I13_verify_sector,I13_format_track,I13_format_bad_track,I13_format_drive,
- I13_get_drive_parameters
- };
- #define FCARRY 1
- #define RETRY_MAX 5
-
- typedef unsigned short word;
- typedef unsigned char byte;
- typedef unsigned long dword;
-
-
- typedef struct {
- byte bootable_flag;
- byte head_start;
- word tracksect_start; /* format as CX for INT13 */
- byte partion_type; /* 0x01 = DOS, FAT12
- 0x04 = DOS, FAT16 (small DOS)
- 0x05 = extended partion
- 0x06 = DOS, FAT16 (big DOS)
- 0x83 = Linux native
- ...
- */
- byte head_end;
- word tracksect_end; /* format as CX for INT13 */
- dword start_sector; /* logical sector (counting from 0)
- of bootsect of this partion */
- dword total_sectors; /* total number of sectors in this partition
- including bootsect */
- } partition_typ;
-
- typedef struct {
- byte loader_code[0x1be];
- partition_typ partitions[4];
- word bootmagic; /* = 0xAA55 */
- } MBR_typ;
-
- typedef struct {
- word cylinders;
- word heads;
- word sector_per_track;
- word phys_drive;
- MBR_typ mbr;
- char linux_dev;
- } my_drive_param_table_typ;
-
-
-
- #define MAX_DRIVES 2 /* I know, I know ... Two drives are enough,
- but I saw device drivers, which hook the INT13
- and supplied 0x82, 0x83..
- If we get report of someone using such drives,
- we will try a greater MAX_DRIVES*/
-
- my_drive_param_table_typ drives[MAX_DRIVES];
- int num_drives;
- MBR_typ embr;
- char devname[80];
- int can_exit_to_dos=0;
- int verbose_only=0;
-
- void err_exit(char *tx)
- {
- #if DEBUGGING
- debug_write_close();
- debug_read_close();
- #endif
- if (tx) fprintf(stderr, "%s\n",tx);
- if (can_exit_to_dos) {
- if (tx) exit(1);
- else exit(0);
- }
- fprintf(stderr, "\n LOADLIN holding in idle loop, you must reboot\n");
- while (1);
- }
-
-
- #if DEBUGGING /* >>>>>>>>>> debugging >>>>>>>>>> */
-
- typedef struct {
- word kind;
- word phys_drive;
- dword sector;
- byte dummy[16-8];
- union {
- MBR_typ mbr;
- struct REGPACK r;
- int cmos;
- } u;
- } debug_record_typ;
-
- int fdebug_out=-1;
- int fdebug_in=-1;
-
- debug_write_close()
- {
- if (fdebug_out>0) close(fdebug_out);
- fdebug_out=-1;
- }
-
- void debug_write_open(char *fname)
- {
- debug_write_close();
- if ((fdebug_out=_creat(fname, FA_ARCH)) == -1 ) {
- perror(fname);
- err_exit("can't open output-debug file");
- }
- }
-
- debug_read_close()
- {
- if (fdebug_in>0) close(fdebug_out);
- fdebug_in=-1;
- }
-
- void debug_read_open(char *fname)
- {
- debug_read_close();
- if ((fdebug_in=_open(fname, O_RDONLY)) == -1 ) {
- perror(fname);
- err_exit("can't open input-debug file");
- }
- }
-
- void debug_write(int kind, int physdrive, dword sector, void *buf)
- {
- debug_record_typ b;
- if (!fdebug_out) return;
- memcpy(&b.u.mbr,buf,sizeof(b.u.mbr));
- b.kind=kind;
- b.phys_drive=physdrive;
- b.sector=sector;
- memset(&b.dummy,0,sizeof(b.dummy));
- write(fdebug_out,&b,sizeof(b));
- }
-
- int debug_read(int kind, int physdrive, dword sector, void *buf)
- {
- debug_record_typ b;
- int r;
- int size;
- if (!fdebug_in) return -1;
- lseek(fdebug_in,0,SEEK_SET);
- while (read(fdebug_in,&b,sizeof(b)) == sizeof(b)) {
- if ( (b.phys_drive==physdrive)
- && (b.kind==kind)
- && (b.sector==sector) ) {
- switch (kind) {
- case 1: size= sizeof(b.u.r);break;
- case 2: size= sizeof(b.u.cmos); break;
- default: size= sizeof(b.u.mbr); break;
- }
- memcpy(buf,&b.u.mbr,size);
- return 0;
- }
- }
- return -1;
- }
-
- int read_file(char *name, void *buf, int bufsize)
- {
- int f;
- if ((f=_open(name, O_RDONLY)) == -1 ) {
- printf("can't open input file %s\n",name);
- return -1;
- }
- bufsize=read(f,buf,bufsize);
- close(f);
- return bufsize;
- }
-
-
- void generate_virtual_drive_manually()
- {
- dword virtual_total_size=(64*1024L*2);
- char name[80];
- int i,part_type,numdrives;
- dword ii,first_sector;
- struct REGPACK regs;
- int virtually = 0;
- int more=0;
- int physdrive;
- int has_bootable;
-
- printf("enter name of output file:\n");
- gets(name);
- if (!name[0]) err_exit("");
- debug_write_open(name);
- printf("how many drives total (1 or 2, default=1):\n");
- gets(name);
- if (name[0] != '2') name[0] = 1;
- numdrives=name[0] & 3;
- more=numdrives;
- do {
- has_bootable=0;
- printf("enter drive to be simulated (0 or 1, empty=0):\n");
- gets(name);
- name[0] &=1;
- physdrive= (name[0] & 1) +0x80;
- drives[0].phys_drive=physdrive;
- i=47;
- debug_write(2,drives[0].phys_drive,0, &i);
- regs.r_dx = numdrives;
- debug_write(1,drives[0].phys_drive,0, ®s);
-
- printf("enter name of file containing MBR (or empty if none ):\n");
- gets(name);
- if (name[0]) {
- if (read_file(name, &drives[0].mbr, sizeof(drives[0].mbr))!=sizeof(drives[0].mbr)) err_exit("");
- } else {
- virtually=1;
- memset(&drives[0].mbr,0,sizeof(drives[0].mbr));
- drives[0].mbr.bootmagic = 0xAA55;
- first_sector=0x100;
- for (i=0; i<4; i++) {
- printf("enter type of partition %d:\n",i+1);
- gets(name);
- if (!name[0]) break;
- drives[0].mbr.partitions[i].partion_type = strtoul(name,0,0);
- if ((physdrive == 0x80) && (!has_bootable)) {
- printf("bootable partition ? (enter for NO, any other for YES)\n");
- gets(name);
- if (name[0]) {
- drives[0].mbr.partitions[i].bootable_flag=0x80;
- has_bootable=1;
- }
- }
- drives[0].mbr.partitions[i].start_sector=first_sector;
- first_sector+=virtual_total_size;
- drives[0].mbr.partitions[i].total_sectors=virtual_total_size;
- }
- }
- debug_write(0,drives[0].phys_drive,0, &drives[0].mbr);
- for (i=0; i<4; i++) {
- if (drives[0].mbr.partitions[i].partion_type == 5) {
- printf("has extended partition\n");
- first_sector=drives[0].mbr.partitions[i].start_sector;
- ii=first_sector;
- part_type=drives[0].mbr.partitions[i].partion_type;
- while (part_type == 5) {
- if (!virtually) {
- printf("needs bootrec for logical partition, sector = %ld\n"
- "enter name of file containing this bootrec\n",ii);
- gets(name);
- if (!name[0]) err_exit("");
- if (read_file(name, &drives[0].mbr, sizeof(drives[0].mbr))!=sizeof(drives[0].mbr)) err_exit("");
- printf("partition type is 0x%02x, enter new partition type ( empty for no change)\n",
- drives[0].mbr.partitions[0].partion_type);
- gets(name);
- if (name[0]) drives[0].mbr.partitions[0].partion_type=strtoul(name,0,0);
- }
- else {
- memset(&drives[0].mbr,0,sizeof(drives[0].mbr));
- drives[0].mbr.bootmagic = 0xAA55;
- printf("enter type of sub-partition %d (default is 6):\n");
- gets(name);
- if (!name[0]) drives[0].mbr.partitions[0].partion_type =6;
- else drives[0].mbr.partitions[0].partion_type = strtoul(name,0,0);
- drives[0].mbr.partitions[0].start_sector=ii-first_sector;
- drives[0].mbr.partitions[0].total_sectors=virtual_total_size;
- printf("is this the last sub-partition (enter for NO, any other for YES)\n");
- gets(name);
- if (!name[0]) {
- drives[0].mbr.partitions[1].partion_type = 5;
- drives[0].mbr.partitions[1].start_sector=ii-first_sector+virtual_total_size;
- drives[0].mbr.partitions[1].total_sectors=virtual_total_size;
- }
- }
- debug_write(0,drives[0].phys_drive,ii, &drives[0].mbr);
- ii= first_sector+drives[0].mbr.partitions[1].start_sector;
- part_type=drives[0].mbr.partitions[1].partion_type;
- }
- break;
- }
- }
- more--;
- if (more>0) {
- printf("will you generate a second virtual drive (enter for NO, any other for YES)\n");
- gets(name);
- if (!name[0]) more=-1;
- }
- } while (more>0);
- debug_write_close();
- }
-
- #endif /* <<<<<<<<<< debugging <<<<<<<<<< */
-
-
- int get_drive_parameters(int physdrive, my_drive_param_table_typ *t)
- {
- struct REGPACK r;
- int ret;
- t->phys_drive = physdrive;
- #if DEBUGGING
- if (!(ret=debug_read(1, physdrive, 0, &r))) return r.r_dx & 255;
- #endif
- r.r_ax=(I13_get_drive_parameters) << 8;
- r.r_dx=physdrive;
- intr(0x13,&r);
- if ((r.r_flags & FCARRY) || (r.r_ax & 0xff00)) return 0;
- t->cylinders = (r.r_cx >> 8) | ((r.r_cx << 2) & 0x300);
- t->cylinders++;
- t->heads = r.r_dx >> 8;
- t->heads++;
- t->sector_per_track = r.r_cx & 0x3f;
- ret = r.r_dx & 255; /* number of available drives */
- #if DEBUGGING
- debug_write(1, physdrive, 0, &r);
- #endif
- return ret;
- }
-
-
-
- int phys_disk_read(int physdrive, int track, int head, int sector, void *buf)
- {
- /* NOTE: because we only access harddrives, which don't use DMA
- we never get DMA overrun, so "buf" can be unaligned.
- (SCSI-bioses, which hook into INT13 and use DMA,
- take care of DMA-overun themself).
- */
- int i,s;
- for (i=0; i<RETRY_MAX; i++) {
- s=biosdisk(I13_read_sector,physdrive, head, track, sector, 1, buf);
- if ((!s) || (s=0x11)) return 0;
- }
- return s;
- }
-
- int logical_disk_read(my_drive_param_table_typ *dp, dword logsector, void *buf)
- {
- dword t,h,s;
- int r;
- #if DEBUGGING
- if (!(r=debug_read(0, dp->phys_drive, logsector, buf))) return r;
- #endif
- s= (dword)dp->heads * dp->sector_per_track;
- t = logsector / s;
- s = logsector % s;
- h = s / dp->sector_per_track;
- s = (s % dp->sector_per_track) +1 ;
- r=phys_disk_read(dp->phys_drive,t,h,s,buf);
- #if DEBUGGING
- debug_write(0, dp->phys_drive, logsector, buf);
- #endif
- return r;
- }
-
-
- unsigned char get_cmos_byte(int index)
- {
- enum {CMOS_INDEX=0x70,CMOS_DATA};
- outportb(CMOS_INDEX,index);
- return inportb(CMOS_DATA);
- }
-
-
- int CMOS_harddisk_type(int drive)
- {
- enum {CMOS_HARDDISKS=0x12,CMOS_HARDDISK0=0x19,CMOS_HARDDISK1};
- int h,r;
- #if DEBUGGING
- if (!(r=debug_read(2, 0x80+drive, 0, &h))) return h;
- #endif
- h = get_cmos_byte(CMOS_HARDDISKS);
- if (drive) {
- h &=15;
- drive=1;
- }
- else h >>=4;
- if (h<15) return h;
- r = get_cmos_byte(CMOS_HARDDISK0+drive);
- #if DEBUGGING
- debug_write(2, 0x80+drive, 0, &r);
- #endif
- return r;
- }
-
-
-
-
- int first_check()
- {
- int i;
-
- /* first we check, how much INT13 accessable drives we have
- We do this by getting the drive params for drive 0 (0x80)
- and looking at "consecutive number of drives".
- If we access a not existing drive, we may wait for LONG while
- until the BIOS returns.
- Impatient users like to apply the 3-finger-salut before this.
- ( oh dear... )
- */
- num_drives=get_drive_parameters(0x80, &drives[0]);
- if (verbose_only) printf("number of INT13 accessable drives: %d\n",num_drives);
- if (!num_drives) err_exit("can't access any hard drives");
- if (num_drives > MAX_DRIVES) err_exit("..ouch.., to many drives, send report to lermen@elserv.ffm.fgan.de");
-
- /* Ok, we have one drive at minimum, we get the MBR of it */
- if (logical_disk_read(&drives[0],0,&drives[0].mbr)) err_exit("can't access MBR of drive 0");
- /* now we do the same for all other drives */
- for (i=1; i<num_drives; i++) {
- if (!get_drive_parameters(0x80+i, &drives[i])) {
- fprintf(stderr,"drive %d: ",i);
- err_exit("can't get drive params");
- }
- if (logical_disk_read(&drives[i],0,&drives[i].mbr)) {
- fprintf(stderr,"drive %d: ",i);
- err_exit("can't access MBR");
- }
- }
- }
-
- int second_check()
- {
- int i;
- /* we now must decide, which of the drives are non-AT,
- for the monent we assume non-AT == SCSI
- we do this by looking in the CMOSram, if we have an entry
- for that drive.
- drives >1 can't be AT.
- */
- for (i=0; i<num_drives; i++) {
- if (i>1) drives[i].linux_dev='s';
- else {
- if (CMOS_harddisk_type(i)) drives[i].linux_dev='h';
- else drives[i].linux_dev='s';
- }
- }
- }
-
- int get_bootpartition_of(int drive)
- {
- int i;
- for (i=0; i<4; i++) {
- switch (drives[drive].mbr.partitions[i].partion_type) {
- case 1:
- case 4:
- case 6:
- if (drives[drive].mbr.partitions[i].bootable_flag) {
- drives[drive].mbr.partitions[i].partion_type=0; /* avoid reusage */
- return i+1;
- }
- }
- }
- return -1;
- }
-
- int get_primary_partition_of(int drive)
- {
- int i;
- for (i=0; i<4; i++) {
- switch (drives[drive].mbr.partitions[i].partion_type) {
- case 1:
- case 4:
- case 6:
- drives[drive].mbr.partitions[i].partion_type=0; /* avoid reusage */
- return i+1;
- }
- }
- return -1;
- }
-
- char *decode_partition_type(int ptype){
- switch (ptype) {
- case 0x00: return "Empty";
- case 0x01: return "DOS 12-bit FAT";
- case 0x02: return "XENIX root";
- case 0x03: return "XENIX usr";
- case 0x04: return "DOS 16-bit <32M";
- case 0x05: return "Extended";
- case 0x06: return "DOS 16-bit >=32";
- case 0x07: return "OS/2 HPFS";
- case 0x08: return "AIX";
- case 0x09: return "AIX bootable";
- case 0x0a: return "OPUS";
- case 0x40: return "Venix 80286";
- case 0x51: return "Novell?";
- case 0x52: return "Microport";
- case 0x63: return "GNU HURD";
- case 0x64: return "Novell";
- case 0x75: return "PC/IX";
- case 0x80: return "Old MINIX";
- case 0x81: return "Linux/MINIX";
- case 0x82: return "Linux swap";
- case 0x83: return "Linux native";
- case 0x93: return "Amoeba";
- case 0x94: return "Amoeba BBT";
- case 0xb7: return "BSDI fs";
- case 0xb8: return "BSDI swap";
- case 0xc7: return "Syrinx";
- case 0xdb: return "CP/M";
- case 0xe1: return "DOS access";
- case 0xe3: return "DOS R/O";
- case 0xf2: return "DOS secondary";
- case 0xff: return "BBT";
- default: return "unknown";
- }
- }
-
- print_extended_partitions_of(int drive, int part)
- {
- int ii;
- unsigned long sect0,sect;
- sect0=drives[drive].mbr.partitions[part].start_sector;
- sect=sect0;
- for (ii=1; ii<16 ;ii++) {
- if (logical_disk_read(&drives[drive],sect, &embr)) {
- fprintf(stderr,"drive %d extended partition %d sub-partition %d\n",drive,part,ii);
- err_exit("can't read partition header");
- }
- if (embr.bootmagic != 0xAA55) return;
-
- printf(
- " log-part. %d %ld Mb %s\n",
- ii+4,
- embr.partitions[0].total_sectors / (2*1024),
- decode_partition_type(embr.partitions[0].partion_type)
- );
- if ( (embr.partitions[1].partion_type != 5)
- || !embr.partitions[1].total_sectors ) return;
- sect= sect0+embr.partitions[1].start_sector;
- }
- }
-
- print_partitions_of(int drive)
- {
- int i,ptype;
- char *bootable;
- printf("drive %d == Linux device: /dev/%cd%c\n",
- drive,drives[drive].linux_dev,'a'+drive);
- for (i=0; i<4; i++) {
- ptype=drives[drive].mbr.partitions[i].partion_type;
- if (!ptype) return;
- if (drives[drive].mbr.partitions[i].bootable_flag) bootable=" bootable";
- else bootable="";
- printf(
- " partition %d %ld Mb %s%s\n",
- i+1,
- drives[drive].mbr.partitions[i].total_sectors / (2*1024),
- decode_partition_type(ptype),
- bootable
- );
- if (ptype == 5) print_extended_partitions_of(drive, i);
- }
- }
-
- int get_extended_partitions_of(int drive, char dosdrive, char *currentdrive)
- {
- int i,ii;
- partition_typ *p;
- unsigned long sect0,sect;
- for (i=0; i<4; i++) {
- if (drives[drive].mbr.partitions[i].partion_type == 5) {
- /* found an extended partition, and walk through the chain
- of partition header only to count.
-
- Comment from Linus Thorvalds (linux/drivers/block/genhd.c):
- >>>
- * The logical partitions form a linked list, with each entry being
- * a partition table with two entries. The first entry
- * is the real data partition (with a start relative to the partition
- * table start). The second is a pointer to the next logical partition
- * (with a start relative to the entire extended partition).
- <<< end comment.
- */
- drives[drive].mbr.partitions[i].partion_type=0; /* avoid reusage */
- sect0=drives[drive].mbr.partitions[i].start_sector;
- sect=sect0;
- for (ii=1; ii<16 ;ii++) {
- if (logical_disk_read(&drives[drive],sect, &embr)) {
- fprintf(stderr,"drive %d extended partition %d sub-partition %d\n",drive,i,ii);
- err_exit("can't read partition header");
- }
- if (embr.bootmagic != 0xAA55) return ii-1;
- switch (embr.partitions[0].partion_type) {
- case 1:
- case 4:
- case 6: {
- if (*currentdrive == dosdrive) return ii;
- (*currentdrive)++;
- break;
- }
- }
- if ( (embr.partitions[1].partion_type != 5)
- || !embr.partitions[1].total_sectors ) return -1;
- sect= sect0+embr.partitions[1].start_sector;
- }
- }
- }
- return -1;
- }
-
- assemble_devname_(int drive, int part, char *linuxdev)
- {
- strcpy(linuxdev,"root=/dev/");
- linuxdev += 10;
- *linuxdev++ = drives[drive].linux_dev;
- *linuxdev++ = 'd';
- *linuxdev++ = 'a'+drive;
- itoa(part,linuxdev,10);
- }
-
- int assemble_devname(int drive, int part, char dosdrive, char *d, char *linuxdev)
- {
- if (part<=0) return -1;
- if (dosdrive == *d) {
- assemble_devname_(drive,part,linuxdev);
- return 0;
- }
- (*d)++;
- return 1;
- }
-
- char *search_drive(char dosdrive, char *linuxdev)
- {
- char d;
- int part,i;
-
- dosdrive= tolower(dosdrive);
-
- if (verbose_only) for (i=0; i<num_drives; i++) print_partitions_of(i);
-
- /*
- DOS-FDISK doesn't create an extended partion on a drive,
- that has no primary partition. It only creates max 1 primary
- and 1 extended partition.
- Under Linux, however, it is possible to create more than
- one primary DOS-partition (types 1,4,6). And also possible
- is the creation of a drive, which has only an extended partion.
- DOS, nevertheless can work with these partions, so we have
- do be aware of it.
-
- After doing heavy testing with multiple combinations under MSDOS 6.2
- I guess the following strategie is used by DOS to assign
- drive letters (C:, D:, ..) to partions:
-
- 1. DOS searches upwards for appropriate partion-entries in the MBR
- ( 0,1,2,3 )
- Be not confused with partion numbering of DOS-FDISK,
- it sorts the partions by sizes, not by there entry in the MBR.
- Seems that MS likes do have the things nice on the screen,
- regardless of internal order (...sh.. ).
-
- 2. Beginning with "C:" DOS searches for a PRI-DOS with "bootable-flag"
- on drive 0, then on drive 1.
- If it can find any, it searches for an unflagged PRI-DOS,
- first on drive 0, then on drive 1.
- NOTE 1:
- "bootable-flag" can also be set on drive 1 PRI-DOS
- with the effect, that this partition becomes "D:",
- even if there is an other PRI-DOS with lower partition number.
- NOTE 2:
- If DOS can't find any PRI-DOS on drive 0, but on drive 1,
- then (..surprise..) it assigns "C:" on drive 1 !
-
- 3. After (if possible) having assigned at minum one PRI-DOS
- for both drives, it stops assigning PRI-DOS and continues
- with the extended partion on drive 0.
- It assignes ALL sub-partitions in the extended partion (type 5),
- which have DOS-types (1,4,6) in there proper order.
- If there are non-DOS partions, the are skipped.
-
- 4. If there are some PRI-DOS partitions remaining on drive 0
- they are now assigned.
-
- 5. Then it goes to drive 1, doing steps 3. and 4. accordingly.
-
-
- For better understanding here some examples:
-
- EXAMPLE 1
-
- drive 0:
- part 0 PRI-DOS G:
- part 1 bootable PRI-DOS C:
- part 2 extended none
- part 3 PRI-DOS H:
- ext-part 1 DOS E:
- ext-part 2 Linux
- ext-part 3 DOS F:
-
- drive 1:
- part 0 PRI-DOS I:
- part 1 Linux-native none
- part 2 bootable PRI-DOS D:
- part 3 PRI-DOS J:
-
- EXAMPLE 2
-
- drive 0:
- part 0 extended none
- ext-part 1 DOS D:
- ext-part 2 DOS E:
-
- drive 1:
- part 0 PRI-DOS C: (but you can't boot from it)
- part 1 Linux-native none
-
- Isn't it nice ? (..why simple, if we can have it complicated..)
- */
-
-
- d = 'c'; /* we start with 'C:' */
-
- /* first search for a bootable partition on drive 0 */
- part=get_bootpartition_of(0);
- if (!assemble_devname(0,part,dosdrive,&d,linuxdev)) return linuxdev;
- if (part<=0) {
- /* then search for a primary partition on drive 0 */
- part=get_primary_partition_of(0);
- if (!assemble_devname(0,part,dosdrive,&d,linuxdev)) return linuxdev;
- }
-
- /* then search for a bootable partition on drive 1 */
- part=get_bootpartition_of(1);
- if (!assemble_devname(1,part,dosdrive,&d,linuxdev)) return linuxdev;
- if (part<=0) {
- /* then search for a primary partition on drive 1 */
- part=get_primary_partition_of(1);
- if (!assemble_devname(1,part,dosdrive,&d,linuxdev)) return linuxdev;
- }
-
- /* now we go back to drive 0, assigning all we have,
- but first the extended partions */
- part=get_extended_partitions_of(0,dosdrive,&d);
- if (part>0) {
- if (dosdrive == d) {
- assemble_devname_(0,4+part,linuxdev);
- return linuxdev;
- }
- }
- /* now the rest of drive 0 */
- do {
- part=get_primary_partition_of(0);
- if (!assemble_devname(0,part,dosdrive,&d,linuxdev)) return linuxdev;
- } while (part>0);
-
-
- /* now we go to drive 1, assigning all we have,
- but first the extended partions */
- part=get_extended_partitions_of(1,dosdrive,&d);
- if (part>0) {
- if (dosdrive == d) {
- assemble_devname_(1,4+part,linuxdev);
- return linuxdev;
- }
- }
- /* now the rest of drive 1 */
- do {
- part=get_primary_partition_of(1);
- if (!assemble_devname(1,part,dosdrive,&d,linuxdev)) return linuxdev;
- } while (part>0);
-
- /* we come here if dosdrive couldn't be translated */
- return 0;
- }
-
- int parse_for_arg(char *search, int n,char **argv)
- {
- int i=0;
- while (*argv) {
- if (n) {
- if (!strnicmp(*argv++,search,n)) return i;
- } else {
- if (!stricmp(*argv++,search)) return i;
- }
- i++;
- }
- return 0;
- }
-
- void delete_arg(int arg, int *argc, char **argv)
- {
- memcpy(argv+arg,argv+arg+1,(*argc+1-arg)*4);
- (*argc)--;
- }
-
- typedef struct {
- unsigned short jmp_op; /* jmp short start_of_setup */
- unsigned long setup_header_sign;
- unsigned short setup_header_version;
- void * setup_realmode_switch;
- unsigned short start_sys_seg;
- unsigned short kernel_version;
- } setup_header;
-
- #define SIGNATURE 0x53726448 /* setup header signature */
-
- char * get_kernel_version_string(char *fname,char *buf,int sizebuf)
- {
- int f;
- setup_header h;
- if ((f=_open(fname, O_RDONLY)) == -1 ) {
- perror(fname);
- err_exit("can't open image file");
- }
- lseek(f,0x200,SEEK_SET);
- if (read(f,&h,sizeof(h)) != sizeof(h)) {
- _close(f);
- err_exit("image has wrong format");
- }
- if ((h.setup_header_sign == SIGNATURE) && (h.setup_header_version >= 0x105)) {
- lseek(f,0x200+h.kernel_version,SEEK_SET);
- if (read(f,buf,sizebuf) == sizebuf) return buf;
- }
- _close(f);
- return 0;
- }
-
- long int value_of(char **s)
- {
- int i=0;
- char s_[30];
- while (isdigit(**s)) s_[i++]=*(*s)++;
- s_[i]=0;
- *(*s)++; /* this code HAS effect, though TURBO-C states that not */
- return atoi(s_);
- }
-
- unsigned long version_string_to_binary(char *vstring)
- {
- unsigned long v=0;
- char *s;
- v =value_of(&vstring);
- v <<=8;
- v +=value_of(&vstring);
- v <<=8;
- v +=value_of(&vstring);
- v <<=8;
- if (vstring=strchr(vstring-1,'#')) {
- vstring++;
- v +=value_of(&vstring);
- }
- /* printf(">%08lx<\n",v); */
- return v;
- }
-
- void check_kernel_version(char *imagename, char *version)
- {
- unsigned long v_desired;
- unsigned long v_actual;
- int check_below=0, ok;
- char buf[128];
-
- if (get_kernel_version_string(imagename,buf,sizeof(buf))) {
- if (version[0]=='-') {
- check_below=1;
- version++;
- }
- v_desired=version_string_to_binary(version);
- v_actual=version_string_to_binary(buf);
- if (!(v_desired & 0xff)) v_actual &= ~0xFF;
- if (check_below) ok= v_actual <= v_desired;
- else ok= v_actual >= v_desired;
- if (!ok) err_exit("wrong kernel version");
- }
- else err_exit("setup of image file has no version stamp, can\'t verify");
- }
-
- void print_version_string(char *image)
- {
- char buf[128];
- if (get_kernel_version_string(image,buf,sizeof(buf))) {
- fprintf(stderr, "\n%s %s\n",image,buf);
- err_exit(0);
- }
- else err_exit("setup of image file has no version stamp");
- }
-
-
- /* -------------- response-file stuff -------------- */
-
- FILE * fparam_in=0;
-
- param_read_close()
- {
- if (fparam_in) fclose(fparam_in);
- fparam_in=0;
- }
-
- void param_read_open(char *fname)
- {
- param_read_close();
- if ((fparam_in=fopen(fname, "rt")) == 0 ) {
- perror(fname);
- err_exit("can't open params file");
- }
- }
-
- #define MAX_OUR_ARGS 50
- char *our_argv[MAX_OUR_ARGS+1]={0};
- int our_argc=0;
- typedef struct {
- unsigned short opint20;
- unsigned short memend_frame;
- unsigned char dos_reserved4;
- unsigned char cpm_function_entry[0xa-0x5];
- unsigned long int22_copy;
- unsigned long int23_copy;
- unsigned long int24_copy;
- unsigned short PID;
- unsigned char file_handles[20];
- unsigned short envir_frame;
- unsigned long system_stack;
- unsigned short max_open_files;
- unsigned long file_handles_ptr;
- unsigned char dos_reserved38[0x50-0x38];
- unsigned char high_language_dos_call[0x53-0x50];
- unsigned char dos_reserved53[0x5c-0x53];
- unsigned char FCB1[0x6c-0x5c];
- unsigned char FCB2[0x80-0x6c];
- unsigned char DTA[0x100-0x80];
- } dos_segprefix;
-
-
- static build_param_buf(char **argv)
- {
- dos_segprefix *psp=MK_FP(_psp,0);
- unsigned segp;
- int ret;
- unsigned char *param_buf=(void *)0x90200000;
-
- ret=allocmem(0x1000,&segp);
- freemem(segp);
- if (ret==-1 && segp<0x9000) {
- if (psp->memend_frame >0x9c00) {
- argv++; /* skip argv[0] ( the program name ) */
- while (*argv) param_buf+=sprintf(param_buf,"%s\n",*argv++);
- *param_buf=0;
- }
- else err_exit("not enough memory at top of 0x9C000, can\'t pass params to LOADLIN.EXE");
- }
- else err_exit("not enough memory starting at 0x90000, can\'t pass params to LOADLIN.EXE");
- }
-
- static put_our_arg(char *arg)
- {
- /* printf(">%s<\n",arg); */
- if (our_argc<MAX_OUR_ARGS) {
- our_argv[our_argc]=strdup(arg);
- if (our_argv[our_argc]) our_argc++;
- our_argv[our_argc]=0;
- }
- }
-
- void get_params_from_file(char *fname)
- {
- int c,i=0;
- char buf[256];
-
- param_read_open(fname);
- while ((c=fgetc(fparam_in)) !=EOF) {
- switch (c) {
- case '#': {
- do {
- c=fgetc(fparam_in);
- } while ((c !=EOF) && (c!='\n') );
- ungetc(c,fparam_in);
- break;
- }
- case '\n':
- case ' ':
- case '\t':
- {
- if (i) {
- buf[i]=0;
- put_our_arg(buf);
- i=0;
- }
- break;
- }
- default: {
- buf[i++]=c;
- break;
- }
- }
- }
- if (i) {
- buf[i]=0;
- put_our_arg(buf);
- i=0;
- }
- param_read_close();
- }
-
-
- /* -------------- end response-file stuff -------------- */
-
-
- main(int argc, char **argv)
- {
- int i,root;
- char lname[80];
- int have_responsefile=0;
-
-
- if (getenv("COMSPEC")) can_exit_to_dos=1;
- #if DEBUGGING
- if (i=parse_for_arg("--dg",0,argv)) {
- generate_virtual_drive_manually();
- err_exit("Ok");
- }
- if (i=parse_for_arg("--di",0,argv)) {
- delete_arg(i, &argc, argv);
- if (argv[i]) {
- debug_read_open(argv[i]);
- delete_arg(i, &argc, argv);
- }
- }
- if (i=parse_for_arg("--do",0,argv)) {
- delete_arg(i, &argc, argv);
- if (argv[i]) {
- debug_write_open(argv[i]);
- delete_arg(i, &argc, argv);
- }
- }
- #endif
-
- if (i=parse_for_arg("--dv",0,argv)) {
- delete_arg(i, &argc, argv);
- verbose_only=1;
- }
-
-
- if (i=parse_for_arg("@",1,argv)) {
- char **_argv=argv+1;
- char *c,j;
- put_our_arg(argv[0]);
- get_params_from_file(argv[i]+1);
- have_responsefile=1;
- if (i>1) _argv++;
- while (*_argv) {
- if (strcmp(*_argv,argv[i])) {
- if (c=strchr(*_argv,'=')) {
- j=parse_for_arg(*_argv,(c-*_argv)+1,our_argv);
- if (j) our_argv[j]=*_argv;
- else put_our_arg(*_argv);
- }
- else {
- if (!(parse_for_arg(*_argv,0,our_argv))) {
- if (!strcmp("ro",*_argv)) {
- if (j=(parse_for_arg("rw",0,our_argv))) our_argv[j]=*_argv;
- else put_our_arg(*_argv);
- }
- else {
- if (!strcmp("rw",*_argv)) {
- if (j=(parse_for_arg("ro",0,our_argv))) our_argv[j]=*_argv;
- else put_our_arg(*_argv);
- }
- else put_our_arg(*_argv);
- }
- }
- }
- }
- _argv++;
- }
- if (i>1) our_argv[1]=argv[1];
- argv=(char **)&our_argv;
- argc=our_argc;
- }
- if ( (root=parse_for_arg("root=",5,argv)) && (argv[root][6] == ':') ) {
- int drivenum=tolower(argv[root][5]);
- if (drivenum >= 'c') {
- first_check();
- second_check();
- if (!search_drive(argv[root][5],devname)) err_exit("can't translate root device");
- }
- else {
- if (drivenum == 'a') strcpy(devname,"root=/dev/fd0");
- else strcpy(devname,"root=/dev/fd1");
- }
- argv[root]=devname;
- }
- else {
- if (verbose_only) {
- first_check();
- second_check();
- search_drive('z',devname);
- /* err_exit(0); */
- }
- }
-
- if (i=parse_for_arg("--version=",10,argv)) {
- check_kernel_version(argv[1],argv[i]+10);
- delete_arg(i, &argc, argv);
- }
- if (i=parse_for_arg("--version",0,argv)) {
- print_version_string(argv[1]);
- /* doesn't return */
- }
-
-
-
- strcpy(lname,argv[0]);
- for (i=strlen(lname); lname[i] !='\\' ; i--);
- strcpy(lname+i+1,"LOADLIN.EXE");
- if (verbose_only) {
- fprintf(stderr,"\n %s would be started with following command line:\n\n ",lname);
- argv++;
- while (*argv) fprintf(stderr," %s",*argv++);
- err_exit("\n");
- }
- else {
- if (have_responsefile) {
- build_param_buf(argv);
- argv[1]="@@loadlinx@@";
- argv[2]=0;
- }
- if (execv(lname,argv) == -1) err_exit("can't find/execute LOADLIN.EXE");
- }
- }