sgdisk can now accept GUID values with its -t option. Also some
additional checks for hybrid MBR issues.
diff --git a/NEWS b/NEWS
index 2394dfb..441c9f1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,24 @@
 0.6.11 (??/??/2010):
 --------------------
 
-- 
+- The -t option to sgdisk now accepts GUID values as well as the
+  sgdisk/gdisk-specific two-byte hex codes.
+
+- Added check that the protective 0xEE MBR partition begins on sector 1
+  to the verify function. If it doesn't, a warning message is displayed,
+  but it doesn't count as an error.
+
+- Added check for overlapping MBR partitions to verify function (gdisk "v"
+  function on all menus; sgdisk -v/--verify function). Also warns about
+  multiple MBR 0xEE partitions (causes problems in some OSes).
+
+- Added check to GPT-to-MBR and hybrid MBR creation options to prevent
+  creation of disks with duplicate partitions. When told to create a disk
+  with duplicates, sgdisk now aborts with the error message "Problem
+  creating MBR!" When attempting to create a hybrid MBR with duplicates,
+  gdisk silently drops duplicate partitions, leaving fewer than requested.
+  Creating duplicates should not be possible in sgdisk when converting to
+  MBR form.
 
 0.6.10 (8/22/2010):
 -------------------
diff --git a/gpt.cc b/gpt.cc
index 7dcbc86..85176b8 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -227,6 +227,9 @@
    // Check for mismatched MBR and GPT partitions...
    problems += FindHybridMismatches();
 
+   // Check for MBR-specific problems....
+   problems += VerifyMBR();
+
    // Verify that partitions don't run into GPT data areas....
    problems += CheckGPTSize();
 
@@ -1512,6 +1515,7 @@
 
    protectiveMBR.EmptyMBR(0);
    protectiveMBR.SetDiskSize(diskSize);
+   notes.MakeItLegal();
    notes.Rewind();
    while (notes.GetNextInfo(&convInfo) >= 0) {
       if ((convInfo.gptPartNum >= 0) && (convInfo.type == PRIMARY)) {
@@ -1860,6 +1864,17 @@
    return retval;
 } // GPTData::ChangePartType()
 
+// Change partition type code non-interactively. Returns 1 if
+// successful, 0 if not....
+int GPTData::ChangePartType(uint32_t partNum, PartType theGUID) {
+   int retval = 1;
+
+   if (!IsFreePartNum(partNum)) {
+      partitions[partNum].SetType(theGUID);
+   } else retval = 0;
+   return retval;
+} // GPTData::ChangePartType()
+
 // Recompute the CHS values of all the MBR partitions. Used to reset
 // CHS values that some BIOSes require, despite the fact that the
 // resulting CHS values violate the GPT standard.
diff --git a/gpt.h b/gpt.h
index 4f0ccf7..6566a64 100644
--- a/gpt.h
+++ b/gpt.h
@@ -16,7 +16,7 @@
 #ifndef __GPTSTRUCTS
 #define __GPTSTRUCTS
 
-#define GPTFDISK_VERSION "0.6.10"
+#define GPTFDISK_VERSION "0.6.11-pre1"
 
 // Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
 // numbered value to refer to partition numbers. (Most will be 0 or positive,
@@ -113,6 +113,7 @@
    void RecomputeCRCs(void);
    void RebuildMainHeader(void);
    void RebuildSecondHeader(void);
+   int VerifyMBR(void) {return protectiveMBR.Verify();}
    int FindHybridMismatches(void);
    int FindOverlaps(void);
    int FindInsanePartitions(void);
@@ -162,6 +163,7 @@
    int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
    void RandomizeGUIDs(void);
    int ChangePartType(uint32_t pn, uint16_t hexCode);
+   int ChangePartType(uint32_t pn, PartType theGUID);
    void MakeProtectiveMBR(void) {protectiveMBR.MakeProtectiveMBR();}
    void RecomputeCHS(void);
    int Align(uint64_t* sector);
diff --git a/mbr.cc b/mbr.cc
index 3a5aec4..e0e92a3 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -535,6 +535,44 @@
    return (retval);
 } // MBRData::LBAtoCHS()
 
