tech-userlevel archive

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

fdisk behavior on a gpt partitioned disks



Hello,

as EFI goes forward it becomes a more and more common case when a
reused disk partitioned in MBR style can contain GPT as well (usually
just because its deletion wasn't carried before). It's not a problem on
usual PCs, but EFI compliant systems are have to use GUID partition
tables, and therefore they are just ignoring MBR layout. This is the
problem.

The simple solution here is just remove GUID tables from the disk by
issuing "gpt destroy" command (see gpt(8) for details). However, I
heard a lot from other people that fdisk(8) should take care about this
problem too. Well, if you're one from those guys, please examine
attached patch :-)

The patch implements the following logic:

- always warn if disk have GPT

- in interactive mode: explicitly warn that any change to MBR will
  result in GPT removal, ask for confirmation, and remove GPT

- in non-interactive mode: remove GPT and explicitly note this fact

--
Cheers,
Mishka.
Index: Makefile
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/Makefile,v
retrieving revision 1.38
diff -u -r1.38 Makefile
--- Makefile    29 Nov 2007 23:19:25 -0000      1.38
+++ Makefile    29 May 2009 11:33:10 -0000
@@ -18,7 +18,7 @@
 
 .if (${HOSTPROG:U} == "")
 SUBDIR=        mbr
-DPADD+=        ${LIBUTIL}
-LDADD+=        -lutil
+DPADD+=        ${LIBUTIL} ${LIBZ}
+LDADD+=        -lutil -lz
 .include <bsd.subdir.mk>
 .endif
Index: fdisk.c
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/fdisk.c,v
retrieving revision 1.116.6.1
diff -u -r1.116.6.1 fdisk.c
--- fdisk.c     20 Apr 2009 23:16:45 -0000      1.116.6.1
+++ fdisk.c     29 May 2009 11:33:12 -0000
@@ -61,13 +61,16 @@
 
 #if !HAVE_NBTOOL_CONFIG_H
 #include <sys/disklabel.h>
+#include <sys/disklabel_gpt.h>
 #include <sys/bootblock.h>
 #include <sys/ioctl.h>
 #include <sys/sysctl.h>
 #include <disktab.h>
 #include <util.h>
+#include <zlib.h>
 #else
 #include <nbinclude/sys/disklabel.h>
+#include <nbinclude/sys/disklabel_gpt.h>
 #include <nbinclude/sys/bootblock.h>
 #include "../../include/disktab.h"
 /* We enforce -F, so none of these possibly undefined items can be needed */
@@ -245,6 +248,9 @@
 int    get_params(void);
 int    read_s0(daddr_t, struct mbr_sector *);
 int    write_mbr(void);
+int    get_gpt(void);
+int    read_gpt(daddr_t, struct gpt_hdr *);
+int    delete_gpt(int);
 int    yesno(const char *, ...);
 int    decimal(const char *, int, int, int, int);
 #define DEC_SEC                1               /* asking for a sector number */
@@ -291,6 +297,7 @@
        size_t len;
        char *cp;
        int n;
+       int gptm = 0;
 #ifdef BOOTSEL
        daddr_t default_ptn;            /* start sector of default ptn */
        char *cbootmenu = 0;
@@ -298,7 +305,8 @@
 
        int csysid;     /* For the b_flag. */
        unsigned int cstart, csize;
-       a_flag = i_flag = u_flag = sh_flag = f_flag = s_flag = b_flag = 0;
+       a_flag = u_flag = sh_flag = f_flag = s_flag = b_flag = 0;
+       i_flag = B_flag = 0;
        v_flag = 0;
        E_flag = 0;
        csysid = cstart = csize = 0;
@@ -444,6 +452,10 @@
                /* must have been a blank disk */
                init_sector0(1);
 
+       gptm = get_gpt();
+       if (gptm)
+               warnx("The disk is carrying GUID Partition Tables");
+
 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H
        get_geometry();
 #else
@@ -509,10 +521,20 @@
                               "yet.  This is your last chance.\n");
                        if (u_flag)
                                print_s0(-1);
-                       if (yesno("Should we write new partition table?"))
+                       if (gptm)
+                               printf("\nWARNING: The disk is carrying "
+                                      "GUID Partition Tables.\n"
+                                      "         If you continue, "
+                                      "GPT headers will be deleted.\n\n");
+                       if (yesno("Should we write new partition table?")) {
+                               delete_gpt(gptm);
                                write_mbr();
-               } else
+                       }
+               } else {
+                       if (delete_gpt(gptm) > 0)
+                               warnx("GPT headers were deleted");
                        write_mbr();
+               }
        }
 
        exit(0);
@@ -2777,3 +2799,79 @@
                return ("unknown");
        return (ptr->name);
 }
+
+int
+get_gpt(void)
+{
+       int gptm = 0;
+       struct gpt_hdr *gptp;
+
+       if ((gptp = malloc(512)) == NULL)
+               err(1, "Malloc failed");
+
+       if (read_gpt(GPT_HDR_BLKNO, gptp) == 1)
+               gptm |= 1;
+       if (read_gpt(disksectors - 1, gptp) == 1)
+               gptm |= 2;
+
+       free(gptp);
+       return (gptm);
+}
+
+int
+read_gpt(daddr_t offset, struct gpt_hdr *gptp)
+{
+       int rc = 1;
+       struct gpt_hdr *buf;
+       const char *tabletype =
+               offset == GPT_HDR_BLKNO ? "primary" : "secondary";
+
+       memset(gptp, 0, sizeof(struct gpt_hdr));
+       if (read_disk(offset, gptp) == -1) {
+               warn("Can't read %s GPT header", tabletype);
+               return -1;
+       }
+
+       if ((buf = malloc(512)) == NULL)
+               err(1, "Malloc failed");
+       memcpy(buf, gptp, 512);
+       buf->hdr_crc_self = 0;
+
+       if (memcmp(gptp->hdr_sig, GPT_HDR_SIG, sizeof(gptp->hdr_sig))
+                       || gptp->hdr_lba_self != offset
+                       || crc32(0, (void *)buf, gptp->hdr_size)
+                               != gptp->hdr_crc_self)
+               /* not a GPT */
+               rc = 0;
+
+       if (rc && v_flag)
+               printf("Found %s GPT header CRC %"PRIu32" "
+                      "at sector %"PRIdaddr", backup at %"PRIdaddr".\n",
+                      tabletype, gptp->hdr_crc_self,
+                      offset, gptp->hdr_lba_alt);
+       free(buf);
+       return (rc);
+}
+
+int
+delete_gpt(int gptm)
+{
+       int rc = 0;
+       void *buf;
+
+       if ((buf = calloc(1, 512)) == NULL)
+               err(1, "Malloc failed");
+
+       if (gptm&1 && (rc = write_disk(1, buf)) == -1) {
+               warn("can't delete primary GPT header");
+               goto delete_gpt_exit;
+       }
+       if (gptm&2 && (rc = write_disk(disksectors - 1, buf)) == -1) {
+               warn("can't delete secondary GPT header");
+               goto delete_gpt_exit;
+       }
+
+    delete_gpt_exit:
+       free(buf);
+       return (rc);
+}


Home | Main Index | Thread Index | Old Index