home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 316.lha / DF / df.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-12-05  |  22.2 KB  |  964 lines

  1. /*
  2.  
  3.     DF.C - A utility to format a disk.
  4.  
  5.     This routine was developed for use on a Palomax hard drive system,
  6.     which did not support bad sector re-mapping. It creates a file 
  7.     called 'bad.blocks' which contains a valid file header with links
  8.     to all of the bad blocks. It will work under both filing systems,
  9.     and for hard and floppy drives. If nothing else, it has a better
  10.     syntax than AmigaDos's, and hopefully, provides some examples of
  11.     working with the filing system.
  12.  
  13.     Note: This utility will work with the Maximum drive size 
  14.     currently supported by Palomax software, (2048 tracks and
  15.     16 heads) and then some.
  16.  
  17.     Note also: Some of the error messages are meant mainly for hard
  18.     drives, but should still be informative.
  19. */
  20.  
  21.  
  22. #include    <exec/io.h>
  23. #include    <exec/devices.h>
  24. #include    <exec/memory.h>
  25. #include    <devices/trackdisk.h>
  26. #include    <devices/bootblock.h>
  27. #include    <libraries/dosextens.h>
  28. #include    <libraries/filehandler.h>
  29. #include    "df.h"
  30.  
  31.  
  32.  
  33. char    Usage[] =
  34. "<device name (df0: etc)> <options> [<volume name>]\n\
  35. Where <options> is one or more of the following:\n\
  36.     QUICK FORMAT\t\t -q\n\
  37.     NO VERIFY\t\t -nv\n\
  38.     PRINT BAD BLOCK LIST\t -p\n\
  39.     UPDATE BAD BLOCK FILE\t -u\n\
  40.     USE FAST FILING SYSTEM\t -ffs\n\
  41.     ENTER BAD TRACK LIST\t -t\n";
  42.  
  43.  
  44. char    Greeting[] = 
  45. "    Amiga disk foramatter\n\
  46.      Copyright 1989 SLADE software\n\n";
  47.  
  48.  
  49. char            *my_name;    /* Invocation name         */
  50. struct     MsgPort        *diskport;    /* Reply port for I/O requests    */
  51. struct    IOStdReq    *diskreq;    /* Request struct for I/O     */
  52. char            *dsk_buf;    /* buffer to hold info from dsk */
  53. long            doe;        /* Device open error flag     */
  54. int            dev_open;    /* Device open flag         */
  55. int            drive_inhibited;/* Flag for inhibit operation    */
  56. int            bad_tracks;    /* Number of bad tracks     */
  57.  
  58. int            dformat;    /* Flag to indicate format     */
  59. int            update;        /* Flag to indicate just update */
  60. int            quick_format;    /* Quick format flag...        */
  61. int            no_verify;    /* Format w/no verify flag..    */
  62. int            report;        /* Report on bad blocks only     */
  63. int            enter_tracks;    /* Enter own bad tracks flag    */
  64.  
  65. struct    RootBlock    rb;        /* Root block structure */
  66. struct    disk_parm    dp;        /* disk_parm structure    */
  67.  
  68. extern    void        update_bad_blocks();
  69. extern    void        create_bad_block_file();
  70. extern    void        print_bad_blocks();
  71. extern    int        block_already_bad();
  72.  
  73. struct    bad_block    *bad_block_list;  /* Used block list pointer    */
  74. int    bad_blocks;              /* Number of used/bad blocks    */
  75. void    add_bad_block();          /* add bad block routine    */
  76.  
  77. long    bad_track_list[BADTRKSIZE];      /* Bad track list        */
  78. char    *device;              /* Device (df0: etc) to use    */
  79. char    volname[40];              /* Supplied volume name    */
  80.  
  81. extern    struct    DosLibrary    *DOSBase;
  82. int    def_PreAlloc;        
  83.  
  84.  
  85. /*-----------------------------------------------------------------------------
  86. ------------------------------------------------------------------------------*/
  87. BYTE    write_blocks( block_start, count )
  88. ULONG    block_start;
  89. int    count;
  90.     {
  91.     /*
  92.       Write count blocks to the disk. block_start contains the
  93.       the actual block number to write. We do not check the
  94.       range here. The write will be immediate with no buffering
  95.       because we do a CMD_UPDATE after the write...
  96.     */
  97.  
  98.     diskreq->io_Length     = dp.block_size*count;
  99.     diskreq->io_Data       = (APTR) dsk_buf;
  100.     diskreq->io_Command    = CMD_WRITE;
  101.     diskreq->io_Offset    = block_start*dp.block_size;
  102.     DoIO( diskreq );
  103.     if ( diskreq->io_Error )
  104.           return( (diskreq->io_Error == 0) );
  105.  
  106.     diskreq->io_Command    = CMD_UPDATE;
  107.     DoIO( diskreq );
  108.     return( (diskreq->io_Error == 0) );
  109.     }
  110.  
  111.  
  112. /*-----------------------------------------------------------------------------
  113. ------------------------------------------------------------------------------*/
  114. BYTE    read_blocks( block_start, count )
  115. ULONG    block_start;
  116. int    count;
  117.     {
  118.     /*
  119.       Read count blocks from the file. block_start contains the
  120.       the actual starting offset of the block to read. We do not 
  121.       check the range here!
  122.     */
  123.  
  124.     diskreq->io_Length     = dp.block_size*count;
  125.     diskreq->io_Data       = (APTR) dsk_buf;
  126.     diskreq->io_Command    = CMD_READ;
  127.     diskreq->io_Offset    = block_start;
  128.     DoIO( diskreq );
  129.     return( (diskreq->io_Error == 0) );
  130.     }
  131.  
  132.  
  133. /*-----------------------------------------------------------------------------
  134. ------------------------------------------------------------------------------*/
  135. void    motor_off()
  136.     {
  137.     /*
  138.       Turn the drive motor off. (only valid for 3.5's)...
  139.     */
  140.     diskreq->io_Length     = 0;
  141.     diskreq->io_Command    = TD_MOTOR;
  142.     DoIO( diskreq );
  143.     }
  144.  
  145.  
  146.  
  147. /*-----------------------------------------------------------------------------
  148. ------------------------------------------------------------------------------*/
  149. void    inhibit_drive( yorn )
  150. int    yorn;
  151.     {
  152.     /*
  153.       Depending on the value of yorn, inhibit or enable the drive.
  154.     */
  155.  
  156.     void        df_exit();
  157.     struct    MsgPort    *dev_proc, *DeviceProc();
  158.  
  159.     /*
  160.       Find the device handling this drive, and complain if it
  161.       does not exist.
  162.     */
  163.     if ( !(dev_proc = DeviceProc( device ) ) )
  164.         {
  165.         df_exit( EBADDEV );
  166.         }
  167.  
  168.     /*
  169.        Tell DOS to inhibit the drive.
  170.     */
  171.     if ( !dos_packet( dev_proc, ACTION_INHIBIT, (long) yorn,
  172.               0L, 0L, 0L, 0L, 0L, 0L, 0L ) ) 
  173.         {
  174.         df_exit( ENOINH );    
  175.         }
  176.  
  177.     drive_inhibited    = yorn;
  178.     }
  179.  
  180.  
  181. /*-----------------------------------------------------------------------------
  182. ------------------------------------------------------------------------------*/
  183. BYTE    verify_track( track )
  184. ULONG    track;
  185.     {
  186.     /*
  187.       Do a read-verify of the track we just formatted. If no_verify
  188.       is true, just return true...
  189.     */
  190.     long    track_start;
  191.  
  192.     if ( no_verify )
  193.         return( 1 );
  194.  
  195.     track_start = track * dp.track_size;
  196.  
  197.     read_blocks( track_start, dp.blocks_track );
  198.     return( (diskreq->io_Error == 0) );
  199.     }
  200.  
  201.  
  202.  
  203. /*-----------------------------------------------------------------------------
  204. ------------------------------------------------------------------------------*/
  205. BYTE     format_track( track )
  206. ULONG    track;
  207.     {
  208.     /* 
  209.       Tell the device driver to format the supplied track. A track
  210.       is defined by disk_parm.track_size.
  211.     */
  212.     
  213.     diskreq->io_Length     = dp.track_size;
  214.     diskreq->io_Data       = (APTR) dsk_buf;
  215.     diskreq->io_Command    = TD_FORMAT;
  216.     diskreq->io_Offset    = track * dp.track_size;
  217.     DoIO( diskreq );
  218.         
  219.     return( (diskreq->io_Error == 0) );
  220.     }
  221.     
  222.  
  223.  
  224. /*-----------------------------------------------------------------------------
  225. ------------------------------------------------------------------------------*/
  226. void    format_disk()
  227.     {
  228.     /* 
  229.       Format the disk a track at a time from low_cyl to high_cyl on 
  230.       dp.surfaces heads. If we come to a track that is already in the
  231.       bad_track_list, skip the format. If we find a new bad track, 
  232.       add it to the list, and make sure the list is not full.
  233.     */
  234.     void    df_exit();
  235.     void    initialize_disk();
  236.     ULONG    i, j, cur_track;
  237.  
  238.   
  239.     inhibit_drive( 1 );
  240.  
  241.     /*
  242.       We have several options here: Normal format and verify,
  243.       format without verify, and quick format (write root and 
  244.       boot blocks only). Test for quick first...
  245.     */
  246.     if ( quick_format )
  247.         {
  248.         initialize_disk();
  249.         return;
  250.         }
  251.  
  252.     for( i = dp.low_cyl; i <= dp.high_cyl; i++ )
  253.         for ( j = 0; j < dp.surfaces; j++ )
  254.         {
  255.         cur_track = (i * dp.surfaces) + j;
  256.  
  257.         if ( track_already_bad( cur_track ) )
  258.             {
  259.             printf( "Head %ld, Track %ld already marked as bad - skipping\n", 
  260.                  j, i );
  261.             continue;
  262.             }
  263.  
  264.         if ( !format_track( cur_track ) || !verify_track( cur_track ) )
  265.             {
  266.             bad_track_list[bad_tracks++] = cur_track;
  267.             if ( bad_tracks > BADTRKSIZE )
  268.                 {
  269.                 df_exit( EBTOV );
  270.                 }
  271.  
  272.             printf( "Unable to format head: %ld, track: %ld ", j, i );
  273.             printf( "Adding to bad track list\n" );
  274.             }
  275.  
  276.         }
  277.  
  278.     /*
  279.       Initialize the disk...
  280.     */
  281.     initialize_disk();
  282.     }
  283.  
  284.  
  285. /*-----------------------------------------------------------------------------
  286. ------------------------------------------------------------------------------*/
  287. void    create_bad_block_list()
  288.     {
  289.     /* 
  290.       Take the bad track table and convert the tracks to blocks.
  291.       The first block on a track will be (blocks_track * track),
  292.       then we just count up to blocks_track to get the rest.
  293.     */
  294.     int            i, j;
  295.     ULONG            current_block;
  296.  
  297.     for( i = 0, bad_blocks = 0; i < bad_tracks; i++ )
  298.         {
  299.         current_block = bad_track_list[i] * dp.blocks_track;
  300.  
  301.         for( j = 0; j < dp.blocks_track; j++ )
  302.             {
  303.             add_bad_block( current_block++ );
  304.             bad_blocks++;
  305.             }
  306.         }
  307.     }
  308.  
  309.  
  310. /*-----------------------------------------------------------------------------
  311. ------------------------------------------------------------------------------*/
  312. void    write_boot_block()
  313.     {
  314.     /*
  315.       Create the boot block and write it to the disk. We will first
  316.       check to see if it was found to be bad during the format. If
  317.       so, we will inform the user and quit. Also, if we get a write
  318.       error (in case we only did a read verify), we will quit.
  319.     */
  320.     void    df_exit();
  321.     int    i;
  322.     
  323.     if ( block_already_bad( dp.boot_key ) )
  324.         {
  325.         df_exit( EBADBB );
  326.         }
  327.  
  328.     switch( dp.disk_type )
  329.         {
  330.         case    ROMFS : strcpy( dsk_buf, "DOS" );
  331.                 break;
  332.  
  333.         case    FFS   : strcpy( dsk_buf, "DOS\001" );
  334.         }
  335.  
  336.     if ( !write_blocks( dp.boot_key, 1 ) )
  337.         {
  338.         df_exit( EBADBB );
  339.         }
  340.     }
  341.  
  342.  
  343.  
  344. /*-----------------------------------------------------------------------------
  345. ------------------------------------------------------------------------------*/
  346. void    initialize_root_block()
  347.     {
  348.     /*
  349.       Initialize the known fields in the root block. 
  350.     */
  351.  
  352.     rb.Type         = 2L;
  353.     rb.SecondaryType     = 1L;
  354.     rb.HTSize        = 72L;
  355.  
  356.     /*
  357.        Set the BimapFlag to 0, so the validator will come and 
  358.        create the bitmap for us.....
  359.     */
  360.     rb.BitmapFlag        = 0L;
  361.  
  362.     /*
  363.       Copy the volume name to the root block.
  364.     */
  365.     rb.Name[0] = strlen( volname );
  366.     strcpy( &rb.Name[1], volname );
  367.     
  368.     /*
  369.       Create and initialize all the pertinent date fields: DiskMade,
  370.       DirAltered, and DiskAltered. I set these to the same value due
  371.       to ignorance. If they should be different, feel free to change
  372.       this.
  373.     */
  374.     DateStamp( &rb.DiskMade[0] );
  375.     movmem( (char *) &rb.DiskMade, (char *) &rb.DirAltered, 12);
  376.     movmem( (char *) &rb.DiskMade, (char *) &rb.DiskAltered, 12);
  377.     }
  378.  
  379.  
  380. /*-----------------------------------------------------------------------------
  381. ------------------------------------------------------------------------------*/
  382. void    write_root_block()
  383.     {
  384.     /*
  385.       Calculate the checksum for the root block and attempt to write
  386.       it to the disk.
  387.     */
  388.     int    i;
  389.     long    temp, *p;
  390.  
  391.     /*
  392.        Calculate the checksum for this block.
  393.     */
  394.     for( i = 0, temp = 0, p = (long *) &rb; i < (sizeof( rb )/4); i++ )
  395.         {
  396.         temp += *p++;
  397.         }
  398.     rb.Checksum = -temp;
  399.  
  400.  
  401.     /*
  402.       Copy it to the disk buffer and write it.
  403.     */
  404.     movmem( (char *) &rb, dsk_buf, sizeof( rb ) );
  405.     if ( !write_blocks( dp.root_key, 1 ) )
  406.         {
  407.         df_exit( EBADRB );
  408.         }
  409.     }
  410.  
  411.  
  412.  
  413. /*-----------------------------------------------------------------------------
  414. ------------------------------------------------------------------------------*/
  415. void    initialize_disk()
  416.     {
  417.     /*
  418.       Attempt to write the boot block, root block and bad block file.
  419.       each routine will handle its own errors. We do not mess with the
  420.       bitmap for the disk at all. We set the 'not validated' field of
  421.       the root block, and when we un-inibit() the drive, AmigaDOS will
  422.       go out and create it for us. Not the most efficient thing to do,
  423.       but it beats writing the code to do it by hand...
  424.     */
  425.     create_bad_block_list();    /* translate tracks to blocks     */
  426.     write_boot_block();        /* write the boot block        */
  427.     initialize_root_block();    /* set some fields in root block*/
  428.  
  429.     /* 
  430.       Create and write the bad block file if we have any bad blocks.
  431.     */
  432.     if ( bad_block_list )
  433.         create_bad_block_file();
  434.  
  435.     write_root_block();        /* update and write the root blk*/
  436.     }
  437.  
  438.  
  439.  
  440. /*-----------------------------------------------------------------------------
  441. ------------------------------------------------------------------------------*/
  442. get_drive_type()
  443.     {
  444.     /*
  445.       If we are going to format the drive, its type will be ROMFS by
  446.       default, unless the user specified -ffs. If we are just going
  447.       to do an update, we need to read the boot block to get the type.
  448.     */
  449.     void    df_exit();
  450.     
  451.     if ( update )
  452.         {
  453.         if ( !read_blocks( dp.boot_key, 1 ) )
  454.             {
  455.             df_exit( EBADBB );
  456.             }
  457.  
  458.         dp.disk_type = (int) dsk_buf[3];
  459.         }
  460.  
  461.     /*
  462.       Get the pre-allocated block count.
  463.     */
  464.     dp.pre_alloc = (dp.disk_type == ROMFS) ? 0 : def_PreAlloc;
  465.  
  466.     /*
  467.       dp.lower_key is the lowest block on the drive. It is usually 2, 
  468.       because AmigaDOS reserves the lowest two for the boot blocks - 
  469.       also because of the way the bitmap is structured, we cannot use 
  470.       block 0 - a value of 0 in the bitmap indicates a used block.
  471.     */
  472.     dp.lower_key    = dp.low_cyl * dp.blocks_track * dp.surfaces + 
  473.               dp.reserved;
  474.  
  475.     dp.upper_key    = ((dp.high_cyl + 1) * dp.surfaces * dp.blocks_track) -
  476.               ( dp.pre_alloc + 1 ); 
  477.  
  478.     }
  479.  
  480.  
  481.  
  482. /*-----------------------------------------------------------------------------
  483. ------------------------------------------------------------------------------*/
  484. get_drive_stats( drive )
  485. char    *drive; 
  486.     {
  487.     /*
  488.       Get the needed drive data from the environment vector. This is also
  489.       the DevInfo block masquerading under a different name. It is not too
  490.       well documented, and I have TransAmi to thank for this little tidbit.
  491.     */
  492.  
  493.     struct RootNode            *rn;
  494.     struct DosInfo            *dsi;
  495.     struct DeviceNode        *di;
  496.     struct FileSysStartupMsg    *fsm;
  497.     struct DosEnvironment        *de;
  498.     char                dev[32], *p, *q;
  499.     
  500.     for( p = drive, q = dev; (*p != ':') && *p; )
  501.         *q++ = toupper( *p++ );
  502.  
  503.     *q = '\0';
  504.  
  505.     if ( !p )
  506.         {
  507.         return( 0 );
  508.         }
  509.  
  510.     Forbid();
  511.     rn = (struct RootNode *) DOSBase->dl_Root;
  512.     dsi= (struct DosInfo *) BADDR( rn->rn_Info );
  513.     di = (struct DeviceNode *) BADDR( dsi->di_DevInfo );
  514.  
  515.     /*
  516.       Attempt to find the device in the list.
  517.     */
  518.     for( ; di->dn_Next; di = (struct DeviceNode *) BADDR( di->dn_Next ) )
  519.         {
  520.         if ( !strcmp( BADDR( di->dn_Name )+1, dev ) )
  521.             break;
  522.         }
  523.  
  524.     if ( !di )        /* device not found */
  525.         {
  526.         Permit();
  527.         return( 0 );
  528.         }
  529.  
  530.  
  531.     fsm = (struct FileSysStartupMsg *) BADDR( di->dn_Startup );
  532.     de =  (struct DosEnvironment *) BADDR( fsm->fssm_Environ );
  533.  
  534.     /*
  535.       Copy the pertinent fields.
  536.     */
  537.     dp.unit        = fsm->fssm_Unit;        /* Unit number         */
  538.     dp.block_size    = de->de_SizeBlock * 4;        /* Block size          */
  539.     dp.surfaces    = de->de_Surfaces;        /* Sides        */
  540.     dp.sec_block    = de->de_SecPerBlock;        /* Sectors/block    */
  541.     dp.blocks_track = de->de_BlocksPerTrack;    /* Blocks/track        */
  542.     dp.reserved    = de->de_Reserved;        /* Reserved blocks  */
  543.     dp.low_cyl    = de->de_LowCyl;        /* Low cylinder        */
  544.     dp.high_cyl    = de->de_HighCyl;        /* High cylinder    */
  545.  
  546.     /*
  547.       Copy the name of the driver to dp.driver.
  548.     */
  549.     p         = (char *) BADDR( fsm->fssm_Device );
  550.     strncpy( dp.driver, p + 1, (int) *p );
  551.  
  552.     dp.track_size    = dp.block_size * dp.blocks_track;
  553.  
  554.     dp.root_key    = ((dp.high_cyl + 1) * dp.blocks_track * dp.surfaces)/2;
  555.     dp.boot_key    = dp.low_cyl * dp.surfaces * dp.blocks_track;
  556.  
  557.     def_PreAlloc     = de->de_PreAlloc;
  558.     Permit();
  559.     return( 1 );
  560.     }
  561.  
  562.  
  563.  
  564.  
  565. /*-----------------------------------------------------------------------------
  566. ------------------------------------------------------------------------------*/
  567. void    init_bad_track_list()
  568.     {
  569.     /* 
  570.       Initialize the bad track list to -1's.
  571.     */
  572.     int     i;
  573.  
  574.     for( i = 0; i < BADTRKSIZE; i++ )
  575.         bad_track_list[i] = -1L;
  576.     }
  577.  
  578.  
  579. /*-----------------------------------------------------------------------------
  580. ------------------------------------------------------------------------------*/
  581. void    get_bad_tracks()
  582.     {
  583.     /*
  584.       Prompt the user for a list of bad tracks.
  585.     */
  586.     char    tmp[10];
  587.     ULONG    cur_track, head, track;
  588.  
  589.     printf( "Enter bad tracks - enter q to quit\n" );
  590.  
  591.     for ( ; ; )
  592.         {
  593.         printf( "Head " );
  594.         gets( tmp );
  595.         if ( toupper( *tmp ) == 'Q' )
  596.             break;
  597.         
  598.         head = atol( tmp );
  599.         printf( "Track " );
  600.         gets( tmp );
  601.         track = atol( tmp ); 
  602.  
  603.         cur_track = (track * dp.surfaces) + head;    
  604.  
  605.  
  606.         bad_track_list[bad_tracks++] = cur_track;
  607.         if ( bad_tracks > BADTRKSIZE )
  608.             {
  609.             df_exit( EBTOV );
  610.             }
  611.         }
  612.  
  613.     }
  614.  
  615.  
  616.  
  617. /*-----------------------------------------------------------------------------
  618. ------------------------------------------------------------------------------*/
  619. int    track_already_bad( track )
  620. ULONG    track;
  621.     {
  622.     /*
  623.        Cruise through the bad_track_list and see if the given track
  624.        is in it. return the result of the search.
  625.     */
  626.     int    i;
  627.  
  628.     for( i = 0; i < BADTRKSIZE; i++ )
  629.         {
  630.         if ( bad_track_list[i] == track ) 
  631.             return( 1 );
  632.         }
  633.     return( 0 );
  634.     }
  635.  
  636.  
  637.  
  638. /*-----------------------------------------------------------------------------
  639. ------------------------------------------------------------------------------*/
  640. void    df_exit( rc, err )
  641. int    rc;
  642. char    *err;
  643.     {
  644.     /*
  645.       This is the function that everyone exits by. We will
  646.       close or return allocated resources and quit gracefully
  647.       on error.
  648.     */
  649.  
  650.     if ( (dev_open) && (dp.disk_type == ROMFS) ) 
  651.         motor_off();
  652.  
  653.     if ( dev_open )
  654.         CloseDevice( diskreq );
  655.  
  656.     if ( diskport )
  657.         DeletePort( diskport );
  658.  
  659.     if ( diskreq )
  660.         DeleteStdIO( diskreq );
  661.  
  662.     if ( dsk_buf )
  663.         FreeMem( dsk_buf, (long) dp.track_size );
  664.  
  665.     if ( drive_inhibited )
  666.         inhibit_drive( 0 );
  667.  
  668.     if ( !rc )
  669.         exit( rc );
  670.  
  671.  
  672.     if ( rc == ENOARGS )
  673.             {
  674.         printf( "Usage: %s %s\n", my_name, Usage );
  675.         exit( 200 );
  676.         }
  677.  
  678.     /* Tell user where the error came from */
  679.     printf( "%s:", my_name );
  680.  
  681.     switch ( rc )
  682.         {
  683.         case    ENOPORT      : printf( "Cannot open reply port\n" );
  684.                     break;
  685.  
  686.         case    ENOIOBLK  : printf( "Cannot create I/O block\n" );
  687.                      break;
  688.  
  689.         case     ENOOPEN      : printf( "Cannot open device - error: %x\n", doe );
  690.                         break;
  691.  
  692.         case    EBADDEV      : printf( "Illegal device name\n" );
  693.                         break;
  694.  
  695.         case    EBTOV      : printf( "Bad track table overflow\n" );
  696.                     break;
  697.  
  698.         case    ENOMEM      : printf( "Unable to allocate memory\n" );
  699.                         break;
  700.  
  701.         case    EBADBB    : printf( "The boot block is not writeable. " );
  702.                         printf( "If this is a Mounted disk, you\n");
  703.                         printf( "must increase the LowCyl value " );
  704.                         printf( "in the Mountlist to format this ");
  705.                     printf( "disk.\n" );
  706.                     break;
  707.  
  708.         case    EBADRB    : printf( "The root block is not writeable. " );
  709.                     printf( "You must change either the low_cyl\n" );
  710.                     printf( "or high_cyl value in the Mountlist " );
  711.                     printf( "to format this disk\n" );
  712.                     break;
  713.  
  714.         case   ENOBLKS      : printf( "No more room to create bad " );
  715.                     printf( "block list\n" );
  716.                     break;
  717.  
  718.         case       EBMAPWR      : printf( "Another bad block found while " );
  719.                     printf( "writing the bitmap - please " );
  720.                     printf( "re-run\n" );
  721.                     break;
  722.  
  723.         case    EBADOPT      : printf( "Bad option: %s Halting\n", err );
  724.                     break;
  725.  
  726.         case    ENOINH      : printf( "Unable to inhibit drive\n" );
  727.                     break;
  728.  
  729.         case    ENHDR      : printf( "Unable to write file header block " );
  730.                     printf( "to the disk - format failed\n" );
  731.                     break;
  732.  
  733.         case    ENEXTB      : printf( "Unable to write file extension " );
  734.                     printf( "blocks to the disk - format failed\n");
  735.                     break;
  736.  
  737.         case    EBADBLK      : printf( "Block number out of range\n" );
  738.                     break;
  739.         }
  740.  
  741.  
  742.     exit( 200 );
  743.     }
  744.  
  745.  
  746.  
  747. /*-----------------------------------------------------------------------------
  748. ------------------------------------------------------------------------------*/
  749. void    parse_args( arg_list )
  750. char    **arg_list;
  751.     {
  752.     /* 
  753.       See if we got any flags, and assign some global variables. Assume
  754.       a normal format (dformat = True) if no args are supplied.
  755.     */
  756.     dformat        = 1;
  757.     report        =
  758.     no_verify    =
  759.     update        =
  760.     enter_tracks    =
  761.     quick_format    = 0;
  762.     dp.disk_type    = ROMFS;        /* default */
  763.  
  764.     /*
  765.       The device name MUST be next...
  766.     */
  767.     device    = *arg_list;
  768.  
  769.     /*
  770.       Now all we have left is flags and possibly a volume name. 
  771.     */
  772.  
  773.     while( *++arg_list )
  774.         {
  775.         if (!strcmp( *arg_list, "-u" ) ) 
  776.             {
  777.             update = 1;
  778.             continue;
  779.             }
  780.  
  781.         if (!strcmp( *arg_list, "-p" ) ) 
  782.             {
  783.             report = 1;
  784.             continue;
  785.             }
  786.  
  787.         if (!strcmp( *arg_list, "-ffs" ) )
  788.             {
  789.             dp.disk_type = FFS;
  790.             continue;
  791.             }
  792.     
  793.         if (!strcmp( *arg_list, "-q" ) )
  794.             {
  795.             quick_format = 1;    
  796.             continue;
  797.             }
  798.  
  799.         if (!strcmp( *arg_list, "-nv" ) )
  800.             {
  801.             no_verify = 1;
  802.             continue;
  803.             }
  804.  
  805.         if (!strcmp( *arg_list, "-t" ) )
  806.             {
  807.             enter_tracks = 1;
  808.             continue;
  809.             }
  810.  
  811.         if (!strlen( volname ) )
  812.             {
  813.             strcpy( volname, *arg_list );
  814.             continue;
  815.             }
  816.  
  817.         /*
  818.           If we get here, our illustrious user has entered a
  819.           bad option. We will quit in case this was a typo.
  820.         */
  821.         df_exit( EBADOPT, *arg_list );
  822.         }
  823.  
  824.     /*
  825.       Assign a default volume name of "empty" if none was specified.
  826.     */
  827.     if ( !strlen( volname ) )
  828.         strcpy( volname, "empty" );
  829.     }
  830.  
  831.  
  832.  
  833.  
  834. /*-----------------------------------------------------------------------------
  835. ------------------------------------------------------------------------------*/
  836. main( argc, argv )
  837. int    argc;
  838. char    **argv;
  839.  
  840.     {
  841.     struct     MsgPort        *CreatePort();
  842.     struct    IOStdReq    *CreateStdIO();
  843.     char            *AllocMem();
  844.     long            OpenDevice();
  845.     int            i;
  846.  
  847.     /* 
  848.       Say hello to joe user, and get our invocation name for later
  849.       use.
  850.     */
  851.     printf( "%s", Greeting );
  852.     my_name = *argv;
  853.  
  854.     /*
  855.       Make sure we got enough arguments..
  856.     */
  857.     if ( argc < 2 )
  858.         {
  859.         df_exit( ENOARGS );
  860.         }
  861.  
  862.     parse_args( ++argv );
  863.  
  864.  
  865.  
  866.     if (! (diskport = CreatePort( 0L, 0L )) )
  867.         {
  868.         df_exit( ENOPORT );
  869.         }
  870.  
  871.     if (! (diskreq = CreateStdIO( diskport )) )
  872.         {
  873.         df_exit( ENOIOBLK );
  874.         }
  875.  
  876.  
  877.     if (! get_drive_stats( device ) )
  878.         {
  879.         df_exit( EBADDEV );
  880.         }
  881.  
  882.     if ( (doe = OpenDevice( dp.driver, (long) dp.unit, diskreq, 0L ) ) )
  883.         {
  884.         df_exit( ENOOPEN );
  885.         }
  886.  
  887.     dev_open = 1;
  888.  
  889.  
  890.     /* 
  891.       Create the buffer used to hold information to write to
  892.       the disk during a format, and used in reads.
  893.     */
  894.     if ( !(dsk_buf    = AllocMem( (long) dp.track_size,
  895.                     MEMF_CHIP | MEMF_PUBLIC | MEMF_CLEAR ) ) )
  896.         df_exit( ENOMEM );
  897.  
  898.  
  899.  
  900.     /*
  901.       We're ready to go. Make sure the disk is inserted if it is a floppy,
  902.       also give the user a chance to bail out.
  903.     */
  904.     printf( "Insert disk in drive %s. Press <enter> to continue.", device );
  905.     getchar();
  906.  
  907.     /*
  908.       Get the type of the drive...
  909.     */
  910.     get_drive_type();
  911.  
  912.  
  913.     /*
  914.       Initialize the bad_track_list.
  915.     */
  916.     init_bad_track_list();
  917.  
  918.     /*
  919.       Ask the user to enter their own bad tracks (perhaps found
  920.       by another test). This part is optional - we do our own
  921.       format and verify, and add any new bad tracks to the list.
  922.     */
  923.     if ( enter_tracks || update )
  924.         get_bad_tracks();
  925.  
  926.  
  927.     printf( "  Disk Statistics:\n" );
  928.     printf( "\troot  key:  \t%ld\n", dp.root_key );
  929.     printf( "\tboot  key:  \t%ld\n", dp.boot_key );
  930.     printf( "\tlower key: \t%ld\n", dp.lower_key );
  931.     printf( "\tupper key: \t%ld\n", dp.upper_key );
  932.  
  933.     /* 
  934.       If the user just wants to update the bad blocks (-u), we will
  935.       skip the rest of this junk and go straigh to update.
  936.     */
  937.     if ( update )
  938.         {
  939.         update_bad_blocks();
  940.         df_exit( 0 );
  941.         }
  942.  
  943.     /*
  944.       If we just want a list of bad blocks, print it and quit...
  945.     */
  946.     if ( report )
  947.         {
  948.         print_bad_blocks();
  949.         df_exit( 0 );
  950.         }
  951.  
  952.  
  953.     /*
  954.       Format the disk...
  955.     */
  956.     if ( dformat || quick_format || no_verify )
  957.         format_disk();
  958.  
  959.     df_exit( 0 );
  960.     }
  961.     
  962.         
  963.  
  964.