+// Look for problems -- overlapping partitions, etc.
+int MBRData::Verify(void) {
+   int i, j, theyOverlap, numProbs = 0, numEE = 0;
+   uint32_t firstLBA1, firstLBA2, lastLBA1, lastLBA2;
+
+   for (i = 0; i < MAX_MBR_PARTS; i++) {
+      for (j = i + 1; j < MAX_MBR_PARTS; j++) {
+         theyOverlap = 0;
+         firstLBA1 = partitions[i].firstLBA;
+         firstLBA2 = partitions[j].firstLBA;
+         if ((firstLBA1 != 0) && (firstLBA2 != 0)) {
+            lastLBA1 = partitions[i].firstLBA + partitions[i].lengthLBA - 1;
+            lastLBA2 = partitions[j].firstLBA + partitions[j].lengthLBA - 1;
+            if ((firstLBA1 < lastLBA2) && (lastLBA1 >= firstLBA2))
+               theyOverlap = 1;
+            if ((firstLBA2 < lastLBA1) && (lastLBA2 >= firstLBA1))
+               theyOverlap = 1;
+         } // if
+         if (theyOverlap) {
+            numProbs++;
+            cout << "\nProblem: MBR partitions " << i + 1 << " and " << j + 1
+                 << " overlap!\n";
+         } // if
+      } // for (j...)
+      if (partitions[i].partitionType == 0xEE) {
+         numEE++;
+         if (partitions[i].firstLBA != 1)
+            cout << "\nWarning: 0xEE partition doesn't start on sector 1. This can cause problems\n"
+                 << "in some OSes.\n";
+      } // if
+   } // for (i...)
+   if (numEE > 1)
+      cout << "\nCaution: More than one 0xEE MBR partition found. This can cause problems\n"
+           << "in some OSes.\n";
+
+   return numProbs;
+} // MBRData::Verify()
+
 /*****************************************************
  *                                                   *
  * Functions to create, delete, or change partitions *
diff --git a/mbr.h b/mbr.h
index a8e348e..b434ac0 100644
--- a/mbr.h
+++ b/mbr.h
@@ -110,6 +110,7 @@
    void SetHybrid(void) {state = hybrid;} // Set hybrid flag
    void SetCHSGeom(uint32_t h, uint32_t s);
    int LBAtoCHS(uint64_t lba, uint8_t * chs); // Convert LBA to CHS
+   int Verify(void);
 
    // Functions to create, delete, or change partitions
    // Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
diff --git a/partnotes.cc b/partnotes.cc
index c7954e7..1edd5b8 100644
--- a/partnotes.cc
+++ b/partnotes.cc
@@ -451,8 +451,28 @@
  *                                                                       *
  *************************************************************************/
 
+// Remove duplicate partitions from the list.
+void PartNotes::RemoveDuplicates(void) {
+   struct PartInfo *n1, *n2;
+
+   n1 = notes;
+   while (n1 != NULL) {
+      n2 = n1->next;
+      while (n2 != NULL) {
+         if ((n1->firstLBA == n2->firstLBA) && (n1->lastLBA == n2->lastLBA)) {
+            n1->next = n2->next;
+            delete n2;
+            n2 = n1->next;
+         } else {
+            n2 = n2->next;
+         } // if/else
+      } // while (n2 != NULL)
+      n1 = n1->next;
+   } // while (n1 != NULL)
+} // PartNotes::RemoveDuplicates()
+
 // Creates a legal mix of primaries and logicals, maximizing the number
