Blame gptcl.cc

Packit 062bc7
/*
Packit 062bc7
    Implementation of GPTData class derivative with popt-based command
Packit 062bc7
    line processing
Packit 062bc7
    Copyright (C) 2010-2014 Roderick W. Smith
Packit 062bc7
Packit 062bc7
    This program is free software; you can redistribute it and/or modify
Packit 062bc7
    it under the terms of the GNU General Public License as published by
Packit 062bc7
    the Free Software Foundation; either version 2 of the License, or
Packit 062bc7
    (at your option) any later version.
Packit 062bc7
Packit 062bc7
    This program is distributed in the hope that it will be useful,
Packit 062bc7
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 062bc7
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 062bc7
    GNU General Public License for more details.
Packit 062bc7
Packit 062bc7
    You should have received a copy of the GNU General Public License along
Packit 062bc7
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit 062bc7
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 062bc7
*/
Packit 062bc7
Packit 062bc7
#include <string.h>
Packit 062bc7
#include <string>
Packit 062bc7
#include <iostream>
Packit 062bc7
#include <sstream>
Packit 062bc7
#include <errno.h>
Packit 062bc7
#include <popt.h>
Packit 062bc7
#include "gptcl.h"
Packit 062bc7
Packit 062bc7
GPTDataCL::GPTDataCL(void) {
Packit 062bc7
   attributeOperation = backupFile = partName = hybrids = newPartInfo = NULL;
Packit 062bc7
   mbrParts = twoParts = outDevice = typeCode = partGUID = diskGUID = NULL;
Packit 062bc7
   alignment = DEFAULT_ALIGNMENT;
Packit 062bc7
   deletePartNum = infoPartNum = largestPartNum = bsdPartNum = 0;
Packit 062bc7
   tableSize = GPT_SIZE;
Packit 062bc7
} // GPTDataCL constructor
Packit 062bc7
Packit 062bc7
GPTDataCL::GPTDataCL(string filename) {
Packit 062bc7
} // GPTDataCL constructor with filename
Packit 062bc7
Packit 062bc7
GPTDataCL::~GPTDataCL(void) {
Packit 062bc7
} // GPTDataCL destructor
Packit 062bc7
Packit 062bc7
void GPTDataCL::LoadBackupFile(string backupFile, int &saveData, int &neverSaveData) {
Packit 062bc7
   if (LoadGPTBackup(backupFile) == 1) {
Packit 062bc7
      JustLooking(0);
Packit 062bc7
      saveData = 1;
Packit 062bc7
   } else {
Packit 062bc7
      saveData = 0;
Packit 062bc7
      neverSaveData = 1;
Packit 062bc7
      cerr << "Error loading backup file!\n";
Packit 062bc7
   } // else
Packit 062bc7
} // GPTDataCL::LoadBackupFile()
Packit 062bc7
Packit 062bc7
// Perform the actions specified on the command line. This is necessarily one
Packit 062bc7
// monster of a function!
Packit 062bc7
// Returns values:
Packit 062bc7
// 0 = success
Packit 062bc7
// 1 = too few arguments
Packit 062bc7
// 2 = error when reading partition table
Packit 062bc7
// 3 = non-GPT disk and no -g option
Packit 062bc7
// 4 = unable to save changes
Packit 062bc7
// 8 = disk replication operation (-R) failed
Packit 062bc7
int GPTDataCL::DoOptions(int argc, char* argv[]) {
Packit 062bc7
   GPTData secondDevice;
Packit 062bc7
   int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
Packit 062bc7
   int partNum = 0, newPartNum = -1, saveNonGPT = 1, retval = 0, pretend = 0;
Packit 062bc7
   uint64_t low, high, startSector, endSector, sSize, mainTableLBA;
Packit 062bc7
   uint64_t temp; // temporary variable; free to use in any case
Packit 062bc7
   char *device;
Packit 062bc7
   string cmd, typeGUID, name;
Packit 062bc7
   PartType typeHelper;
Packit 062bc7
Packit 062bc7
   struct poptOption theOptions[] =
Packit 062bc7
   {
Packit 062bc7
      {"attributes", 'A', POPT_ARG_STRING, &attributeOperation, 'A', "operate on partition attributes",
Packit 062bc7
          "list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]"},
Packit 062bc7
      {"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
Packit 062bc7
      {"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
Packit 062bc7
      {"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
Packit 062bc7
      {"recompute-chs", 'C', POPT_ARG_NONE, NULL, 'C', "recompute CHS values in protective/hybrid MBR", ""},
Packit 062bc7
      {"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
Packit 062bc7
      {"display-alignment", 'D', POPT_ARG_NONE, NULL, 'D', "show number of sectors per allocation block", ""},
Packit 062bc7
      {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
Packit 062bc7
      {"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
Packit 062bc7
      {"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
Packit 062bc7
      {"first-aligned-in-largest", 'F', POPT_ARG_NONE, NULL, 'F', "show start of the largest free block, aligned", ""},
Packit 062bc7
      {"mbrtogpt", 'g', POPT_ARG_NONE, NULL, 'g', "convert MBR to GPT", ""},
Packit 062bc7
      {"randomize-guids", 'G', POPT_ARG_NONE, NULL, 'G', "randomize disk and partition GUIDs", ""},
Packit 062bc7
      {"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...]"},
Packit 062bc7
      {"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
Packit 062bc7
      {"move-main-table", 'j', POPT_ARG_INT, &mainTableLBA, 'j', "adjust the location of the main partition table", "sector"},
Packit 062bc7
      {"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
Packit 062bc7
      {"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""},
Packit 062bc7
      {"gpttombr", 'm', POPT_ARG_STRING, &mbrParts, 'm', "convert GPT to MBR", "partnum[:partnum...]"},
Packit 062bc7
      {"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
Packit 062bc7
      {"largest-new", 'N', POPT_ARG_INT, &largestPartNum, 'N', "create largest possible new partition", "partnum"},
Packit 062bc7
      {"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
Packit 062bc7
      {"print-mbr", 'O', POPT_ARG_NONE, NULL, 'O', "print MBR partition table", ""},
Packit 062bc7
      {"print", 'p', POPT_ARG_NONE, NULL, 'p', "print partition table", ""},
Packit 062bc7
      {"pretend", 'P', POPT_ARG_NONE, NULL, 'P', "make changes in memory, but don't write them", ""},
Packit 062bc7
      {"transpose", 'r', POPT_ARG_STRING, &twoParts, 'r', "transpose two partitions", "partnum:partnum"},
Packit 062bc7
      {"replicate", 'R', POPT_ARG_STRING, &outDevice, 'R', "replicate partition table", "device_filename"},
Packit 062bc7
      {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
Packit 062bc7
      {"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
Packit 062bc7
      {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:{hexcode|GUID}"},
Packit 062bc7
      {"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
Packit 062bc7
      {"partition-guid", 'u', POPT_ARG_STRING, &partGUID, 'u', "set partition GUID", "partnum:guid"},
Packit 062bc7
      {"disk-guid", 'U', POPT_ARG_STRING, &diskGUID, 'U', "set disk GUID", "guid"},
Packit 062bc7
      {"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
Packit 062bc7
      {"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""},
Packit 062bc7
      {"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT (but not MBR) data structures", ""},
Packit 062bc7
      {"zap-all", 'Z', POPT_ARG_NONE, NULL, 'Z', "zap (destroy) GPT and MBR data structures", ""},
Packit 062bc7
      POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
Packit 062bc7
   };
Packit 062bc7
Packit 062bc7
   // Create popt context...
Packit 062bc7
   poptCon = poptGetContext(NULL, argc, (const char**) argv, theOptions, 0);
Packit 062bc7
Packit 062bc7
   poptSetOtherOptionHelp(poptCon, " [OPTION...] <device>");
Packit 062bc7
Packit 062bc7
   if (argc < 2) {
Packit 062bc7
      poptPrintUsage(poptCon, stderr, 0);
Packit 062bc7
      return 1;
Packit 062bc7
   }
Packit 062bc7
Packit 062bc7
   // Do one loop through the options to find the device filename and deal
Packit 062bc7
   // with options that don't require a device filename, to flag destructive
Packit 062bc7
   // (o, z, or Z) options, and to flag presence of a --pretend/-P option
Packit 062bc7
   while ((opt = poptGetNextOpt(poptCon)) > 0) {
Packit 062bc7
      switch (opt) {
Packit 062bc7
         case 'A':
Packit 062bc7
            cmd = GetString(attributeOperation, 1);
Packit 062bc7
            if (cmd == "list")
Packit 062bc7
               Attributes::ListAttributes();
Packit 062bc7
            break;
Packit 062bc7
         case 'L':
Packit 062bc7
            typeHelper.ShowAllTypes(0);
Packit 062bc7
            break;
Packit 062bc7
         case 'P':
Packit 062bc7
            pretend = 1;
Packit 062bc7
            break;
Packit 062bc7
         case 'V':
Packit 062bc7
            cout << "GPT fdisk (sgdisk) version " << GPTFDISK_VERSION << "\n\n";
Packit 062bc7
            break;
Packit 062bc7
         default:
Packit 062bc7
            break;
Packit 062bc7
      } // switch
Packit 062bc7
      numOptions++;
Packit 062bc7
   } // while
Packit 062bc7
Packit 062bc7
   // Assume first non-option argument is the device filename....
Packit 062bc7
   device = (char*) poptGetArg(poptCon);
Packit 062bc7
   poptResetContext(poptCon);
Packit 062bc7
Packit 062bc7
   if (device != NULL) {
Packit 062bc7
      JustLooking(); // reset as necessary
Packit 062bc7
      BeQuiet(); // Tell called functions to be less verbose & interactive
Packit 062bc7
      if (LoadPartitions((string) device)) {
Packit 062bc7
         if ((WhichWasUsed() == use_mbr) || (WhichWasUsed() == use_bsd))
Packit 062bc7
            saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
Packit 062bc7
         sSize = GetBlockSize();
Packit 062bc7
         while ((opt = poptGetNextOpt(poptCon)) > 0) {
Packit 062bc7
            switch (opt) {
Packit 062bc7
               case 'A': {
Packit 062bc7
                  if (cmd != "list") {
Packit 062bc7
                     partNum = (int) GetInt(attributeOperation, 1) - 1;
Packit 062bc7
                     if (partNum < 0)
Packit 062bc7
                        partNum = newPartNum;
Packit 062bc7
                     if ((partNum >= 0) && (partNum < (int) GetNumParts())) {
Packit 062bc7
                        switch (ManageAttributes(partNum, GetString(attributeOperation, 2),
Packit 062bc7
                           GetString(attributeOperation, 3))) {
Packit 062bc7
                           case -1:
Packit 062bc7
                              saveData = 0;
Packit 062bc7
                              neverSaveData = 1;
Packit 062bc7
                              break;
Packit 062bc7
                           case 1:
Packit 062bc7
                              JustLooking(0);
Packit 062bc7
                              saveData = 1;
Packit 062bc7
                              break;
Packit 062bc7
                           default:
Packit 062bc7
                              break;
Packit 062bc7
                        } // switch
Packit 062bc7
                     } else {
Packit 062bc7
                        cerr << "Error: Invalid partition number " << partNum + 1 << "\n";
Packit 062bc7
                        saveData = 0;
Packit 062bc7
                        neverSaveData = 1;
Packit 062bc7
                     } // if/else reasonable partition #
Packit 062bc7
                  } // if (cmd != "list")
Packit 062bc7
                  break;
Packit 062bc7
               } // case 'A':
Packit 062bc7
               case 'a':
Packit 062bc7
                  SetAlignment(alignment);
Packit 062bc7
                  break;
Packit 062bc7
               case 'b':
Packit 062bc7
                  SaveGPTBackup(backupFile);
Packit 062bc7
                  free(backupFile);
Packit 062bc7
                  break;
Packit 062bc7
               case 'c':
Packit 062bc7
                  cout << "Setting name!\n";
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  partNum = (int) GetInt(partName, 1) - 1;
Packit 062bc7
                  if (partNum < 0)
Packit 062bc7
                     partNum = newPartNum;
Packit 062bc7
                  cout << "partNum is " << partNum << "\n";
Packit 062bc7
                  if ((partNum >= 0) && (partNum < (int) GetNumParts())) {
Packit 062bc7
                     name = GetString(partName, 2);
Packit 062bc7
                     if (SetName(partNum, (UnicodeString) name.c_str())) {
Packit 062bc7
                        saveData = 1;
Packit 062bc7
                     } else {
Packit 062bc7
                        cerr << "Unable to set partition " << partNum + 1
Packit 062bc7
                             << "'s name to '" << GetString(partName, 2) << "'!\n";
Packit 062bc7
                        neverSaveData = 1;
Packit 062bc7
                     } // if/else
Packit 062bc7
                     free(partName);
Packit 062bc7
                  }
Packit 062bc7
                  break;
Packit 062bc7
               case 'C':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  RecomputeCHS();
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'd':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  if (DeletePartition(deletePartNum - 1) == 0) {
Packit 062bc7
                     cerr << "Error " << errno << " deleting partition!\n";
Packit 062bc7
                     neverSaveData = 1;
Packit 062bc7
                  } else saveData = 1;
Packit 062bc7
                                                      break;
Packit 062bc7
               case 'D':
Packit 062bc7
                  cout << GetAlignment() << "\n";
Packit 062bc7
                  break;
Packit 062bc7
               case 'e':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  MoveSecondHeaderToEnd();
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'E':
Packit 062bc7
                  cout << FindLastInFree(FindFirstInLargest()) << "\n";
Packit 062bc7
                  break;
Packit 062bc7
               case 'f':
Packit 062bc7
                  cout << FindFirstInLargest() << "\n";
Packit 062bc7
                  break;
Packit 062bc7
               case 'F':
Packit 062bc7
                  temp = FindFirstInLargest();
Packit 062bc7
                  Align(&temp);
Packit 062bc7
                  cout << temp << "\n";
Packit 062bc7
                  break;
Packit 062bc7
               case 'g':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  saveNonGPT = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'G':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  RandomizeGUIDs();
Packit 062bc7
                  break;
Packit 062bc7
               case 'h':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  if (BuildMBR(hybrids, 1) == 1)
Packit 062bc7
                     saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'i':
Packit 062bc7
                  ShowPartDetails(infoPartNum - 1);
Packit 062bc7
                  break;
Packit 062bc7
               case 'j':
Packit 062bc7
                   if (MoveMainTable(mainTableLBA)) {
Packit 062bc7
                       JustLooking(0);
Packit 062bc7
                       saveData = 1;
Packit 062bc7
                   } else {
Packit 062bc7
                       neverSaveData = 1;
Packit 062bc7
                   } // if/else
Packit 062bc7
                   break;
Packit 062bc7
               case 'l':
Packit 062bc7
                  LoadBackupFile(backupFile, saveData, neverSaveData);
Packit 062bc7
                  free(backupFile);
Packit 062bc7
                  break;
Packit 062bc7
               case 'L':
Packit 062bc7
                  break;
Packit 062bc7
               case 'm':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  if (BuildMBR(mbrParts, 0) == 1) {
Packit 062bc7
                     if (!pretend) {
Packit 062bc7
                        if (SaveMBR()) {
Packit 062bc7
                           DestroyGPT();
Packit 062bc7
                        } else
Packit 062bc7
                           cerr << "Problem saving MBR!\n";
Packit 062bc7
                     } // if
Packit 062bc7
                     saveNonGPT = 0;
Packit 062bc7
                     pretend = 1; // Not really, but works around problem if -g is used with this...
Packit 062bc7
                     saveData = 0;
Packit 062bc7
                  } // if
Packit 062bc7
                  break;
Packit 062bc7
               case 'n':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  newPartNum = (int) GetInt(newPartInfo, 1) - 1;
Packit 062bc7
                  if (newPartNum < 0)
Packit 062bc7
                     newPartNum = FindFirstFreePart();
Packit 062bc7
                  low = FindFirstInLargest();
Packit 062bc7
                  Align(&low);
Packit 062bc7
                  high = FindLastInFree(low);
Packit 062bc7
                  startSector = IeeeToInt(GetString(newPartInfo, 2), sSize, low, high, low);
Packit 062bc7
                  endSector = IeeeToInt(GetString(newPartInfo, 3), sSize, startSector, high, high);
Packit 062bc7
                  if (CreatePartition(newPartNum, startSector, endSector)) {
Packit 062bc7
                     saveData = 1;
Packit 062bc7
                  } else {
Packit 062bc7
                     cerr << "Could not create partition " << newPartNum + 1 << " from "
Packit 062bc7
                          << startSector << " to " << endSector << "\n";
Packit 062bc7
                     neverSaveData = 1;
Packit 062bc7
                  } // if/else
Packit 062bc7
                  free(newPartInfo);
Packit 062bc7
                  break;
Packit 062bc7
               case 'N':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  startSector = FindFirstInLargest();
Packit 062bc7
                  Align(&startSector);
Packit 062bc7
                  endSector = FindLastInFree(startSector);
Packit 062bc7
                  if (largestPartNum <= 0)
Packit 062bc7
                     largestPartNum = FindFirstFreePart() + 1;
Packit 062bc7
                  if (CreatePartition(largestPartNum - 1, startSector, endSector)) {
Packit 062bc7
                     saveData = 1;
Packit 062bc7
                  } else {
Packit 062bc7
                     cerr << "Could not create partition " << largestPartNum << " from "
Packit 062bc7
                     << startSector << " to " << endSector << "\n";
Packit 062bc7
                     neverSaveData = 1;
Packit 062bc7
                  } // if/else
Packit 062bc7
                  break;
Packit 062bc7
               case 'o':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  ClearGPTData();
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'O':
Packit 062bc7
                   DisplayMBRData();
Packit 062bc7
                   break;
Packit 062bc7
               case 'p':
Packit 062bc7
                  DisplayGPTData();
Packit 062bc7
                  break;
Packit 062bc7
               case 'P':
Packit 062bc7
                  pretend = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'r':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  uint64_t p1, p2;
Packit 062bc7
                  p1 = GetInt(twoParts, 1) - 1;
Packit 062bc7
                  p2 = GetInt(twoParts, 2) - 1;
Packit 062bc7
                  if (SwapPartitions((uint32_t) p1, (uint32_t) p2) == 0) {
Packit 062bc7
                     neverSaveData = 1;
Packit 062bc7
                     cerr << "Cannot swap partitions " << p1 + 1 << " and " << p2 + 1 << "\n";
Packit 062bc7
                  } else saveData = 1;
Packit 062bc7
                                                      break;
Packit 062bc7
               case 'R':
Packit 062bc7
                  secondDevice = *this;
Packit 062bc7
                  secondDevice.SetDisk(outDevice);
Packit 062bc7
                  secondDevice.JustLooking(0);
Packit 062bc7
                  if (!secondDevice.SaveGPTData(1))
Packit 062bc7
                     retval = 8;
Packit 062bc7
                  break;
Packit 062bc7
               case 's':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  SortGPT();
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'S':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  if (SetGPTSize(tableSize) == 0)
Packit 062bc7
                     neverSaveData = 1;
Packit 062bc7
                  else
Packit 062bc7
                     saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 't':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  partNum = (int) GetInt(typeCode, 1) - 1;
Packit 062bc7
                  if (partNum < 0)
Packit 062bc7
                     partNum = newPartNum;
Packit 062bc7
                  if ((partNum >= 0) && (partNum < (int) GetNumParts())) {
Packit 062bc7
                     typeHelper = GetString(typeCode, 2);
Packit 062bc7
                     if ((typeHelper != (GUIDData) "00000000-0000-0000-0000-000000000000") &&
Packit 062bc7
                         (ChangePartType(partNum, typeHelper))) {
Packit 062bc7
                        saveData = 1;
Packit 062bc7
                        } else {
Packit 062bc7
                           cerr << "Could not change partition " << partNum + 1
Packit 062bc7
                           << "'s type code to " << GetString(typeCode, 2) << "!\n";
Packit 062bc7
                           neverSaveData = 1;
Packit 062bc7
                        } // if/else
Packit 062bc7
                     free(typeCode);
Packit 062bc7
                  }
Packit 062bc7
                  break;
Packit 062bc7
               case 'T':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  XFormDisklabel(bsdPartNum - 1);
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  break;
Packit 062bc7
               case 'u':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  partNum = (int) GetInt(partGUID, 1) - 1;
Packit 062bc7
                  if (partNum < 0)
Packit 062bc7
                     partNum = newPartNum;
Packit 062bc7
                  if ((partNum >= 0) && (partNum < (int) GetNumParts())) {
Packit 062bc7
                     SetPartitionGUID(partNum, GetString(partGUID, 2).c_str());
Packit 062bc7
                  }
Packit 062bc7
                  break;
Packit 062bc7
               case 'U':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  SetDiskGUID(diskGUID);
Packit 062bc7
                  break;
Packit 062bc7
               case 'v':
Packit 062bc7
                  Verify();
Packit 062bc7
                  break;
Packit 062bc7
               case 'z':
Packit 062bc7
                  if (!pretend) {
Packit 062bc7
                     DestroyGPT();
Packit 062bc7
                  } // if
Packit 062bc7
                  saveNonGPT = 1;
Packit 062bc7
                  saveData = 0;
Packit 062bc7
                  break;
Packit 062bc7
               case 'Z':
Packit 062bc7
                  if (!pretend) {
Packit 062bc7
                     DestroyGPT();
Packit 062bc7
                     DestroyMBR();
Packit 062bc7
                  } // if
Packit 062bc7
                  saveNonGPT = 1;
Packit 062bc7
                  saveData = 0;
Packit 062bc7
                  break;
Packit 062bc7
               default:
Packit 062bc7
                  cerr << "Unknown option (-" << opt << ")!\n";
Packit 062bc7
                  break;
Packit 062bc7
               } // switch
Packit 062bc7
         } // while
Packit 062bc7
      } else { // if loaded OK
Packit 062bc7
         poptResetContext(poptCon);
Packit 062bc7
         // Do a few types of operations even if there are problems....
Packit 062bc7
         while ((opt = poptGetNextOpt(poptCon)) > 0) {
Packit 062bc7
            switch (opt) {
Packit 062bc7
               case 'l':
Packit 062bc7
                  LoadBackupFile(backupFile, saveData, neverSaveData);
Packit 062bc7
                  cout << "Information: Loading backup partition table; will override earlier problems!\n";
Packit 062bc7
                  free(backupFile);
Packit 062bc7
                  retval = 0;
Packit 062bc7
                  break;
Packit 062bc7
               case 'o':
Packit 062bc7
                  JustLooking(0);
Packit 062bc7
                  ClearGPTData();
Packit 062bc7
                  saveData = 1;
Packit 062bc7
                  cout << "Information: Creating fresh partition table; will override earlier problems!\n";
Packit 062bc7
                  retval = 0;
Packit 062bc7
                  break;
Packit 062bc7
               case 'v':
Packit 062bc7
                  cout << "Verification may miss some problems or report too many!\n";
Packit 062bc7
                  Verify();
Packit 062bc7
                  break;
Packit 062bc7
               case 'z':
Packit 062bc7
                  if (!pretend) {
Packit 062bc7
                     DestroyGPT();
Packit 062bc7
                  } // if
Packit 062bc7
                  saveNonGPT = 1;
Packit 062bc7
                  saveData = 0;
Packit 062bc7
                  break;
Packit 062bc7
               case 'Z':
Packit 062bc7
                  if (!pretend) {
Packit 062bc7
                     DestroyGPT();
Packit 062bc7
                     DestroyMBR();
Packit 062bc7
                  } // if
Packit 062bc7
                  saveNonGPT = 1;
Packit 062bc7
                  saveData = 0;
Packit 062bc7
                  break;
Packit 062bc7
            } // switch
Packit 062bc7
         } // while
Packit 062bc7
         retval = 2;
Packit 062bc7
      } // if/else loaded OK
Packit 062bc7
      if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend)) {
Packit 062bc7
         if (!SaveGPTData(1))
Packit 062bc7
            retval = 4;
Packit 062bc7
      }
Packit 062bc7
      if (saveData && (!saveNonGPT)) {
Packit 062bc7
         cout << "Non-GPT disk; not saving changes. Use -g to override.\n";
Packit 062bc7
         retval = 3;
Packit 062bc7
      } // if
Packit 062bc7
      if (neverSaveData) {
Packit 062bc7
         cerr << "Error encountered; not saving changes.\n";
Packit 062bc7
         retval = 4;
Packit 062bc7
      } // if
Packit 062bc7
   } // if (device != NULL)
Packit 062bc7
   poptFreeContext(poptCon);
Packit 062bc7
   return retval;
Packit 062bc7
} // GPTDataCL::DoOptions()
Packit 062bc7
Packit 062bc7
// Create a hybrid or regular MBR from GPT data structures
Packit 062bc7
int GPTDataCL::BuildMBR(char* argument, int isHybrid) {
Packit 062bc7
   int numParts, allOK = 1, i, origPartNum;
Packit 062bc7
   MBRPart newPart;
Packit 062bc7
   BasicMBRData newMBR;
Packit 062bc7
Packit 062bc7
   if (argument != NULL) {
Packit 062bc7
      numParts = CountColons(argument) + 1;
Packit 062bc7
      if (numParts <= (4 - isHybrid)) {
Packit 062bc7
         newMBR.SetDisk(GetDisk());
Packit 062bc7
         for (i = 0; i < numParts; i++) {
Packit 062bc7
            origPartNum = GetInt(argument, i + 1) - 1;
Packit 062bc7
            if (IsUsedPartNum(origPartNum) && (partitions[origPartNum].IsSizedForMBR() == MBR_SIZED_GOOD)) {
Packit 062bc7
               newPart.SetInclusion(PRIMARY);
Packit 062bc7
               newPart.SetLocation(operator[](origPartNum).GetFirstLBA(),
Packit 062bc7
                                   operator[](origPartNum).GetLengthLBA());
Packit 062bc7
               newPart.SetStatus(0);
Packit 062bc7
               newPart.SetType((uint8_t)(operator[](origPartNum).GetHexType() / 0x0100));
Packit 062bc7
               newMBR.AddPart(i + isHybrid, newPart);
Packit 062bc7
            } else {
Packit 062bc7
               cerr << "Original partition " << origPartNum + 1 << " does not exist or is too big! Aborting operation!\n";
Packit 062bc7
               allOK = 0;
Packit 062bc7
            } // if/else
Packit 062bc7
         } // for
Packit 062bc7
         if (isHybrid) {
Packit 062bc7
            newPart.SetInclusion(PRIMARY);
Packit 062bc7
            newPart.SetLocation(1, newMBR.FindLastInFree(1));
Packit 062bc7
            newPart.SetStatus(0);
Packit 062bc7
            newPart.SetType(0xEE);
Packit 062bc7
            newMBR.AddPart(0, newPart);
Packit 062bc7
         } // if
Packit 062bc7
         if (allOK)
Packit 062bc7
            SetProtectiveMBR(newMBR);
Packit 062bc7
      } else allOK = 0;
Packit 062bc7
   } else allOK = 0;
Packit 062bc7
   if (!allOK)
Packit 062bc7
      cerr << "Problem creating MBR!\n";
Packit 062bc7
   return allOK;
Packit 062bc7
} // GPTDataCL::BuildMBR()
Packit 062bc7
Packit 062bc7
// Returns the number of colons in argument string, ignoring the
Packit 062bc7
// first character (thus, a leading colon is ignored, as GetString()
Packit 062bc7
// does).
Packit 062bc7
int CountColons(char* argument) {
Packit 062bc7
   int num = 0;
Packit 062bc7
Packit 062bc7
   while ((argument[0] != '\0') && (argument = strchr(&argument[1], ':')))
Packit 062bc7
      num++;
Packit 062bc7
Packit 062bc7
   return num;
Packit 062bc7
} // GPTDataCL::CountColons()
Packit 062bc7
Packit 062bc7
// Extract integer data from argument string, which should be colon-delimited
Packit 062bc7
uint64_t GetInt(const string & argument, int itemNum) {
Packit 062bc7
   uint64_t retval;
Packit 062bc7
Packit 062bc7
   istringstream inString(GetString(argument, itemNum));
Packit 062bc7
   inString >> retval;
Packit 062bc7
   return retval;
Packit 062bc7
} // GPTDataCL::GetInt()
Packit 062bc7
Packit 062bc7
// Extract string data from argument string, which should be colon-delimited
Packit 062bc7
// If string begins with a colon, that colon is skipped in the counting. If an
Packit 062bc7
// invalid itemNum is specified, returns an empty string.
Packit 062bc7
string GetString(string argument, int itemNum) {
Packit 062bc7
   size_t startPos = 0, endPos = 0;
Packit 062bc7
   string retVal = "";
Packit 062bc7
   int foundLast = 0;
Packit 062bc7
   int numFound = 0;
Packit 062bc7
Packit 062bc7
   if (argument[0] == ':')
Packit 062bc7
      argument.erase(0, 1);
Packit 062bc7
   while ((numFound < itemNum) && (!foundLast)) {
Packit 062bc7
      endPos = argument.find(':', startPos);
Packit 062bc7
      numFound++;
Packit 062bc7
      if (endPos == string::npos) {
Packit 062bc7
         foundLast = 1;
Packit 062bc7
         endPos = argument.length();
Packit 062bc7
      } else if (numFound < itemNum) {
Packit 062bc7
         startPos = endPos + 1;
Packit 062bc7
      } // if/elseif
Packit 062bc7
   } // while
Packit 062bc7
   if ((numFound == itemNum) && (numFound > 0))
Packit 062bc7
      retVal = argument.substr(startPos, endPos - startPos);
Packit 062bc7
Packit 062bc7
   return retVal;
Packit 062bc7
} // GetString()