home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / KERNELS / LODLIN15.ZIP / LOADLIN / LOADLINX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-05  |  33.9 KB  |  1,188 lines

  1. /*  >>> this is file LOADLINX.C
  2.         compile it with TURBO-C in large model
  3. ============================================================================
  4.    LOADLIN v1.4 (C) 1994 Hans Lermen (lermen@elserv.ffm.fgan.de)
  5.  
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. ----------------------------------------------------------------------------
  21.    Comments and bug reports are welcome and may be sent to:
  22.    E-Mail:    lermen@elserv.ffm.fgan.de
  23.    SnailMail: Hans Lermen
  24.               Am Muehlenweg 38
  25.               D53424 REMAGEN-Unkelbach
  26.               GERMANY
  27.  
  28. ============================================================================
  29.  
  30.    This program has to be used as a "preprocessor" for LOADLIN,
  31.    it does translation of DOSish drive numbering (C:,D:...)
  32.    to Linux device names (/dev/...).
  33.    In addition to "root=X:" LOADLINX accepts the same parameters as LOADLIN
  34.    and passes them to it.
  35.    But translation is NOT supported for parameter files (@param).
  36.                       === =========                      ======
  37.    It can even be executed via shell= in CONFIG.SYS, but must reside
  38.    in the same directory, where LOADLIN is located.
  39.  
  40.    Jacques Gelinas (jacques@solucorp.qc.ca) is the author of this
  41.    algorithm ( I just implemented and enhanced it for LOADLIN
  42.    and adapted it to the exact behavior of DOS ).
  43.    It's use is intended for UMSDOS-users only
  44.    (others do not have a DOS-partition for "root").
  45.  
  46.  
  47.    It is (at the time of LOADLIN-1.4) restricted to
  48.    to systems with all drives AT-type or maximum 2 SCSI-drives over BIOS,
  49.    mixed usage it not (yet) supported.
  50.  
  51.  
  52.    USAGE:
  53.  
  54.      LOADLINX [--dv] loadlin_command_line
  55.  
  56.         --dv    debug verbose, did't exec LOADLIN
  57.  
  58.  
  59. ============================================================================ */
  60.  
  61. #define DEBUGGING 0
  62.  
  63.  
  64. #include <stdio.h>
  65. #include <stdlib.h>
  66. #include <process.h>
  67. #include <string.h>
  68. #include <dos.h>
  69. #include <bios.h>
  70. #include <ctype.h>
  71. #include <io.h>
  72. #include <fcntl.h>
  73.  
  74.  
  75. enum {
  76.   I13_reset_drive,I13_drive_status,I13_read_sector,I13_write_sector,
  77.   I13_verify_sector,I13_format_track,I13_format_bad_track,I13_format_drive,
  78.   I13_get_drive_parameters
  79. };
  80. #define FCARRY 1
  81. #define RETRY_MAX  5
  82.  
  83. typedef unsigned short word;
  84. typedef unsigned char byte;
  85. typedef unsigned long dword;
  86.  
  87.  
  88. typedef struct {
  89.   byte bootable_flag;
  90.   byte head_start;
  91.   word tracksect_start;  /* format as CX for INT13 */
  92.   byte partion_type;     /* 0x01 = DOS, FAT12
  93.                             0x04 = DOS, FAT16 (small DOS)
  94.                             0x05 = extended partion
  95.                             0x06 = DOS, FAT16 (big DOS)
  96.                             0x83 = Linux native
  97.                             ...
  98.                          */
  99.   byte head_end;
  100.   word tracksect_end;  /* format as CX for INT13 */
  101.   dword start_sector;  /* logical sector (counting from 0)
  102.                           of bootsect of this partion */
  103.   dword total_sectors; /* total number of sectors in this partition
  104.                           including bootsect */
  105. } partition_typ;
  106.  
  107. typedef struct {
  108.   byte loader_code[0x1be];
  109.   partition_typ partitions[4];
  110.   word bootmagic; /* = 0xAA55 */
  111. } MBR_typ;
  112.  
  113. typedef struct {
  114.   word cylinders;
  115.   word heads;
  116.   word sector_per_track;
  117.   word phys_drive;
  118.   MBR_typ mbr;
  119.   char linux_dev;
  120. } my_drive_param_table_typ;
  121.  
  122.  
  123.  
  124. #define MAX_DRIVES 2   /* I know, I know ... Two drives are enough,
  125.                           but I saw device drivers, which hook the INT13
  126.                           and supplied 0x82, 0x83..
  127.                           If we get report of someone using such drives,
  128.                           we will try a greater MAX_DRIVES*/
  129.  
  130. my_drive_param_table_typ drives[MAX_DRIVES];
  131. int num_drives;
  132. MBR_typ embr;
  133. char devname[80];
  134. int can_exit_to_dos=0;
  135. int verbose_only=0;
  136.  
  137. void err_exit(char *tx)
  138. {
  139. #if DEBUGGING
  140.   debug_write_close();
  141.   debug_read_close();
  142. #endif
  143.   if (tx) fprintf(stderr, "%s\n",tx);
  144.   if (can_exit_to_dos) {
  145.     if (tx) exit(1);
  146.     else exit(0);
  147.   }
  148.   fprintf(stderr, "\n LOADLIN holding in idle loop, you must reboot\n");
  149.   while (1);
  150. }
  151.  
  152.  
  153. #if DEBUGGING    /* >>>>>>>>>> debugging >>>>>>>>>> */
  154.  
  155. typedef struct {
  156.   word kind;
  157.   word phys_drive;
  158.   dword sector;
  159.   byte dummy[16-8];
  160.   union {
  161.     MBR_typ mbr;
  162.     struct REGPACK r;
  163.     int cmos;
  164.   } u;
  165. } debug_record_typ;
  166.  
  167. int fdebug_out=-1;
  168. int fdebug_in=-1;
  169.  
  170. debug_write_close()
  171. {
  172.   if (fdebug_out>0) close(fdebug_out);
  173.   fdebug_out=-1;
  174. }
  175.  
  176. void debug_write_open(char *fname)
  177. {
  178.   debug_write_close();
  179.   if ((fdebug_out=_creat(fname, FA_ARCH)) == -1 ) {
  180.      perror(fname);
  181.      err_exit("can't open output-debug file");
  182.   }
  183. }
  184.  
  185. debug_read_close()
  186. {
  187.   if (fdebug_in>0) close(fdebug_out);
  188.   fdebug_in=-1;
  189. }
  190.  
  191. void debug_read_open(char *fname)
  192. {
  193.   debug_read_close();
  194.   if ((fdebug_in=_open(fname, O_RDONLY)) == -1 ) {
  195.      perror(fname);
  196.      err_exit("can't open input-debug file");
  197.   }
  198. }
  199.  
  200. void debug_write(int kind, int physdrive, dword sector, void *buf)
  201. {
  202.   debug_record_typ b;
  203.   if (!fdebug_out) return;
  204.   memcpy(&b.u.mbr,buf,sizeof(b.u.mbr));
  205.   b.kind=kind;
  206.   b.phys_drive=physdrive;
  207.   b.sector=sector;
  208.   memset(&b.dummy,0,sizeof(b.dummy));
  209.   write(fdebug_out,&b,sizeof(b));
  210. }
  211.  
  212. int debug_read(int kind, int physdrive, dword sector, void *buf)
  213. {
  214.   debug_record_typ b;
  215.   int r;
  216.   int size;
  217.   if (!fdebug_in) return -1;
  218.   lseek(fdebug_in,0,SEEK_SET);
  219.   while (read(fdebug_in,&b,sizeof(b)) == sizeof(b)) {
  220.     if (    (b.phys_drive==physdrive)
  221.          && (b.kind==kind)
  222.          && (b.sector==sector) ) {
  223.       switch (kind) {
  224.         case  1: size= sizeof(b.u.r);break;
  225.         case  2: size= sizeof(b.u.cmos); break;
  226.         default: size= sizeof(b.u.mbr); break;
  227.       }
  228.       memcpy(buf,&b.u.mbr,size);
  229.       return 0;
  230.     }
  231.   }
  232.   return -1;
  233. }
  234.  
  235. int read_file(char *name, void *buf, int bufsize)
  236. {
  237.   int f;
  238.   if ((f=_open(name, O_RDONLY)) == -1 ) {
  239.     printf("can't open input file %s\n",name);
  240.     return -1;
  241.   }
  242.   bufsize=read(f,buf,bufsize);
  243.   close(f);
  244.   return bufsize;
  245. }
  246.  
  247.  
  248. void generate_virtual_drive_manually()
  249. {
  250.   dword virtual_total_size=(64*1024L*2);
  251.   char name[80];
  252.   int i,part_type,numdrives;
  253.   dword ii,first_sector;
  254.   struct REGPACK regs;
  255.   int virtually = 0;
  256.   int more=0;
  257.   int physdrive;
  258.   int has_bootable;
  259.  
  260.   printf("enter name of output file:\n");
  261.   gets(name);
  262.   if (!name[0]) err_exit("");
  263.   debug_write_open(name);
  264.   printf("how many drives total (1 or 2, default=1):\n");
  265.   gets(name);
  266.   if (name[0] != '2') name[0] = 1;
  267.   numdrives=name[0] & 3;
  268.   more=numdrives;
  269.   do {
  270.     has_bootable=0;
  271.     printf("enter drive to be simulated (0 or 1, empty=0):\n");
  272.     gets(name);
  273.     name[0] &=1;
  274.     physdrive= (name[0] & 1) +0x80;
  275.     drives[0].phys_drive=physdrive;
  276.     i=47;
  277.     debug_write(2,drives[0].phys_drive,0, &i);
  278.     regs.r_dx = numdrives;
  279.     debug_write(1,drives[0].phys_drive,0, ®s);
  280.  
  281.     printf("enter name of file containing MBR (or empty if none ):\n");
  282.     gets(name);
  283.     if (name[0]) {
  284.       if (read_file(name, &drives[0].mbr, sizeof(drives[0].mbr))!=sizeof(drives[0].mbr)) err_exit("");
  285.     } else {
  286.       virtually=1;
  287.       memset(&drives[0].mbr,0,sizeof(drives[0].mbr));
  288.       drives[0].mbr.bootmagic = 0xAA55;
  289.       first_sector=0x100;
  290.       for (i=0; i<4; i++) {
  291.         printf("enter type of partition %d:\n",i+1);
  292.         gets(name);
  293.         if (!name[0]) break;
  294.         drives[0].mbr.partitions[i].partion_type = strtoul(name,0,0);
  295.         if ((physdrive == 0x80) && (!has_bootable)) {
  296.           printf("bootable partition ? (enter for NO, any other for YES)\n");
  297.           gets(name);
  298.           if (name[0]) {
  299.             drives[0].mbr.partitions[i].bootable_flag=0x80;
  300.             has_bootable=1;
  301.           }
  302.         }
  303.         drives[0].mbr.partitions[i].start_sector=first_sector;
  304.         first_sector+=virtual_total_size;
  305.         drives[0].mbr.partitions[i].total_sectors=virtual_total_size;
  306.       }
  307.     }
  308.     debug_write(0,drives[0].phys_drive,0, &drives[0].mbr);
  309.     for (i=0; i<4; i++) {
  310.       if (drives[0].mbr.partitions[i].partion_type == 5) {
  311.         printf("has extended partition\n");
  312.         first_sector=drives[0].mbr.partitions[i].start_sector;
  313.         ii=first_sector;
  314.         part_type=drives[0].mbr.partitions[i].partion_type;
  315.         while (part_type == 5) {
  316.           if (!virtually) {
  317.             printf("needs bootrec for logical partition, sector = %ld\n"
  318.                    "enter name of file containing this bootrec\n",ii);
  319.             gets(name);
  320.             if (!name[0]) err_exit("");
  321.             if (read_file(name, &drives[0].mbr, sizeof(drives[0].mbr))!=sizeof(drives[0].mbr)) err_exit("");
  322.             printf("partition type is 0x%02x, enter new partition type ( empty for no change)\n",
  323.                     drives[0].mbr.partitions[0].partion_type);
  324.             gets(name);
  325.             if (name[0]) drives[0].mbr.partitions[0].partion_type=strtoul(name,0,0);
  326.           }
  327.           else {
  328.             memset(&drives[0].mbr,0,sizeof(drives[0].mbr));
  329.             drives[0].mbr.bootmagic = 0xAA55;
  330.             printf("enter type of sub-partition %d (default is 6):\n");
  331.             gets(name);
  332.             if (!name[0]) drives[0].mbr.partitions[0].partion_type =6;
  333.             else drives[0].mbr.partitions[0].partion_type = strtoul(name,0,0);
  334.             drives[0].mbr.partitions[0].start_sector=ii-first_sector;
  335.             drives[0].mbr.partitions[0].total_sectors=virtual_total_size;
  336.             printf("is this the last sub-partition (enter for NO, any other for YES)\n");
  337.             gets(name);
  338.             if (!name[0]) {
  339.               drives[0].mbr.partitions[1].partion_type = 5;
  340.               drives[0].mbr.partitions[1].start_sector=ii-first_sector+virtual_total_size;
  341.               drives[0].mbr.partitions[1].total_sectors=virtual_total_size;
  342.             }
  343.           }
  344.           debug_write(0,drives[0].phys_drive,ii, &drives[0].mbr);
  345.           ii= first_sector+drives[0].mbr.partitions[1].start_sector;
  346.           part_type=drives[0].mbr.partitions[1].partion_type;
  347.         }
  348.         break;
  349.       }
  350.     }
  351.     more--;
  352.     if (more>0) {
  353.       printf("will you generate a second virtual drive (enter for NO, any other for YES)\n");
  354.       gets(name);
  355.       if (!name[0]) more=-1;
  356.     }
  357.   } while (more>0);
  358.   debug_write_close();
  359. }
  360.  
  361. #endif              /* <<<<<<<<<< debugging <<<<<<<<<< */
  362.  
  363.  
  364. int get_drive_parameters(int physdrive, my_drive_param_table_typ *t)
  365. {
  366.   struct REGPACK r;
  367.   int ret;
  368.   t->phys_drive = physdrive;
  369. #if DEBUGGING
  370.   if (!(ret=debug_read(1, physdrive, 0, &r))) return r.r_dx & 255;
  371. #endif
  372.   r.r_ax=(I13_get_drive_parameters) << 8;
  373.   r.r_dx=physdrive;
  374.   intr(0x13,&r);
  375.   if ((r.r_flags & FCARRY) || (r.r_ax & 0xff00)) return 0;
  376.   t->cylinders = (r.r_cx >> 8) | ((r.r_cx << 2) & 0x300);
  377.   t->cylinders++;
  378.   t->heads = r.r_dx >> 8;
  379.   t->heads++;
  380.   t->sector_per_track = r.r_cx & 0x3f;
  381.   ret = r.r_dx & 255; /* number of available drives */
  382. #if DEBUGGING
  383.   debug_write(1, physdrive, 0, &r);
  384. #endif
  385.   return ret;
  386. }
  387.  
  388.  
  389.  
  390. int phys_disk_read(int physdrive, int track, int head, int sector, void *buf)
  391. {
  392.   /* NOTE: because we only access harddrives, which don't use DMA
  393.            we never get DMA overrun, so "buf" can be unaligned.
  394.            (SCSI-bioses, which hook into INT13 and use DMA,
  395.             take care of DMA-overun themself).
  396.   */
  397.   int i,s;
  398.   for (i=0; i<RETRY_MAX; i++) {
  399.     s=biosdisk(I13_read_sector,physdrive, head, track, sector, 1, buf);
  400.     if ((!s) || (s=0x11)) return 0;
  401.   }
  402.   return s;
  403. }
  404.  
  405. int logical_disk_read(my_drive_param_table_typ *dp, dword logsector, void *buf)
  406. {
  407.   dword t,h,s;
  408.   int r;
  409. #if DEBUGGING
  410.   if (!(r=debug_read(0, dp->phys_drive, logsector, buf))) return r;
  411. #endif
  412.   s= (dword)dp->heads * dp->sector_per_track;
  413.   t = logsector / s;
  414.   s = logsector %  s;
  415.   h = s / dp->sector_per_track;
  416.   s = (s % dp->sector_per_track) +1 ;
  417.   r=phys_disk_read(dp->phys_drive,t,h,s,buf);
  418. #if DEBUGGING
  419.   debug_write(0, dp->phys_drive, logsector, buf);
  420. #endif
  421.   return r;
  422. }
  423.  
  424.  
  425. unsigned char get_cmos_byte(int index)
  426. {
  427.   enum {CMOS_INDEX=0x70,CMOS_DATA};
  428.   outportb(CMOS_INDEX,index);
  429.   return inportb(CMOS_DATA);
  430. }
  431.  
  432.  
  433. int CMOS_harddisk_type(int drive)
  434. {
  435.   enum {CMOS_HARDDISKS=0x12,CMOS_HARDDISK0=0x19,CMOS_HARDDISK1};
  436.   int h,r;
  437. #if DEBUGGING
  438.   if (!(r=debug_read(2, 0x80+drive, 0, &h))) return h;
  439. #endif
  440.   h = get_cmos_byte(CMOS_HARDDISKS);
  441.   if (drive) {
  442.     h &=15;
  443.     drive=1;
  444.   }
  445.   else h >>=4;
  446.   if (h<15) return h;
  447.   r = get_cmos_byte(CMOS_HARDDISK0+drive);
  448. #if DEBUGGING
  449.   debug_write(2, 0x80+drive, 0, &r);
  450. #endif
  451.   return r;
  452. }
  453.  
  454.  
  455.  
  456.  
  457. int first_check()
  458. {
  459.   int i;
  460.  
  461.   /* first we check, how much INT13 accessable drives we have
  462.      We do this by getting the drive params for drive 0 (0x80)
  463.      and looking at "consecutive number of drives".
  464.      If we access a not existing drive, we may wait for LONG while
  465.      until the BIOS returns.
  466.      Impatient users like to apply the 3-finger-salut before this.
  467.      ( oh dear... )
  468.   */
  469.   num_drives=get_drive_parameters(0x80, &drives[0]);
  470.   if (verbose_only) printf("number of INT13 accessable drives: %d\n",num_drives);
  471.   if (!num_drives) err_exit("can't access any hard drives");
  472.   if (num_drives > MAX_DRIVES) err_exit("..ouch.., to many drives, send report to lermen@elserv.ffm.fgan.de");
  473.  
  474.   /* Ok, we have one drive at minimum, we get the MBR of it */
  475.   if (logical_disk_read(&drives[0],0,&drives[0].mbr)) err_exit("can't access MBR of drive 0");
  476.   /* now we do the same for all other drives */
  477.   for (i=1; i<num_drives; i++) {
  478.     if (!get_drive_parameters(0x80+i, &drives[i])) {
  479.       fprintf(stderr,"drive %d: ",i);
  480.       err_exit("can't get drive params");
  481.     }
  482.     if (logical_disk_read(&drives[i],0,&drives[i].mbr)) {
  483.       fprintf(stderr,"drive %d: ",i);
  484.       err_exit("can't access MBR");
  485.     }
  486.   }
  487. }
  488.  
  489. int second_check()
  490. {
  491.   int i;
  492.   /* we now must decide, which of the drives are non-AT,
  493.      for the monent we assume non-AT == SCSI
  494.      we do this by looking in the CMOSram, if we have an entry
  495.      for that drive.
  496.      drives >1 can't be AT.
  497.   */
  498.   for (i=0; i<num_drives; i++) {
  499.     if (i>1) drives[i].linux_dev='s';
  500.     else {
  501.       if (CMOS_harddisk_type(i)) drives[i].linux_dev='h';
  502.       else drives[i].linux_dev='s';
  503.     }
  504.   }
  505. }
  506.  
  507. int get_bootpartition_of(int drive)
  508. {
  509.   int i;
  510.   for (i=0; i<4; i++) {
  511.     switch (drives[drive].mbr.partitions[i].partion_type) {
  512.       case 1:
  513.       case 4:
  514.       case 6:
  515.       if (drives[drive].mbr.partitions[i].bootable_flag) {
  516.         drives[drive].mbr.partitions[i].partion_type=0; /* avoid reusage */
  517.         return i+1;
  518.       }
  519.     }
  520.   }
  521.   return -1;
  522. }
  523.  
  524. int get_primary_partition_of(int drive)
  525. {
  526.   int i;
  527.   for (i=0; i<4; i++) {
  528.     switch (drives[drive].mbr.partitions[i].partion_type) {
  529.       case 1:
  530.       case 4:
  531.       case 6:
  532.         drives[drive].mbr.partitions[i].partion_type=0; /* avoid reusage */
  533.         return i+1;
  534.     }
  535.   }
  536.   return -1;
  537. }
  538.  
  539. char *decode_partition_type(int ptype){
  540.   switch (ptype) {
  541.     case 0x00:  return "Empty";
  542.     case 0x01:  return "DOS 12-bit FAT";
  543.     case 0x02:  return "XENIX root";
  544.     case 0x03:  return "XENIX usr";
  545.     case 0x04:  return "DOS 16-bit <32M";
  546.     case 0x05:  return "Extended";
  547.     case 0x06:  return "DOS 16-bit >=32";
  548.     case 0x07:  return "OS/2 HPFS";
  549.     case 0x08:  return "AIX";
  550.     case 0x09:  return "AIX bootable";
  551.     case 0x0a:  return "OPUS";
  552.     case 0x40:  return "Venix 80286";
  553.     case 0x51:  return "Novell?";
  554.     case 0x52:  return "Microport";
  555.     case 0x63:  return "GNU HURD";
  556.     case 0x64:  return "Novell";
  557.     case 0x75:  return "PC/IX";
  558.     case 0x80:  return "Old MINIX";
  559.     case 0x81:  return "Linux/MINIX";
  560.     case 0x82:  return "Linux swap";
  561.     case 0x83:  return "Linux native";
  562.     case 0x93:  return "Amoeba";
  563.     case 0x94:  return "Amoeba BBT";
  564.     case 0xb7:  return "BSDI fs";
  565.     case 0xb8:  return "BSDI swap";
  566.     case 0xc7:  return "Syrinx";
  567.     case 0xdb:  return "CP/M";
  568.     case 0xe1:  return "DOS access";
  569.     case 0xe3:  return "DOS R/O";
  570.     case 0xf2:  return "DOS secondary";
  571.     case 0xff:  return "BBT";
  572.     default:  return "unknown";
  573.   }
  574. }
  575.  
  576. print_extended_partitions_of(int drive, int part)
  577. {
  578.   int ii;
  579.   unsigned long sect0,sect;
  580.   sect0=drives[drive].mbr.partitions[part].start_sector;
  581.   sect=sect0;
  582.   for (ii=1; ii<16 ;ii++) {
  583.     if (logical_disk_read(&drives[drive],sect, &embr)) {
  584.       fprintf(stderr,"drive %d extended partition %d sub-partition %d\n",drive,part,ii);
  585.       err_exit("can't read partition header");
  586.     }
  587.     if (embr.bootmagic != 0xAA55) return;
  588.  
  589.     printf(
  590.       " log-part. %d   %ld Mb   %s\n",
  591.       ii+4,
  592.       embr.partitions[0].total_sectors / (2*1024),
  593.       decode_partition_type(embr.partitions[0].partion_type)
  594.     );
  595.     if (   (embr.partitions[1].partion_type != 5)
  596.         || !embr.partitions[1].total_sectors ) return;
  597.     sect= sect0+embr.partitions[1].start_sector;
  598.   }
  599. }
  600.  
  601. print_partitions_of(int drive)
  602. {
  603.   int i,ptype;
  604.   char *bootable;
  605.   printf("drive %d  ==  Linux device: /dev/%cd%c\n",
  606.           drive,drives[drive].linux_dev,'a'+drive);
  607.   for (i=0; i<4; i++) {
  608.     ptype=drives[drive].mbr.partitions[i].partion_type;
  609.     if (!ptype) return;
  610.     if (drives[drive].mbr.partitions[i].bootable_flag) bootable="  bootable";
  611.     else bootable="";
  612.     printf(
  613.       " partition %d   %ld Mb   %s%s\n",
  614.       i+1,
  615.       drives[drive].mbr.partitions[i].total_sectors / (2*1024),
  616.       decode_partition_type(ptype),
  617.       bootable
  618.     );
  619.     if (ptype == 5) print_extended_partitions_of(drive, i);
  620.   }
  621. }
  622.  
  623. int get_extended_partitions_of(int drive, char dosdrive, char *currentdrive)
  624. {
  625.   int i,ii;
  626.   partition_typ *p;
  627.   unsigned long sect0,sect;
  628.   for (i=0; i<4; i++) {
  629.     if (drives[drive].mbr.partitions[i].partion_type == 5) {
  630.       /* found an extended partition, and walk through the chain
  631.          of partition header only to count.
  632.  
  633.            Comment from Linus Thorvalds (linux/drivers/block/genhd.c):
  634.            >>>
  635.            * The logical partitions form a linked list, with each entry being
  636.            * a partition table with two entries.  The first entry
  637.            * is the real data partition (with a start relative to the partition
  638.            * table start).  The second is a pointer to the next logical partition
  639.            * (with a start relative to the entire extended partition).
  640.            <<< end comment.
  641.       */
  642.       drives[drive].mbr.partitions[i].partion_type=0; /* avoid reusage */
  643.       sect0=drives[drive].mbr.partitions[i].start_sector;
  644.       sect=sect0;
  645.       for (ii=1; ii<16 ;ii++) {
  646.         if (logical_disk_read(&drives[drive],sect, &embr)) {
  647.           fprintf(stderr,"drive %d extended partition %d sub-partition %d\n",drive,i,ii);
  648.           err_exit("can't read partition header");
  649.         }
  650.         if (embr.bootmagic != 0xAA55) return ii-1;
  651.         switch (embr.partitions[0].partion_type) {
  652.           case 1:
  653.           case 4:
  654.           case 6: {
  655.             if (*currentdrive == dosdrive) return ii;
  656.             (*currentdrive)++;
  657.             break;
  658.           }
  659.         }
  660.         if (   (embr.partitions[1].partion_type != 5)
  661.             || !embr.partitions[1].total_sectors ) return -1;
  662.         sect= sect0+embr.partitions[1].start_sector;
  663.       }
  664.     }
  665.   }
  666.   return -1;
  667. }
  668.  
  669. assemble_devname_(int drive, int part, char *linuxdev)
  670. {
  671.   strcpy(linuxdev,"root=/dev/");
  672.   linuxdev += 10;
  673.   *linuxdev++ = drives[drive].linux_dev;
  674.   *linuxdev++ = 'd';
  675.   *linuxdev++ = 'a'+drive;
  676.   itoa(part,linuxdev,10);
  677. }
  678.  
  679. int assemble_devname(int drive, int part, char dosdrive, char *d, char *linuxdev)
  680. {
  681.   if (part<=0) return -1;
  682.   if (dosdrive == *d) {
  683.     assemble_devname_(drive,part,linuxdev);
  684.     return 0;
  685.   }
  686.   (*d)++;
  687.   return 1;
  688. }
  689.  
  690. char *search_drive(char dosdrive, char *linuxdev)
  691. {
  692.   char d;
  693.   int part,i;
  694.  
  695.   dosdrive= tolower(dosdrive);
  696.  
  697.   if (verbose_only) for (i=0; i<num_drives; i++) print_partitions_of(i);
  698.  
  699.   /*
  700.      DOS-FDISK doesn't create an extended partion on a drive,
  701.      that has no primary partition. It only creates max 1 primary
  702.      and 1 extended partition.
  703.      Under Linux, however, it is possible to create more than
  704.      one primary DOS-partition (types 1,4,6). And also possible
  705.      is the creation of a drive, which has only an extended partion.
  706.      DOS, nevertheless can work with these partions, so we have
  707.      do be aware of it.
  708.  
  709.      After doing heavy testing with multiple combinations under MSDOS 6.2
  710.      I guess the following strategie is used by DOS to assign
  711.      drive letters (C:, D:, ..) to partions:
  712.  
  713.      1. DOS searches upwards for appropriate partion-entries in the MBR
  714.         ( 0,1,2,3 )
  715.         Be not confused with partion numbering of DOS-FDISK,
  716.         it sorts the partions by sizes, not by there entry in the MBR.
  717.         Seems that MS likes do have the things nice on the screen,
  718.         regardless of internal order (...sh.. ).
  719.  
  720.      2. Beginning with "C:" DOS searches for a PRI-DOS with "bootable-flag"
  721.         on drive 0, then on drive 1.
  722.         If it can find any, it searches for an unflagged PRI-DOS,
  723.         first on drive 0, then on drive 1.
  724.         NOTE 1:
  725.           "bootable-flag" can also be set on drive 1 PRI-DOS
  726.            with the effect, that this partition becomes "D:",
  727.            even if there is an other PRI-DOS with lower partition number.
  728.         NOTE 2:
  729.           If DOS can't find any PRI-DOS on drive 0, but on drive 1,
  730.           then (..surprise..) it assigns "C:" on drive 1 !
  731.  
  732.      3. After (if possible) having assigned at minum one PRI-DOS
  733.         for both drives, it stops assigning PRI-DOS and continues
  734.         with the extended partion on drive 0.
  735.         It assignes ALL sub-partitions in the extended partion (type 5),
  736.         which have DOS-types (1,4,6) in there proper order.
  737.         If there are non-DOS partions, the are skipped.
  738.  
  739.      4. If there are some PRI-DOS partitions remaining on drive 0
  740.         they are now assigned.
  741.  
  742.      5. Then it goes to drive 1, doing steps 3. and 4. accordingly.
  743.  
  744.  
  745.      For better understanding here some examples:
  746.  
  747.      EXAMPLE 1
  748.  
  749.        drive 0:
  750.          part 0             PRI-DOS        G:
  751.          part 1  bootable   PRI-DOS        C:
  752.          part 2             extended       none
  753.          part 3             PRI-DOS        H:
  754.          ext-part 1         DOS            E:
  755.          ext-part 2         Linux
  756.          ext-part 3         DOS            F:
  757.  
  758.        drive 1:
  759.          part 0             PRI-DOS        I:
  760.          part 1             Linux-native   none
  761.          part 2  bootable   PRI-DOS        D:
  762.          part 3             PRI-DOS        J:
  763.  
  764.      EXAMPLE 2
  765.  
  766.        drive 0:
  767.          part 0             extended       none
  768.          ext-part 1         DOS            D:
  769.          ext-part 2         DOS            E:
  770.  
  771.        drive 1:
  772.          part 0             PRI-DOS        C:    (but you can't boot from it)
  773.          part 1             Linux-native   none
  774.  
  775.      Isn't it nice ? (..why simple, if we can have it complicated..)
  776.   */
  777.  
  778.  
  779.   d = 'c';   /* we start with 'C:' */
  780.  
  781.     /* first search for a bootable partition on drive 0 */
  782.   part=get_bootpartition_of(0);
  783.   if (!assemble_devname(0,part,dosdrive,&d,linuxdev)) return linuxdev;
  784.   if (part<=0) {
  785.       /* then search for a primary partition on drive 0 */
  786.     part=get_primary_partition_of(0);
  787.     if (!assemble_devname(0,part,dosdrive,&d,linuxdev)) return linuxdev;
  788.   }
  789.  
  790.     /* then search for a bootable partition on drive 1 */
  791.   part=get_bootpartition_of(1);
  792.   if (!assemble_devname(1,part,dosdrive,&d,linuxdev)) return linuxdev;
  793.   if (part<=0) {
  794.       /* then search for a primary partition on drive 1 */
  795.     part=get_primary_partition_of(1);
  796.     if (!assemble_devname(1,part,dosdrive,&d,linuxdev)) return linuxdev;
  797.   }
  798.  
  799.     /* now we go back to drive 0, assigning all we have,
  800.        but first the extended partions */
  801.   part=get_extended_partitions_of(0,dosdrive,&d);
  802.   if (part>0) {
  803.     if (dosdrive == d) {
  804.       assemble_devname_(0,4+part,linuxdev);
  805.       return linuxdev;
  806.     }
  807.   }
  808.     /* now the rest of drive 0 */
  809.   do {
  810.     part=get_primary_partition_of(0);
  811.     if (!assemble_devname(0,part,dosdrive,&d,linuxdev)) return linuxdev;
  812.   } while (part>0);
  813.  
  814.  
  815.     /* now we go to drive 1, assigning all we have,
  816.        but first the extended partions */
  817.   part=get_extended_partitions_of(1,dosdrive,&d);
  818.   if (part>0) {
  819.     if (dosdrive == d) {
  820.       assemble_devname_(1,4+part,linuxdev);
  821.       return linuxdev;
  822.     }
  823.   }
  824.     /* now the rest of drive 1 */
  825.   do {
  826.     part=get_primary_partition_of(1);
  827.     if (!assemble_devname(1,part,dosdrive,&d,linuxdev)) return linuxdev;
  828.   } while (part>0);
  829.  
  830.     /* we come here if dosdrive couldn't be translated */
  831.   return 0;
  832. }
  833.  
  834. int parse_for_arg(char *search, int n,char **argv)
  835. {
  836.   int i=0;
  837.   while (*argv) {
  838.     if (n) {
  839.       if (!strnicmp(*argv++,search,n)) return i;
  840.     } else {
  841.       if (!stricmp(*argv++,search)) return i;
  842.     }
  843.     i++;
  844.   }
  845.   return 0;
  846. }
  847.  
  848. void delete_arg(int arg, int *argc, char **argv)
  849. {
  850.   memcpy(argv+arg,argv+arg+1,(*argc+1-arg)*4);
  851.   (*argc)--;
  852. }
  853.  
  854. typedef struct {
  855.   unsigned short jmp_op;           /*   jmp     short start_of_setup  */
  856.   unsigned long  setup_header_sign;
  857.   unsigned short setup_header_version;
  858.   void *         setup_realmode_switch;
  859.   unsigned short start_sys_seg;
  860.   unsigned short kernel_version;
  861. } setup_header;
  862.  
  863. #define SIGNATURE 0x53726448       /* setup header signature */
  864.  
  865. char * get_kernel_version_string(char *fname,char *buf,int sizebuf)
  866. {
  867.   int f;
  868.   setup_header h;
  869.   if ((f=_open(fname, O_RDONLY)) == -1 ) {
  870.      perror(fname);
  871.      err_exit("can't open image file");
  872.   }
  873.   lseek(f,0x200,SEEK_SET);
  874.   if (read(f,&h,sizeof(h)) != sizeof(h)) {
  875.     _close(f);
  876.     err_exit("image has wrong format");
  877.   }
  878.   if ((h.setup_header_sign == SIGNATURE) && (h.setup_header_version >= 0x105)) {
  879.     lseek(f,0x200+h.kernel_version,SEEK_SET);
  880.     if (read(f,buf,sizebuf) == sizebuf) return buf;
  881.   }
  882.   _close(f);
  883.   return 0;
  884. }
  885.  
  886. long int value_of(char **s)
  887. {
  888.   int i=0;
  889.   char s_[30];
  890.   while (isdigit(**s)) s_[i++]=*(*s)++;
  891.   s_[i]=0;
  892.   *(*s)++;        /* this code HAS effect, though TURBO-C states that not */
  893.   return atoi(s_);
  894. }
  895.  
  896. unsigned long version_string_to_binary(char *vstring)
  897. {
  898.    unsigned long v=0;
  899.    char *s;
  900.    v =value_of(&vstring);
  901.    v <<=8;
  902.    v +=value_of(&vstring);
  903.    v <<=8;
  904.    v +=value_of(&vstring);
  905.    v <<=8;
  906.    if (vstring=strchr(vstring-1,'#')) {
  907.      vstring++;
  908.      v +=value_of(&vstring);
  909.    }
  910. /*   printf(">%08lx<\n",v);  */
  911.    return v;
  912. }
  913.  
  914. void  check_kernel_version(char *imagename, char *version)
  915. {
  916.   unsigned long v_desired;
  917.   unsigned long v_actual;
  918.   int check_below=0, ok;
  919.   char buf[128];
  920.  
  921.   if (get_kernel_version_string(imagename,buf,sizeof(buf))) {
  922.     if (version[0]=='-') {
  923.       check_below=1;
  924.       version++;
  925.     }
  926.     v_desired=version_string_to_binary(version);
  927.     v_actual=version_string_to_binary(buf);
  928.     if (!(v_desired & 0xff)) v_actual &= ~0xFF;
  929.     if (check_below) ok= v_actual <= v_desired;
  930.     else ok= v_actual >= v_desired;
  931.     if (!ok) err_exit("wrong kernel version");
  932.   }
  933.   else err_exit("setup of image file has no version stamp, can\'t verify");
  934. }
  935.  
  936. void print_version_string(char *image)
  937. {
  938.   char buf[128];
  939.   if (get_kernel_version_string(image,buf,sizeof(buf))) {
  940.     fprintf(stderr, "\n%s  %s\n",image,buf);
  941.     err_exit(0);
  942.   }
  943.   else err_exit("setup of image file has no version stamp");
  944. }
  945.  
  946.  
  947. /* -------------- response-file stuff -------------- */
  948.  
  949. FILE * fparam_in=0;
  950.  
  951. param_read_close()
  952. {
  953.   if (fparam_in) fclose(fparam_in);
  954.   fparam_in=0;
  955. }
  956.  
  957. void param_read_open(char *fname)
  958. {
  959.   param_read_close();
  960.   if ((fparam_in=fopen(fname, "rt")) == 0 ) {
  961.      perror(fname);
  962.      err_exit("can't open params file");
  963.   }
  964. }
  965.  
  966. #define MAX_OUR_ARGS 50
  967. char *our_argv[MAX_OUR_ARGS+1]={0};
  968. int  our_argc=0;
  969. typedef struct {
  970.   unsigned short opint20;
  971.   unsigned short memend_frame;
  972.   unsigned char  dos_reserved4;
  973.   unsigned char  cpm_function_entry[0xa-0x5];
  974.   unsigned long  int22_copy;
  975.   unsigned long  int23_copy;
  976.   unsigned long  int24_copy;
  977.   unsigned short PID;
  978.   unsigned char  file_handles[20];
  979.   unsigned short envir_frame;
  980.   unsigned long  system_stack;
  981.   unsigned short max_open_files;
  982.   unsigned long  file_handles_ptr;
  983.   unsigned char  dos_reserved38[0x50-0x38];
  984.   unsigned char  high_language_dos_call[0x53-0x50];
  985.   unsigned char  dos_reserved53[0x5c-0x53];
  986.   unsigned char  FCB1[0x6c-0x5c];
  987.   unsigned char  FCB2[0x80-0x6c];
  988.   unsigned char  DTA[0x100-0x80];
  989. } dos_segprefix;
  990.  
  991.  
  992. static build_param_buf(char **argv)
  993. {
  994.   dos_segprefix *psp=MK_FP(_psp,0);
  995.   unsigned segp;
  996.   int ret;
  997.   unsigned char *param_buf=(void *)0x90200000;
  998.  
  999.   ret=allocmem(0x1000,&segp);
  1000.   freemem(segp);
  1001.   if (ret==-1 && segp<0x9000) {
  1002.     if (psp->memend_frame >0x9c00) {
  1003.       argv++;  /* skip argv[0] ( the program name ) */
  1004.       while (*argv) param_buf+=sprintf(param_buf,"%s\n",*argv++);
  1005.       *param_buf=0;
  1006.     }
  1007.     else err_exit("not enough memory at top of 0x9C000, can\'t pass params to LOADLIN.EXE");
  1008.   }
  1009.   else err_exit("not enough memory starting at 0x90000, can\'t pass params to LOADLIN.EXE");
  1010. }
  1011.  
  1012. static put_our_arg(char *arg)
  1013. {
  1014. /*   printf(">%s<\n",arg); */
  1015.    if (our_argc<MAX_OUR_ARGS) {
  1016.      our_argv[our_argc]=strdup(arg);
  1017.      if (our_argv[our_argc]) our_argc++;
  1018.      our_argv[our_argc]=0;
  1019.    }
  1020. }
  1021.  
  1022. void get_params_from_file(char *fname)
  1023. {
  1024.    int c,i=0;
  1025.    char buf[256];
  1026.  
  1027.    param_read_open(fname);
  1028.    while ((c=fgetc(fparam_in)) !=EOF) {
  1029.      switch (c) {
  1030.        case '#': {
  1031.          do {
  1032.            c=fgetc(fparam_in);
  1033.          } while ((c !=EOF) && (c!='\n') );
  1034.          ungetc(c,fparam_in);
  1035.          break;
  1036.        }
  1037.        case '\n':
  1038.        case ' ':
  1039.        case '\t':
  1040.        {
  1041.          if (i) {
  1042.            buf[i]=0;
  1043.            put_our_arg(buf);
  1044.            i=0;
  1045.          }
  1046.          break;
  1047.        }
  1048.        default: {
  1049.          buf[i++]=c;
  1050.          break;
  1051.        }
  1052.      }
  1053.    }
  1054.    if (i) {
  1055.      buf[i]=0;
  1056.      put_our_arg(buf);
  1057.      i=0;
  1058.    }
  1059.    param_read_close();
  1060. }
  1061.  
  1062.  
  1063. /* -------------- end response-file stuff -------------- */
  1064.  
  1065.  
  1066. main(int argc, char **argv)
  1067. {
  1068.   int i,root;
  1069.   char lname[80];
  1070.   int have_responsefile=0;
  1071.  
  1072.  
  1073.   if (getenv("COMSPEC")) can_exit_to_dos=1;
  1074. #if DEBUGGING
  1075.   if (i=parse_for_arg("--dg",0,argv)) {
  1076.     generate_virtual_drive_manually();
  1077.     err_exit("Ok");
  1078.   }
  1079.   if (i=parse_for_arg("--di",0,argv)) {
  1080.     delete_arg(i, &argc, argv);
  1081.     if (argv[i]) {
  1082.       debug_read_open(argv[i]);
  1083.       delete_arg(i, &argc, argv);
  1084.     }
  1085.   }
  1086.   if (i=parse_for_arg("--do",0,argv)) {
  1087.     delete_arg(i, &argc, argv);
  1088.     if (argv[i]) {
  1089.       debug_write_open(argv[i]);
  1090.       delete_arg(i, &argc, argv);
  1091.     }
  1092.   }
  1093. #endif
  1094.  
  1095.   if (i=parse_for_arg("--dv",0,argv)) {
  1096.     delete_arg(i, &argc, argv);
  1097.     verbose_only=1;
  1098.   }
  1099.  
  1100.  
  1101.   if (i=parse_for_arg("@",1,argv)) {
  1102.     char **_argv=argv+1;
  1103.     char *c,j;
  1104.     put_our_arg(argv[0]);
  1105.     get_params_from_file(argv[i]+1);
  1106.     have_responsefile=1;
  1107.     if (i>1) _argv++;
  1108.     while (*_argv) {
  1109.       if (strcmp(*_argv,argv[i])) {
  1110.         if (c=strchr(*_argv,'=')) {
  1111.           j=parse_for_arg(*_argv,(c-*_argv)+1,our_argv);
  1112.           if (j) our_argv[j]=*_argv;
  1113.           else put_our_arg(*_argv);
  1114.         }
  1115.         else {
  1116.           if (!(parse_for_arg(*_argv,0,our_argv))) {
  1117.             if (!strcmp("ro",*_argv)) {
  1118.               if (j=(parse_for_arg("rw",0,our_argv))) our_argv[j]=*_argv;
  1119.               else put_our_arg(*_argv);
  1120.             }
  1121.             else {
  1122.               if (!strcmp("rw",*_argv)) {
  1123.                 if (j=(parse_for_arg("ro",0,our_argv))) our_argv[j]=*_argv;
  1124.                 else put_our_arg(*_argv);
  1125.               }
  1126.               else put_our_arg(*_argv);
  1127.             }
  1128.           }
  1129.         }
  1130.       }
  1131.       _argv++;
  1132.     }
  1133.     if (i>1) our_argv[1]=argv[1];
  1134.     argv=(char **)&our_argv;
  1135.     argc=our_argc;
  1136.   }
  1137.   if ( (root=parse_for_arg("root=",5,argv)) && (argv[root][6] == ':') ) {
  1138.     int drivenum=tolower(argv[root][5]);
  1139.     if (drivenum >= 'c') {
  1140.       first_check();
  1141.       second_check();
  1142.       if (!search_drive(argv[root][5],devname)) err_exit("can't translate root device");
  1143.     }
  1144.     else {
  1145.       if (drivenum == 'a') strcpy(devname,"root=/dev/fd0");
  1146.       else strcpy(devname,"root=/dev/fd1");
  1147.     }
  1148.     argv[root]=devname;
  1149.   }
  1150.   else {
  1151.     if (verbose_only) {
  1152.       first_check();
  1153.       second_check();
  1154.       search_drive('z',devname);
  1155. /*      err_exit(0); */
  1156.     }
  1157.   }
  1158.  
  1159.   if (i=parse_for_arg("--version=",10,argv)) {
  1160.     check_kernel_version(argv[1],argv[i]+10);
  1161.     delete_arg(i, &argc, argv);
  1162.   }
  1163.   if (i=parse_for_arg("--version",0,argv)) {
  1164.     print_version_string(argv[1]);
  1165.     /* doesn't return */
  1166.   }
  1167.  
  1168.  
  1169.  
  1170.   strcpy(lname,argv[0]);
  1171.   for (i=strlen(lname); lname[i] !='\\' ; i--);
  1172.   strcpy(lname+i+1,"LOADLIN.EXE");
  1173.   if (verbose_only) {
  1174.     fprintf(stderr,"\n  %s would be started with following command line:\n\n ",lname);
  1175.     argv++;
  1176.     while (*argv) fprintf(stderr," %s",*argv++);
  1177.     err_exit("\n");
  1178.   }
  1179.   else {
  1180.     if (have_responsefile) {
  1181.       build_param_buf(argv);
  1182.       argv[1]="@@loadlinx@@";
  1183.       argv[2]=0;
  1184.     }
  1185.     if (execv(lname,argv) == -1) err_exit("can't find/execute LOADLIN.EXE");
  1186.   }
  1187. }
  1188.