-// of included partitions.
+// of included partitions. Also removes duplicates.
 // Returns 1 if successful, 0 if not (if missing notes list, say)
 int PartNotes::MakeItLegal(void) {
    struct PartInfo *theNote, *lastPrimary;
@@ -460,6 +480,8 @@
    if (notes == NULL)
       return 0;
 
+   RemoveDuplicates();
+
    if (!IsLegal()) {
       // Start by eliminating or converting excessive extended partitions...
       while (GetNumExtended() > 1)
diff --git a/partnotes.h b/partnotes.h
index 31b850c..735e1df 100644
--- a/partnotes.h
+++ b/partnotes.h
@@ -89,6 +89,7 @@
       int IsLegal(void); // returns boolean
 
       // Manipulate data or metadata
+      void RemoveDuplicates(void);
       int MakeItLegal(void);
       void TrimSmallestExtended(void);
 
diff --git a/sgdisk.8 b/sgdisk.8
index 4794faf..dfdd9a7 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -369,9 +369,10 @@
 may need to edit \fI/etc/fstab\fR if you use this option.
 
 .TP 
-.B \-t, \-\-typecode=partnum:hexcode
-Change a single partition's type code. You enter the type code using a
-two\-byte hexadecimal number, as described earlier.
+.B \-t, \-\-typecode=partnum:{hexcode|GUID}
+Change a single partition's type code. You enter the type code using either
+a two\-byte hexadecimal number, as described earlier, or a fully-specified
+GUID value, such as EBD0A0A2-B9E5-4433-87C0-68B6B72699C7.
 
 .TP 
 .B \-T, \-\-transform\-bsd=partnum
diff --git a/sgdisk.cc b/sgdisk.cc
index 3927d26..612c526 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -43,7 +43,7 @@
    char *newPartInfo = NULL, *typeCode = NULL, *partName = NULL;
    char *backupFile = NULL, *twoParts = NULL, *hybrids = NULL, *mbrParts;
    char *partGUID = NULL, *diskGUID = NULL, *outDevice = NULL;
-   string cmd;
+   string cmd, typeGUID;
    PartType typeHelper;
 
    poptContext poptCon;
@@ -75,7 +75,7 @@
       {"replicate", 'R', POPT_ARG_STRING, &outDevice, 'R', "replicate partition table", "device_filename"},
       {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
       {"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
-      {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:hexcode"},
+      {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:{hexcode|GUID}"},
       {"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
       {"partition-guid", 'u', POPT_ARG_STRING, &partGUID, 'u', "set partition GUID", "partnum:guid"},
       {"disk-guid", 'U', POPT_ARG_STRING, &diskGUID, 'U', "set disk GUID", "guid"},
@@ -305,12 +305,18 @@
                case 't':
                   theGPT.JustLooking(0);
                   partNum = (int) GetInt(typeCode, 1) - 1;
-                  sscanf(GetString(typeCode, 2).c_str(), "%x", &hexCode);
-                  if (theGPT.ChangePartType(partNum, hexCode)) {
+                  cout << "Got string '" << GetString(typeCode, 2) << "'\n";
+                  if (GetString(typeCode, 2).length() < 10) {
+                     sscanf(GetString(typeCode, 2).c_str(), "%x", &hexCode);
+                     typeHelper = hexCode;
+                  } else {
+                     typeHelper = GetString(typeCode, 2);
+                  } // if/else hexCode or GUID
+                  if (theGPT.ChangePartType(partNum, typeHelper)) {
                      saveData = 1;
                   } else {
                      cerr << "Could not change partition " << partNum + 1
-                          << "'s type code to " << hex << hexCode << "!\n" << dec;
+                          << "'s type code to " << GetString(typeCode, 2) << "!\n";
                      neverSaveData = 1;
                   } // if/else
                   free(typeCode);
@@ -370,7 +376,7 @@
          while ((opt = poptGetNextOpt(poptCon)) > 0) {
             switch (opt) {
                case 'v':
-                  cout << "Verification may miss some problems!\n";
+                  cout << "Verification may miss some problems or report too many!\n";
                   theGPT.Verify();
                   break;
                case 'z':