Package: dosfstools
Version: 3.0.6-1ubuntu1~ppa2
Severity: normal
Tags: patch

After reformatting a usb-stick syslinux is now failing with an error message of 
"Boot error" whereas it had been
booting ok. This message means that the syslinux ldlinux.sys program is not 
loading properly--the first sector, which
resides in the boot sector is loading but is not finding the rest of the 
ldlinux program where it expects it.
See Ubuntu LP #398241.

I narrowed the problem down to the drop of 14-bootcode.dpatch. My BIOS only 
recognizes a FAT hard disk file system
if the drive number is 0x80 and hidden sectors is non-zero. The patch was 
applied per Debian bug report #303442 and  
was removed due to #489292.

According to the bug reporter for the latter bug the problem was in the setting 
of the hidden sectors field in
the DOS superblock (first sector). The first fix set this so that the boot load 
program would think that it
was located in the first sector of the second track--a common case but 
certainly not a universal one.
This change broke booting from floppies.

The drive number should match the contents of DL for the INT 13 BIOS call. The 
hidden sectors is  used by some boot sector programs to find where it is 
located on the drive, and therefore at what sectors the rest of the contents
of the file system can be found. (With hard disks the combination of the MBR 
and a boot sector program can use
the partition table for the bootable partition rather than the hidden sectors 
field, making the file system
relocatable).

I suggest that the fix be restored but that the hidden sectors field be so set 
only in the hard disk code section--and
that it should be set from the start field from the hard disk geometry ioctl 
result. It is my understanding that
this is what this field is for. The hidden sectors field should remain zero for 
floppies, floppy images, and for
any file systems starting at the first sector of the device.

The FAT superblock settings I propose match what I observed in these fields in 
dumping a partition formatted by a 
reference operating system.

I have coded a patch for the above, adding printing of these fields when in 
verbose mode, and adding options to
override the drive number and FAT media byte. The patch does not include the 
original function to insert bootcode.

