Package: dosfstools
Version: 3.0.6-1
Severity: normal
X-Debbugs-CC: [email protected]
Tags: patch

I have adjusted the patch, attached, to apply to version 3.0.9. I'm
sorry for the noise last October when I first reported this. Joey Hess
reported Debian #489292.
------

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
From 7c38b0fb05f42aebf6fe52b09a94ca0339cc68f5 Mon Sep 17 00:00:00 2001
From: John S Gruber <[email protected]>
Date: Mon, 1 Mar 2010 12:40:18 -0500
Subject: [PATCH] Add options and make dos boot sector more compatible with reference system.

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 drive_number according to FAT media type
Addresses LP: #398241 and Debian #552673

Adds options to override the DOS boot sector device_number and
the FAT media type.
---
 man/mkdosfs.8 |   21 +++++++++++++++++++--
 src/mkdosfs.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/man/mkdosfs.8 b/man/mkdosfs.8
index 9100c39..5baa153 100644
--- a/man/mkdosfs.8
+++ b/man/mkdosfs.8
@@ -67,6 +67,14 @@
 .I logical-sector-size
 ]
 [
+.B \-D
+.I drive-number
+]
+[
+.B \-M
+.I FAT-media-type
+]
+[
 .B \-v
 ]
 .I device
@@ -130,6 +138,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
@@ -143,8 +156,7 @@ between 12, 16 and 32 bit, whatever fits better for the file system size.
 .BI \-h " number-of-hidden-sectors "
 Select the number of hidden sectors in the volume. Apparently some
 digital cameras get indigestion if you feed them a CF card without
-such hidden sectors, this option allows you to satisfy them. Assumes
-\'0\' if no value is given on the command line.
+such hidden sectors, this option allows you to satisfy them.
 .TP
 .I \-i " volume-id"
 Sets the volume ID of the newly created file system;
@@ -176,6 +188,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 media type 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 bfa80a3..94923a5 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 */
 static int align_structures = TRUE;	/* Whether to enforce alignment */
 
@@ -746,6 +750,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 */
@@ -810,6 +816,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
@@ -1224,9 +1242,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" : "");
@@ -1423,6 +1443,7 @@ Usage: mkdosfs [-a][-A][-c][-C][-v][-I][-l bad-block-file][-b backup-boot-sector
        [-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");
 }
 
@@ -1485,7 +1506,7 @@ main (int argc, char **argv)
   printf ("%s " VERSION " (" VERSION_DATE ")\n",
 	   program_name);
 
-  while ((c = getopt (argc, argv, "aAb:cCf:F:Ii:l:m:n:r:R:s:S:h:v")) != EOF)
+  while ((c = getopt (argc, argv, "aAb:cCf:F:Ii:l:m:n:r:R:s:S:h:M:D:v")) != EOF)
     /* Scan the command line for options */
     switch (c)
       {
@@ -1515,6 +1536,16 @@ main (int argc, char **argv)
 	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);
 	if (*tmp || nr_fats < 1 || nr_fats > 4)
@@ -1541,6 +1572,7 @@ main (int argc, char **argv)
 	    printf("Bad number of hidden sectors : %s\n", optarg);
 	    usage ();
 	  }
+	hidden_sectors_by_user = 1;
 	break;
 
       case 'I':
@@ -1628,6 +1660,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;
-- 
1.7.0

Reply via email to