tech-userlevel archive

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

Re: fdisk behavior on a gpt partitioned disks



Alan Barrett <apb%cequrux.com@localhost> wrote:
> On Fri, 29 May 2009, Mike M. Volokhov wrote:
> > To be honest, the fdisk patch will delete GPT headers only, leaving
> > GUID tables intact. So, it should be possible to reconstruct GPT
> > partitioning back :)
> 
> It might make sense to just destroy a magic number, leaving most of the
> GPT headers intact; this would make it easy to recover if somebody makes
> a mistake.

Why not? It's done with new patch. Thanks for idea.

I also updated fdisk man page. I'd be grateful if someone could proofread it.

--
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    30 May 2009 21:38:04 -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.8
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/fdisk.8,v
retrieving revision 1.59
diff -u -r1.59 fdisk.8
--- fdisk.8     20 Jan 2008 15:04:09 -0000      1.59
+++ fdisk.8     30 May 2009 21:38:04 -0000
@@ -1,6 +1,6 @@
 .\"    $NetBSD: fdisk.8,v 1.59 2008/01/20 15:04:09 dsl Exp $
 .\"
-.Dd January 20, 2008
+.Dd June 1, 2009
 .Dt FDISK 8
 .Os
 .Sh NAME
@@ -125,6 +125,14 @@
 .Nm
 selects defaults for its questions to guarantee that behaviour.
 .Pp
+If partition data is going to be updated, and disk carries GUID Partition
+Tables the
+.Nm
+will remove both primary and backup GPT headers from the disk.
+See
+.Xr gpt 8
+for information on how to manipulate GUID Partition Tables.
+.Pp
 .Nm
 will calculate the correct
 .Em cylinder ,
@@ -559,6 +567,7 @@
 .Xr disktab 5 ,
 .Xr boot 8 ,
 .Xr disklabel 8 ,
+.Xr gpt 8 ,
 .Xr installboot 8 ,
 .Xr mbr 8 ,
 .Xr mbrlabel 8
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     30 May 2009 21:38:05 -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 */
@@ -207,6 +210,8 @@
 int F_flag = 1;
 #endif
 
+struct gpt_hdr gpt1, gpt2;     /* GUID partition tables */
+
 struct mbr_sector bootcode[8192 / sizeof (struct mbr_sector)];
 int bootsize;          /* actual size of bootcode */
 int boot_installed;    /* 1 if we've copied code into the mbr */
@@ -245,6 +250,8 @@
 int    get_params(void);
 int    read_s0(daddr_t, struct mbr_sector *);
 int    write_mbr(void);
+int    read_gpt(daddr_t, struct gpt_hdr *);
+int    delete_gpt(struct gpt_hdr *);
 int    yesno(const char *, ...);
 int    decimal(const char *, int, int, int, int);
 #define DEC_SEC                1               /* asking for a sector number */
@@ -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,9 @@
                /* must have been a blank disk */
                init_sector0(1);
 
+       read_gpt(GPT_HDR_BLKNO, &gpt1);
+       read_gpt(disksectors - 1, &gpt2);
+
 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H
        get_geometry();
 #else
@@ -509,10 +520,23 @@
                               "yet.  This is your last chance.\n");
                        if (u_flag)
                                print_s0(-1);
-                       if (yesno("Should we write new partition table?"))
+                       if (gpt1.hdr_size != 0 || gpt2.hdr_size != 0)
+                               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(&gpt1);
+                               delete_gpt(&gpt2);
                                write_mbr();
-               } else
+                       }
+               } else {
+                       if (delete_gpt(&gpt1) > 0)
+                               warnx("Primary GPT header was deleted");
+                       if (delete_gpt(&gpt2) > 0)
+                               warnx("Secondary GPT header was deleted");
                        write_mbr();
+               }
        }
 
        exit(0);
@@ -2777,3 +2801,75 @@
                return ("unknown");
        return (ptr->name);
 }
+
+int
+read_gpt(daddr_t offset, struct gpt_hdr *gptp)
+{
+       struct gpt_hdr *buf;
+       const char *tabletype =
+               offset == GPT_HDR_BLKNO ? "primary" : "secondary";
+
+       if ((buf = malloc(512)) == NULL)
+               err(1, "Malloc failed");
+       if (read_disk(offset, buf) == -1) {
+               warn("Can't read %s GPT header", tabletype);
+               return -1;
+       }
+       memcpy(gptp, buf, GPT_HDR_SIZE);
+
+       /* GPT CRC should be calculated with CRC field preset to zero */
+       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 */
+               memset(gptp, 0, GPT_HDR_SIZE);
+
+       if (v_flag && gptp->hdr_size != 0)
+               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 gptp->hdr_size;
+
+}
+
+int
+delete_gpt(struct gpt_hdr *gptp)
+{
+       struct gpt_hdr *buf;
+
+       if (gptp->hdr_size == 0)
+               return 0;
+
+       /* don't accidently overwrite something important */
+       if (gptp->hdr_lba_self != GPT_HDR_BLKNO &&
+           gptp->hdr_lba_self != disksectors - 1) {
+               warn("given GPT header location doesn't seem correct");
+               return -1;
+       }
+
+       if ((buf = malloc(512)) == NULL)
+               err(1, "Malloc failed");
+       memcpy(buf, gptp, GPT_HDR_SIZE);
+
+       /*
+        * Don't really delete GPT, just "disable" it, so it can
+        * be recovered later in case of mistake or something
+        */
+       memset(buf->hdr_sig, 0, sizeof(gptp->hdr_sig));
+       if (write_disk(gptp->hdr_lba_self, buf) == -1) {
+               warn("can't delete %s GPT header",
+                       gptp->hdr_lba_self == GPT_HDR_BLKNO ?
+                               "primary" : "secondary");
+               free(buf);
+               return -1;
+       }
+
+       memset(gptp, 0, GPT_HDR_SIZE);
+       free(buf);
+       return 1;
+}


Home | Main Index | Thread Index | Old Index