>From the patch I have built a new version in my launchpad ppa
(http://ppa.launchpad.net/~jsjgruber/ppa/ubuntu karmic main)

In testing my version I found that test code included in Debian #489292 works.


-- System Information:
Debian Release: squeeze/sid
  APT prefers karmic-updates
  APT policy: (500, 'karmic-updates'), (500, 'karmic-security'), (500, 'karmic')
Architecture: i386 (i686)

Kernel: Linux 2.6.31-14-generic (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages dosfstools depends on:
ii  libc6                   2.10.1-0ubuntu15 GNU C Library: Shared libraries

dosfstools recommends no packages.

dosfstools suggests no packages.

-- no debconf information
diff --git a/debian/changelog b/debian/changelog
index d4c0675..44b2460 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+dosfstools (3.0.6-1ubuntu1~ppa2) karmic; urgency=low
+
+  * Unless overridden by the user sets the DOS boot sector's
+    hidden-sectors field to match the start of a hard disk's
+    partition.
+  * Initialize DOS boot sector device_number according to device media type 
+    Addresses LP: #398241
+  * Adds options to override the DOS boot sector device_number and
+    the FAT media type. 
+
+ -- John S Gruber <[email protected]>  Sun, 18 Oct 2009 21:10:45 -0400
+
 dosfstools (3.0.6-1) unstable; urgency=low
 
   * Updating maintainer field.
diff --git a/man/mkdosfs.8 b/man/mkdosfs.8
index bb87ce6..8c0f138 100644
--- a/man/mkdosfs.8
+++ b/man/mkdosfs.8
@@ -64,6 +64,14 @@
 .I logical-sector-size
 ]
 [
+.B \-D
+.I drive-number
+]
+[
+.B \-M
+.I FAT-media-type
+]
+[
 .B \-v
 ]
 .I device
@@ -118,6 +126,11 @@ be stored on the disk, but the file nevertheless will have the
 correct size. The resulting file can be copied later to a floppy disk
 or other device, or mounted through a loop device.
 .TP
+.BI \-D " drive-number"
+Specify the BIOS drive number to be stored in the FAT boot sector.
+This value is usually 0x80 for hard disks and 0x00 for floppy devices
+or partitions to be used for floppy emulation.
+.TP
 .BI \-f " number-of-FATs"
 Specify the number of file allocation tables in the file system.  The
 default is 2.  Currently the Linux MS-DOS file system does not support
@@ -164,6 +177,11 @@ file must not exceed 418 bytes once line feeds have been converted to
 carriage return-line feed combinations, and tabs have been expanded.
 If the filename is a hyphen (-), the text is taken from standard input.
 .TP
+.BI \-M " FAT-media-type"
+Specify the BIOS drive number to be stored in the FAT boot sector.
+This value is usually 0xF8 for hard disks and has a value from 0xF9
+to 0xFF for floppies or partitions to be used for floppy emulation.
+.TP
 .BI \-n " volume-name"
 Sets the volume name (label) of the file system.  The volume name can
 be up to 11 characters long.  The default is no label.
diff --git a/src/mkdosfs.c b/src/mkdosfs.c
index 89c5600..7c6773b 100644
--- a/src/mkdosfs.c
+++ b/src/mkdosfs.c
@@ -310,6 +310,10 @@ static int sectors_per_cluster = 0;	/* Number of sectors per disk cluster */
 static int root_dir_entries = 0;	/* Number of root directory entries */
 static char *blank_sector;		/* Blank sector - all zeros */
 static int hidden_sectors = 0;		/* Number of hidden sectors */
+static int hidden_sectors_by_user = 0; /* -h option invoked */
+static int drive_number_option = 0;             /* drive number */
+static int drive_number_by_user = 0;    /* drive number option invoked */
+static int fat_media_byte = 0;          /* media byte in header and starting FAT */
 static int malloc_entire_fat = FALSE;	/* Whether we should malloc() the entire FAT or not */
 
 /* Function prototype definitions */
@@ -753,6 +757,8 @@ establish_params (int device_num,int size)
       else {
         bs.secs_track = CT_LE_W(geometry.sectors);	/* Set up the geometry information */
         bs.heads = CT_LE_W(geometry.heads);
+	  if (!hidden_sectors_by_user)
+	     hidden_sectors = CT_LE_L(geometry.start);
       }
     def_hd_params:
       bs.media = (char) 0xf8; /* Set up the media descriptor for a hard drive */
@@ -805,6 +811,18 @@ setup_tables (void)
     strcpy (bs.system_id, "mkdosfs");
   if (sectors_per_cluster)
     bs.cluster_size = (char) sectors_per_cluster;
+
+  if (fat_media_byte)
+    bs.media = (char) fat_media_byte;
+  
+  if (bs.media == 0xf8)
+      vi->drive_number=0x80;
+  else
+      vi->drive_number=0x00;
+
+  if (drive_number_by_user)
+    vi->drive_number= (char) drive_number_option;
+
   if (size_fat == 32)
     {
       /* Under FAT32, the root dir is in a cluster chain, and this is
@@ -1198,9 +1216,11 @@ setup_tables (void)
       printf("%s has %d head%s and %d sector%s per track,\n",
 	     device_name, CF_LE_W(bs.heads), (CF_LE_W(bs.heads) != 1) ? "s" : "",
 	     CF_LE_W(bs.secs_track), (CF_LE_W(bs.secs_track) != 1) ? "s" : "");
+      printf("hidden sectors 0x%04x;\n",  hidden_sectors);
       printf("logical sector size is %d,\n",sector_size);
       printf("using 0x%02x media descriptor, with %d sectors;\n",
 	     (int) (bs.media), num_sectors);
+      printf("drive number 0x%02x;\n", (int) (vi->drive_number));
       printf("file system has %d %d-bit FAT%s and %d sector%s per cluster.\n",
 	     (int) (bs.fats), size_fat, (bs.fats != 1) ? "s" : "",
 	     (int) (bs.cluster_size), (bs.cluster_size != 1) ? "s" : "");
@@ -1386,6 +1406,7 @@ Usage: mkdosfs [-A] [-c] [-C] [-v] [-I] [-l bad-block-file] [-b backup-boot-sect
        [-m boot-msg-file] [-n volume-name] [-i volume-id]\n\
        [-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs]\n\
        [-h hidden-sectors] [-F fat-size] [-r root-dir-entries] [-R reserved-sectors]\n\
+       [-M FAT-media-byte] [-D drive_number]\n\
        /dev/name [blocks]\n");
 }
 
@@ -1448,7 +1469,7 @@ main (int argc, char **argv)
   printf ("%s " VERSION " (" VERSION_DATE ")\n",
 	   program_name);
 
-  while ((c = getopt (argc, argv, "Ab:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF)
+  while ((c = getopt (argc, argv, "Ab:cCf:F:Ii:l:m:n:r:R:s:S:h:M:D:v")) != EOF)
     /* Scan the command line for options */
     switch (c)
       {
@@ -1473,6 +1494,16 @@ main (int argc, char **argv)
       case 'C':		/* C : Create a new file */
 	create = TRUE;
 	break;
+    
+      case 'D':		/* D : Choose Drive Number */
+	drive_number_option = (int) strtol (optarg, &tmp, 0);
+	if (*tmp || (drive_number_option != 0 && drive_number_option != 0x80))
+	  {
+	    printf ("Drive number must be 0 or 0x80: %s\n", optarg);
+	    usage ();
+	  }
+	drive_number_by_user=1;
+	break;
 
       case 'f':		/* f : Choose number of FATs */
 	nr_fats = (int) strtol (optarg, &tmp, 0);
@@ -1500,6 +1531,7 @@ main (int argc, char **argv)
 	    printf("Bad number of hidden sectors : %s\n", optarg);
 	    usage ();
 	  }
+	hidden_sectors_by_user = 1;
 	break;
 
       case 'I':
@@ -1587,6 +1619,15 @@ main (int argc, char **argv)
 	  }
 	break;
 
+      case 'M':		/* M : FAT Media byte */
+	fat_media_byte = (int) strtol (optarg, &tmp, 0);
+	if (*tmp || fat_media_byte < 248 || fat_media_byte > 255)
+	  {
+	    printf ("FAT Media byte must be between 0xF8 and 0xFF : %s\n", optarg);
+	    usage ();
+	  }
+	break;
+
       case 'n':		/* n : Volume name */
 	sprintf(volume_name, "%-11.11s", optarg);
 	break;

Reply via email to