home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / mtools_3.6.src.lzh / MTOOLS_3.6 / mpartition.c < prev    next >
Text File  |  1997-11-12  |  15KB  |  630 lines

  1. /*
  2.  * mformat.c
  3.  */
  4.  
  5. #include "sysincludes.h"
  6. #include "msdos.h"
  7. #include "mtools.h"
  8. #include "mainloop.h"
  9. #include "fsP.h"
  10. #include "file.h"
  11. #include "plain_io.h"
  12. #include "nameclash.h"
  13. #include "buffer.h"
  14. #include "scsi.h"
  15. #include "partition.h"
  16.  
  17. #include <math.h>
  18.  
  19. #define tolinear(x) \
  20. (sector(x)-1+(head(x)+cyl(x)*used_dev.heads)*used_dev.sectors)
  21.  
  22.  
  23. static inline void print_hsc(hsc *h)
  24. {
  25.     printf(" h=%d s=%d c=%d\n", 
  26.            head(*h), sector(*h), cyl(*h));
  27. }
  28.  
  29. static void set_offset(hsc *h, int offset, int heads, int sectors)
  30. {
  31.     int head, sector, cyl;
  32.  
  33.     if(! heads || !sectors)
  34.         head = sector = cyl = 0; /* linear mode */
  35.     else {
  36.         sector = offset % sectors;
  37.         offset = offset / sectors;
  38.  
  39.         head = offset % heads;
  40.         cyl = offset / heads;
  41.     }
  42.  
  43.     h->head = head;
  44.     h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
  45.     h->cyl = cyl & 0xff;
  46. }
  47.  
  48. /* setsize function.  Determines scsicam mapping if this cannot be inferred from
  49.  * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
  50.  
  51. /*
  52.  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
  53.  *    unsigned int *hds, unsigned int *secs);
  54.  *
  55.  * Purpose : to determine a near-optimal int 0x13 mapping for a
  56.  *    SCSI disk in terms of lost space of size capacity, storing
  57.  *    the results in *cyls, *hds, and *secs.
  58.  *
  59.  * Returns : -1 on failure, 0 on success.
  60.  *
  61.  * Extracted from
  62.  *
  63.  * WORKING                                                    X3T9.2
  64.  * DRAFT                                                        792D
  65.  *
  66.  *
  67.  *                                                        Revision 6
  68.  *                                                         10-MAR-94
  69.  * Information technology -
  70.  * SCSI-2 Common access method
  71.  * transport and SCSI interface module
  72.  * 
  73.  * ANNEX A :
  74.  *
  75.  * setsize() converts a read capacity value to int 13h
  76.  * head-cylinder-sector requirements. It minimizes the value for
  77.  * number of heads and maximizes the number of cylinders. This
  78.  * will support rather large disks before the number of heads
  79.  * will not fit in 4 bits (or 6 bits). This algorithm also
  80.  * minimizes the number of sectors that will be unused at the end
  81.  * of the disk while allowing for very large disks to be
  82.  * accommodated. This algorithm does not use physical geometry. 
  83.  */
  84.  
  85. static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
  86.     unsigned int *secs) { 
  87.     unsigned int rv = 0; 
  88.     unsigned long heads, sectors, cylinders, temp; 
  89.  
  90.     cylinders = 1024L;            /* Set number of cylinders to max */ 
  91.     sectors = 62L;              /* Maximize sectors per track */ 
  92.  
  93.     temp = cylinders * sectors;        /* Compute divisor for heads */ 
  94.     heads = capacity / temp;        /* Compute value for number of heads */
  95.     if (capacity % temp) {        /* If no remainder, done! */ 
  96.         heads++;                    /* Else, increment number of heads */ 
  97.         temp = cylinders * heads;    /* Compute divisor for sectors */ 
  98.         sectors = capacity / temp;    /* Compute value for sectors per
  99.                            track */ 
  100.         if (capacity % temp) {        /* If no remainder, done! */ 
  101.               sectors++;                  /* Else, increment number of sectors */ 
  102.               temp = heads * sectors;    /* Compute divisor for cylinders */
  103.               cylinders = capacity / temp;/* Compute number of cylinders */ 
  104.           } 
  105.     } 
  106.     if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ 
  107.  
  108.     *cyls = (unsigned int) cylinders;    /* Stuff return values */ 
  109.     *secs = (unsigned int) sectors; 
  110.     *hds  = (unsigned int) heads; 
  111.     return(rv); 
  112.  
  113. static void setsize0(unsigned long capacity,unsigned int *cyls,
  114.              unsigned int *hds, unsigned int *secs)
  115. {
  116.     int r;
  117.  
  118.     /* 1. First try "Megabyte" sizes */
  119.     if(capacity < 1024 * 2048 && !(capacity % 1024)) {
  120.         *cyls = capacity >> 11;
  121.         *hds  = 64;
  122.         *secs = 32;
  123.         return;
  124.     }
  125.  
  126.     /* then try scsicam's size */
  127.     r = setsize(capacity,cyls,hds,secs);
  128.     if(r || *hds > 255 || *secs > 63) {
  129.         /* scsicam failed. Do megabytes anyways */
  130.         *cyls = capacity >> 11;
  131.         *hds  = 64;
  132.         *secs = 32;
  133.         return;
  134.     }
  135. }
  136.  
  137.  
  138. static void usage(void)
  139. {
  140.     fprintf(stderr, 
  141.         "Mtools version %s, dated %s\n", mversion, mdate);
  142.     fprintf(stderr, 
  143.         "Usage: %s [-prIadcv] [-s sectors] [-t cylinders] "
  144.         "[-h heads] [-T type] [-b begin] [-l length] "
  145.         "drive\n", progname);
  146.     exit(1);
  147. }
  148.  
  149. void mpartition(int argc, char **argv, int dummy)
  150. {
  151.     Stream_t *Stream;
  152.     unsigned int dummy2;
  153.  
  154.     int i,j;
  155.  
  156.     int sec_per_cyl;
  157.     int doprint = 0;
  158.     int verbose = 0;
  159.     int create = 0;
  160.     int force = 0;
  161.     int length = 0;
  162.     int remove = 0;
  163.     int initialize = 0;
  164.     int tot_sectors=0;
  165.     int type = 0;
  166.     int begin_set = 0;
  167.     int size_set = 0;
  168.     int end_set = 0;
  169.     int last_end = 0;
  170.     int activate = 0;
  171.     int has_activated = 0;
  172.     int inconsistency=0;
  173.     int begin=0;
  174.     int end=0;
  175.     int sizetest=0;
  176.     int dirty = 0;
  177.     int open2flags = NO_OFFSET;
  178.     
  179.     int c;
  180.     struct device used_dev;
  181.     int argtracks, argheads, argsectors;
  182.  
  183.     char drive, name[EXPAND_BUF];
  184.     unsigned char buf[512];
  185.     struct partition *partTable=(struct partition *)(buf+ 0x1ae);
  186.     struct device *dev;
  187.     char errmsg[200];
  188.  
  189.     argtracks = 0;
  190.     argheads = 0;
  191.     argsectors = 0;
  192.  
  193.     /* get command line options */
  194.     while ((c = getopt(argc, argv, "adprcIT:t:h:s:fvpb:l:S:")) != EOF) {
  195.         switch (c) {
  196.             case 'a':
  197.                 /* no privs, as it could be abused to
  198.                  * make other partitions unbootable, or
  199.                  * to boot a rogue kernel from this one */
  200.                 open2flags |= NO_PRIV;
  201.                 activate = 1;
  202.                 dirty = 1;
  203.                 break;
  204.             case 'd':
  205.                 activate = -1;
  206.                 dirty = 1;
  207.                 break;
  208.             case 'p':
  209.                 doprint = 1;
  210.                 break;
  211.             case 'r':
  212.                 remove = 1;
  213.                 dirty = 1;
  214.                 break;
  215.             case 'I':
  216.                 /* could be abused to nuke all other 
  217.                  * partitions */
  218.                 open2flags |= NO_PRIV;
  219.                 initialize = 1;
  220.                 dirty = 1;
  221.                 break;
  222.             case 'c':
  223.                 create = 1;
  224.                 dirty = 1;
  225.                 break;
  226.  
  227.             case 'T':
  228.                 /* could be abused to "manually" create
  229.                  * extended partitions */
  230.                 open2flags |= NO_PRIV;
  231.                 type = strtoul(optarg,0,0);
  232.                 break;
  233.  
  234.             case 't':
  235.                 argtracks = atoi(optarg);
  236.                 break;
  237.             case 'h':
  238.                 argheads = atoi(optarg);
  239.                 break;
  240.             case 's':
  241.                 argsectors = atoi(optarg);
  242.                 break;
  243.  
  244.             case 'f':
  245.                 /* could be abused by creating overlapping
  246.                  * partitions and other such Snafu */
  247.                 open2flags |= NO_PRIV;
  248.                 force = 1;
  249.                 break;
  250.  
  251.             case 'v':
  252.                 verbose++;
  253.                 break;
  254.             case 'S':
  255.                 /* testing only */
  256.                 /* could be abused to create partitions
  257.                  * extending beyond the actual size of the
  258.                  * device */
  259.                 open2flags |= NO_PRIV;
  260.                 tot_sectors = strtoul(optarg,0,0);
  261.                 sizetest = 1;
  262.                 break;
  263.             case 'b':
  264.                 begin_set = 1;
  265.                 begin = atoi(optarg);
  266.                 break;
  267.             case 'l':
  268.                 size_set = 1;
  269.                 length = atoi(optarg);
  270.                 break;
  271.  
  272.             default:
  273.                 usage();
  274.         }
  275.     }
  276.  
  277.     if (argc - optind != 1 ||
  278.         !argv[optind][0] || argv[optind][1] != ':')
  279.         usage();
  280.     
  281.     drive = toupper(argv[optind][0]);
  282.  
  283.     /* check out a drive whose letter and parameters match */    
  284.     sprintf(errmsg, "Drive '%c:' not supported", drive);    
  285.     for(dev=devices;dev->drive;dev++) {
  286.         FREE(&(Stream));
  287.         /* drive letter */
  288.         if (dev->drive != drive)
  289.             continue;
  290.         if (dev->partition < 1 || dev->partition > 4) {
  291.             sprintf(errmsg, 
  292.                 "Drive '%c:' is not a partition", 
  293.                 drive);
  294.             continue;
  295.         }
  296.         used_dev = *dev;
  297.  
  298.         SET_INT(used_dev.tracks, argtracks);
  299.         SET_INT(used_dev.heads, argheads);
  300.         SET_INT(used_dev.sectors, argsectors);
  301.         
  302.         expand(dev->name, name);
  303.         Stream = SimpleFileOpen(&used_dev, dev, name,
  304.                     dirty ? O_RDWR : O_RDONLY, 
  305.                     errmsg, open2flags);
  306.  
  307.         if (!Stream) {
  308.             sprintf(errmsg,"init: open: %s", strerror(errno));
  309.             continue;
  310.         }            
  311.  
  312.  
  313.         /* try to find out the size */
  314.         if(!sizetest)
  315.             tot_sectors = 0;
  316.         if(dev->scsi) {
  317.             unsigned char cmd[10];
  318.             unsigned char data[10];
  319.             cmd[0] = SCSI_READ_CAPACITY;
  320.             memset ((void *) &cmd[2], 0, 8);
  321.             memset ((void *) &data[0], 137, 10);
  322.             scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
  323.                  data, 10);
  324.             
  325.             tot_sectors = 1 +
  326.                 (data[0] << 24) +
  327.                 (data[1] << 16) +
  328.                 (data[2] <<  8) +
  329.                 (data[3]      );
  330.             if(verbose)
  331.                 printf("%d sectors in total\n", tot_sectors);
  332.         }
  333.  
  334.         /* read the partition table */
  335.         if (READS(Stream, (char *) buf, 0, 512) != 512) {
  336.             sprintf(errmsg, 
  337.                 "Error reading from '%s', wrong parameters?",
  338.                 name);
  339.             continue;
  340.         }
  341.         if(verbose>=2)
  342.             print_sector("Read sector", buf);
  343.         break;
  344.     }
  345.  
  346.     /* print error msg if needed */    
  347.     if ( dev->drive == 0 ){
  348.         FREE(&Stream);
  349.         fprintf(stderr,"%s: %s\n", argv[0],errmsg);
  350.         exit(1);
  351.     }
  352.  
  353.     if((used_dev.sectors || used_dev.heads) &&
  354.        (!used_dev.sectors || !used_dev.heads)) {
  355.         fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n");
  356.         fprintf(stderr," or none of them\n");
  357.         exit(1);
  358.     }
  359.  
  360.     if(initialize) {
  361.         memset((char *)(partTable+1), 0, 4*sizeof(*partTable));
  362.         buf[510] = 0x55;
  363.         buf[511] = 0xaa;
  364.     }
  365.  
  366.     /* check for boot signature, and place it if needed */
  367.     if((buf[510] != 0x55) || (buf[511] != 0xaa)) {
  368.         fprintf(stderr,"Boot signature not set\n");
  369.         fprintf(stderr,
  370.             "Use the -I flag to initialize the partition table, and set the boot signature\n");
  371.         inconsistency = 1;
  372.     }
  373.     
  374.     if(remove){
  375.         if(!partTable[dev->partition].sys_ind)
  376.             fprintf(stderr,
  377.                 "Partition for drive %c: does not exist\n",
  378.                 drive);
  379.         if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
  380.             fprintf(stderr,
  381.                 "Partition for drive %c: may be an extended partition\n",
  382.                 drive);
  383.             fprintf(stderr,
  384.                 "Use the -f flag to remove it anyways\n");
  385.             inconsistency = 1;
  386.         }
  387.         memset(&partTable[dev->partition], 0, sizeof(*partTable));
  388.     }
  389.  
  390.     if(create && partTable[dev->partition].sys_ind) {
  391.         fprintf(stderr,
  392.             "Partition for drive %c: already exists\n", drive);
  393.         fprintf(stderr,
  394.             "Use the -r flag to remove it before attempting to recreate it\n");
  395.     }
  396.  
  397.  
  398.     /* find out number of heads and sectors, and whether there is
  399.     * any activated partition */
  400.     has_activated = 0;
  401.     for(i=1; i<5; i++){
  402.         if(!partTable[i].sys_ind)
  403.             continue;
  404.         
  405.         if(partTable[i].boot_ind)
  406.             has_activated++;
  407.  
  408.         /* set geometry from entry */
  409.         if (!used_dev.heads)
  410.             used_dev.heads = head(partTable[i].end)+1;
  411.         if(!used_dev.sectors)
  412.             used_dev.sectors = sector(partTable[i].end);
  413.         if(i<dev->partition && !begin_set)
  414.             begin = END(partTable[i]);
  415.         if(i>dev->partition && !end_set && !size_set) {
  416.             end = BEGIN(partTable[i]);
  417.             end_set = 1;
  418.         }
  419.     }
  420.     
  421.     if(!used_dev.sectors && !used_dev.heads) {
  422.         if(tot_sectors)
  423.             setsize0(tot_sectors,&dummy2,&used_dev.heads,
  424.                  &used_dev.sectors);
  425.         else {
  426.             used_dev.heads = 64;
  427.             used_dev.heads = 32;
  428.         }
  429.     }
  430.  
  431.     if(verbose)
  432.         fprintf(stderr,"sectors: %d heads: %d\n",
  433.             used_dev.sectors, used_dev.heads);
  434.  
  435.     sec_per_cyl = used_dev.sectors * used_dev.heads;
  436.     if(create) {
  437.         if(!end_set && tot_sectors) {
  438.             end = tot_sectors - tot_sectors % sec_per_cyl;
  439.             end_set = 1;
  440.         }
  441.         
  442.         /* if the partition starts right at the beginning of
  443.          * the disk, keep one track unused to allow place for
  444.          * the master boot record */
  445.         if(!begin && !begin_set)
  446.             begin = used_dev.sectors;
  447.         if(!size_set && used_dev.tracks) {
  448.             size_set = 2;
  449.             length = sec_per_cyl * used_dev.tracks;
  450.  
  451.             /*  round the size in order to take
  452.              * into account any "hidden" sectors */
  453.  
  454.             /* do we anchor this at the beginning ?*/
  455.             if(begin_set || dev->partition <= 2 || !end_set)
  456.                 length -= begin % sec_per_cyl;
  457.             else if(end - length < begin)
  458.                 /* truncate any overlap */
  459.                 length = end - begin;
  460.         }
  461.         if(size_set) {
  462.             if(!begin_set && dev->partition >2 && end_set)
  463.                 begin = end - length;
  464.             else
  465.                 end = begin + length;
  466.         } else if(!end_set) {
  467.             fprintf(stderr,"Unknown size\n");
  468.             exit(1);
  469.         }
  470.  
  471.         set_offset(&partTable[dev->partition].start, begin, 
  472.                used_dev.heads, used_dev.sectors);
  473.         set_offset(&partTable[dev->partition].end, end-1, 
  474.                used_dev.heads, used_dev.sectors);
  475.         set_dword(partTable[dev->partition].start_sect, begin);
  476.         set_dword(partTable[dev->partition].nr_sects, end-begin);
  477.         if(has_activated)
  478.             partTable[dev->partition].boot_ind = 0;
  479.         else
  480.             partTable[dev->partition].boot_ind = 0x80;
  481.         if(!type) {
  482.             if(end-begin < 4096)
  483.                 type = 1; /* DOS 12-bit FAT */
  484.             else if(end-begin<32*2048)
  485.                 type = 4; /* DOS 16-bit FAT, <32M */
  486.             else
  487.                 type = 6; /* DOS 16-bit FAT >= 32M */
  488.         }
  489.         partTable[dev->partition].sys_ind = type;
  490.     }
  491.  
  492.     j = 0;
  493.     last_end = 1;
  494.  
  495.     if(activate) {
  496.         if(!partTable[dev->partition].sys_ind) {
  497.             fprintf(stderr,
  498.                 "Partition for drive %c: does not exist\n",
  499.                 drive);
  500.         } else {
  501.             switch(activate) {
  502.                 case 1:
  503.                     partTable[dev->partition].boot_ind=0x80;
  504.                     break;
  505.                 case -1:
  506.                     partTable[dev->partition].boot_ind=0x00;
  507.                     break;
  508.             }
  509.         }
  510.     }
  511.  
  512.     /* quick consistency check */
  513.     has_activated = 0;
  514.     for(i=1; i<5; i++){
  515.         if(!partTable[i].sys_ind)
  516.             continue;
  517.         if(partTable[i].boot_ind)
  518.             has_activated++;
  519.         if(used_dev.heads != head(partTable[i].end)+1 ||
  520.            used_dev.sectors != sector(partTable[i].end) ||
  521.            sector(partTable[i].start) != 1){
  522.             fprintf(stderr,
  523.                 "Partition %d is not aligned\n",
  524.                 i);
  525.             inconsistency=1;
  526.         }
  527.         
  528.         if(j && last_end > BEGIN(partTable[i])) {
  529.             fprintf(stderr,
  530.                 "Partitions %d and %d badly ordered or overlapping\n",
  531.                 j,i);
  532.             inconsistency=1;
  533.         }
  534.             
  535.         last_end = END(partTable[i]);
  536.         j = i;
  537.  
  538.         if(tolinear(partTable[i].start) != BEGIN(partTable[i])) {
  539.             fprintf(stderr,
  540.                 "Start position mismatch for partition %d\n",
  541.                 i);
  542.             inconsistency=1;
  543.         }
  544.         if(tolinear(partTable[i].end)+1 != END(partTable[i])) {
  545.             fprintf(stderr,
  546.                 "End position mismatch for partition %d\n",
  547.                 i);
  548.             inconsistency=1;
  549.         }
  550.  
  551.         if(doprint && verbose) {
  552.             if(i==dev->partition)
  553.                 putchar('*');
  554.             else
  555.                 putchar(' ');
  556.             printf("Partition %d\n",i);
  557.  
  558.             printf("  active=%x\n", partTable[i].boot_ind);
  559.             printf("  start:");
  560.             print_hsc(&partTable[i].start);
  561.             printf("  type=0x%x\n", partTable[i].sys_ind);
  562.             printf("  end:");
  563.             print_hsc(&partTable[i].end);
  564.             printf("  start=%d\n", BEGIN(partTable[i]));
  565.             printf("  nr=%d\n", _DWORD(partTable[i].nr_sects));
  566.             printf("\n");
  567.         }
  568.     }
  569.  
  570.     if(doprint && !inconsistency && partTable[dev->partition].sys_ind) {
  571.         printf("The following command will recreate the partition for drive %c:\n", 
  572.                drive);
  573.         used_dev.tracks = 
  574.             (_DWORD(partTable[dev->partition].nr_sects) +
  575.              (BEGIN(partTable[dev->partition]) % sec_per_cyl)) / 
  576.             sec_per_cyl;
  577.         printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n",
  578.                used_dev.tracks, used_dev.heads, used_dev.sectors,
  579.                BEGIN(partTable[dev->partition]), drive);
  580.     }
  581.  
  582.     if(tot_sectors && last_end >tot_sectors) {
  583.         fprintf(stderr,
  584.             "Partition %d exceeds beyond end of disk\n",
  585.             j);
  586.         exit(1);
  587.     }
  588.  
  589.     
  590.     switch(has_activated) {
  591.         case 0:
  592.             fprintf(stderr,
  593.                 "Warning: no active (bootable) partition present\n");
  594.             break;
  595.         case 1:
  596.             break;
  597.         default:
  598.             fprintf(stderr,
  599.                 "Warning: %d active (bootable) partitions present\n",
  600.                 has_activated);
  601.             fprintf(stderr,
  602.                 "Usually, a disk should have exactly one active partition\n");
  603.             break;
  604.     }
  605.     
  606.     if(inconsistency && !force) {
  607.         fprintf(stderr,
  608.             "inconsistency detected!\n" );
  609.         if(dirty)
  610.             fprintf(stderr,
  611.                 "Retry with the -f switch to go ahead anyways\n");
  612.         exit(1);
  613.     }
  614.  
  615.     if(dirty) {
  616.         /* write data back to the disk */
  617.         if(verbose>=2)
  618.             print_sector("Writing sector", buf);
  619.         if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
  620.             fprintf(stderr,"Error writing partition table");
  621.             exit(1);
  622.         }
  623.         if(verbose>=3)
  624.             print_sector("Sector written", buf);
  625.         FREE(&Stream);
  626.     }
  627.     exit(0);
  628. }
  629.