[PATCH] fdisk: when generating a DOS disk label, give it an ID

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Newer Micro$oft operating systems (NT 3 and later) put a 4-byte
signature in the MBR at offset 440 decimal.  Generate a random such
signature when creating a new disk label, and allow it to be changed.

Signed-off-by: H. Peter Anvin <hpa@xxxxxxxxx>
---
 fdisk/fdisk.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 98 insertions(+), 9 deletions(-)

diff --git a/fdisk/fdisk.c b/fdisk/fdisk.c
index 292b7a8..31449d6 100644
--- a/fdisk/fdisk.c
+++ b/fdisk/fdisk.c
@@ -91,7 +91,7 @@ store4_little_endian(unsigned char *cp, unsigned int val) {
 }
 
 static unsigned int
-read4_little_endian(unsigned char *cp) {
+read4_little_endian(const unsigned char *cp) {
 	return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8)
 		+ ((unsigned int)(cp[2]) << 16)
 		+ ((unsigned int)(cp[3]) << 24);
@@ -117,6 +117,49 @@ get_nr_sects(struct partition *p) {
 	return read4_little_endian(p->size4);
 }
 
+static ssize_t
+xread(int fd, void *buf, size_t count) {
+        char *p = buf;
+        ssize_t out = 0;
+        ssize_t rv;
+	
+        while (count) {
+                rv = read(fd, p, count);
+                if (rv == -1) {
+                        if (errno == EINTR || errno == EAGAIN)
+                                continue;
+                        return out ? out : -1; /* Error */
+                } else if (rv == 0) {
+                        return out; /* EOF */
+                }
+		
+                p += rv;
+                out += rv;
+                count -= rv;
+        }
+	
+        return out;
+}
+
+static unsigned int
+get_random_id(void) {
+	int fd;
+	unsigned int v;
+	ssize_t rv = -1;
+	
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd >= 0) {
+	        rv = xread(fd, &v, sizeof v);
+		close(fd);
+	}
+	
+	if (rv == sizeof v)
+		return v;
+	
+	/* Fallback: sucks, but better than nothing */
+	return (unsigned int)(getpid() + time(NULL));
+}
+
 /* normally O_RDWR, -l option gives O_RDONLY */
 static int type_open = O_RDWR;
 
@@ -457,6 +500,7 @@ xmenu(void) {
 	   puts(_("   f   fix partition order"));		/* !sun, !aix, !sgi */
 	   puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
 	   puts(_("   h   change number of heads"));
+	   puts(_("   i   change the disk identifier")); /* dos only */
 	   puts(_("   m   print this menu"));
 	   puts(_("   p   print the partition table"));
 	   puts(_("   q   quit without saving changes"));
@@ -720,25 +764,66 @@ read_extended(int ext) {
 }
 
 static void
+dos_write_mbr_id(unsigned char *b, unsigned int id) {
+	store4_little_endian(&b[440], id);
+}
+
+static unsigned int
+dos_read_mbr_id(const unsigned char *b) {
+	return read4_little_endian(&b[440]);
+}
+
+static void
+dos_print_mbr_id(void) {
+	printf(_("Disk identifier: 0x%08x\n"), dos_read_mbr_id(MBRbuffer));
+}
+
+static void
+dos_set_mbr_id(void) {
+	unsigned long new_id;
+	char *ep;
+	char ps[64];
+	
+	snprintf(ps, sizeof ps, _("New disk identifier (current 0x%08x): "),
+		 dos_read_mbr_id(MBRbuffer));
+
+	if (read_chars(ps) == '\n')
+		return;
+
+	new_id = strtoul(line_ptr, &ep, 0);
+	if (*ep != '\n')
+		return;
+
+	dos_write_mbr_id(MBRbuffer, new_id);
+	dos_print_mbr_id();
+}
+
+static void
 create_doslabel(void) {
 	int i;
+	unsigned int id = get_random_id();
 
 	fprintf(stderr,
-	_("Building a new DOS disklabel. Changes will remain in memory only,\n"
-	  "until you decide to write them. After that, of course, the previous\n"
-	  "content won't be recoverable.\n\n"));
+	_("Building a new DOS disklabel with disk identifier 0x%08x.\n"
+	  "Changes will remain in memory only, until you decide to write them.\n"
+	  "After that, of course, the previous content won't be recoverable.\n\n"),
+		id);
 	sun_nolabel();  /* otherwise always recognised as sun */
 	sgi_nolabel();  /* otherwise always recognised as sgi */
 	mac_label = aix_label = osf_label = possibly_osf_label = 0;
 	partitions = 4;
 
-	for (i = 510-64; i < 510; i++)
-		MBRbuffer[i] = 0;
-	write_part_table_flag(MBRbuffer);
+	/* Zero out the MBR buffer */
 	extended_offset = 0;
 	set_all_unchanged();
 	set_changed(0);
 	get_boot(create_empty_dos);
+
+	/* Generate an MBR ID for this disk */
+	dos_write_mbr_id(MBRbuffer, id);
+
+	/* Mark it bootable (unfortunately required) */
+	write_part_table_flag(MBRbuffer);
 }
 
 #include <sys/utsname.h>
@@ -1528,9 +1613,12 @@ list_disk_geometry(void) {
 		printf(_(", total %llu sectors"),
 		       total_number_of_sectors / (sector_size/512));
 	printf("\n");
-	printf(_("Units = %s of %d * %d = %d bytes\n\n"),
+	printf(_("Units = %s of %d * %d = %d bytes\n"),
 	       str_units(PLURAL),
 	       units_per_sector, sector_size, units_per_sector * sector_size);
+	if (dos_label)
+		dos_print_mbr_id();
+	printf("\n");
 }
 
 /*
@@ -1695,7 +1783,6 @@ list_table(int xtra) {
 		printf(_("This doesn't look like a partition table\n"
 			 "Probably you selected the wrong device.\n\n"));
 	}
-		
 
 	/* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
 	   but if the device name ends in a digit, say /dev/foo1,
@@ -2310,6 +2397,8 @@ xselect(void) {
 		case 'i':
 			if (sun_label)
 				sun_set_ilfact();
+			if (dos_label)
+				dos_set_mbr_id();
 			break;
 		case 'o':
 			if (sun_label)
-- 
1.5.2.2

-
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux