1fad064250bf6c49eb4966bf0f617591a0821808esrs/*
2e3ee733ff8690af7568dac665bc20ecf869dea1dRoderick W. Smith    Copyright (C) 2010-2013  <Roderick W. Smith>
3fad064250bf6c49eb4966bf0f617591a0821808esrs
4fad064250bf6c49eb4966bf0f617591a0821808esrs    This program is free software; you can redistribute it and/or modify
5fad064250bf6c49eb4966bf0f617591a0821808esrs    it under the terms of the GNU General Public License as published by
6fad064250bf6c49eb4966bf0f617591a0821808esrs    the Free Software Foundation; either version 2 of the License, or
7fad064250bf6c49eb4966bf0f617591a0821808esrs    (at your option) any later version.
8fad064250bf6c49eb4966bf0f617591a0821808esrs
9fad064250bf6c49eb4966bf0f617591a0821808esrs    This program is distributed in the hope that it will be useful,
10fad064250bf6c49eb4966bf0f617591a0821808esrs    but WITHOUT ANY WARRANTY; without even the implied warranty of
11fad064250bf6c49eb4966bf0f617591a0821808esrs    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12fad064250bf6c49eb4966bf0f617591a0821808esrs    GNU General Public License for more details.
13fad064250bf6c49eb4966bf0f617591a0821808esrs
14fad064250bf6c49eb4966bf0f617591a0821808esrs    You should have received a copy of the GNU General Public License along
15fad064250bf6c49eb4966bf0f617591a0821808esrs    with this program; if not, write to the Free Software Foundation, Inc.,
16fad064250bf6c49eb4966bf0f617591a0821808esrs    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17fad064250bf6c49eb4966bf0f617591a0821808esrs
18fad064250bf6c49eb4966bf0f617591a0821808esrs*/
19fad064250bf6c49eb4966bf0f617591a0821808esrs
20fad064250bf6c49eb4966bf0f617591a0821808esrs/* This class implements an interactive text-mode interface atop the
21fad064250bf6c49eb4966bf0f617591a0821808esrs   GPTData class */
22fad064250bf6c49eb4966bf0f617591a0821808esrs
23fad064250bf6c49eb4966bf0f617591a0821808esrs#include <string.h>
24fad064250bf6c49eb4966bf0f617591a0821808esrs#include <errno.h>
2555d926192adc984462509b2966e23bc0d1129bbdsrs#include <stdint.h>
2661768bccdec0016d3d9757d08e63f9a1386c8bc4srs#include <limits.h>
27fad064250bf6c49eb4966bf0f617591a0821808esrs#include <iostream>
28a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs#include <fstream>
29fad064250bf6c49eb4966bf0f617591a0821808esrs#include <sstream>
301c6f8b013e7f5c166abf21c09e319d22b576c41asrs#include <cstdio>
31fad064250bf6c49eb4966bf0f617591a0821808esrs#include "attributes.h"
32fad064250bf6c49eb4966bf0f617591a0821808esrs#include "gpttext.h"
3355d926192adc984462509b2966e23bc0d1129bbdsrs#include "support.h"
34fad064250bf6c49eb4966bf0f617591a0821808esrs
35fad064250bf6c49eb4966bf0f617591a0821808esrsusing namespace std;
36fad064250bf6c49eb4966bf0f617591a0821808esrs
37a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs/********************************************
38a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs *                                          *
39a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * GPTDataText class and related structures *
40a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs *                                          *
41a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs ********************************************/
42fad064250bf6c49eb4966bf0f617591a0821808esrs
43fad064250bf6c49eb4966bf0f617591a0821808esrsGPTDataTextUI::GPTDataTextUI(void) : GPTData() {
44fad064250bf6c49eb4966bf0f617591a0821808esrs} // default constructor
45fad064250bf6c49eb4966bf0f617591a0821808esrs
46fad064250bf6c49eb4966bf0f617591a0821808esrsGPTDataTextUI::GPTDataTextUI(string filename) : GPTData(filename) {
47fad064250bf6c49eb4966bf0f617591a0821808esrs} // constructor passing filename
48fad064250bf6c49eb4966bf0f617591a0821808esrs
49fad064250bf6c49eb4966bf0f617591a0821808esrsGPTDataTextUI::~GPTDataTextUI(void) {
50fad064250bf6c49eb4966bf0f617591a0821808esrs} // default destructor
51fad064250bf6c49eb4966bf0f617591a0821808esrs
52fad064250bf6c49eb4966bf0f617591a0821808esrs/*********************************************************************
53fad064250bf6c49eb4966bf0f617591a0821808esrs *                                                                   *
54fad064250bf6c49eb4966bf0f617591a0821808esrs * The following functions are extended (interactive) versions of    *
55fad064250bf6c49eb4966bf0f617591a0821808esrs * simpler functions in the base class....                           *
56fad064250bf6c49eb4966bf0f617591a0821808esrs *                                                                   *
57fad064250bf6c49eb4966bf0f617591a0821808esrs *********************************************************************/
58fad064250bf6c49eb4966bf0f617591a0821808esrs
59fad064250bf6c49eb4966bf0f617591a0821808esrs// Overridden function; calls base-class function and then makes
60fad064250bf6c49eb4966bf0f617591a0821808esrs// additional queries of the user, if the base-class function can't
61fad064250bf6c49eb4966bf0f617591a0821808esrs// decide what to do.
62fad064250bf6c49eb4966bf0f617591a0821808esrsWhichToUse GPTDataTextUI::UseWhichPartitions(void) {
63fad064250bf6c49eb4966bf0f617591a0821808esrs   WhichToUse which;
64fad064250bf6c49eb4966bf0f617591a0821808esrs   MBRValidity mbrState;
65fad064250bf6c49eb4966bf0f617591a0821808esrs   int answer;
66fad064250bf6c49eb4966bf0f617591a0821808esrs
67fad064250bf6c49eb4966bf0f617591a0821808esrs   which = GPTData::UseWhichPartitions();
68fad064250bf6c49eb4966bf0f617591a0821808esrs   if ((which != use_abort) || beQuiet)
69fad064250bf6c49eb4966bf0f617591a0821808esrs      return which;
70fad064250bf6c49eb4966bf0f617591a0821808esrs
71fad064250bf6c49eb4966bf0f617591a0821808esrs   // If we get past here, it means that the non-interactive tests were
72fad064250bf6c49eb4966bf0f617591a0821808esrs   // inconclusive, so we must ask the user which table to use....
73fad064250bf6c49eb4966bf0f617591a0821808esrs   mbrState = protectiveMBR.GetValidity();
74fad064250bf6c49eb4966bf0f617591a0821808esrs
75fad064250bf6c49eb4966bf0f617591a0821808esrs   if ((state == gpt_valid) && (mbrState == mbr)) {
76fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "Found valid MBR and GPT. Which do you want to use?\n";
77fad064250bf6c49eb4966bf0f617591a0821808esrs      answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
78fad064250bf6c49eb4966bf0f617591a0821808esrs      if (answer == 1) {
79fad064250bf6c49eb4966bf0f617591a0821808esrs         which = use_mbr;
80fad064250bf6c49eb4966bf0f617591a0821808esrs      } else if (answer == 2) {
81fad064250bf6c49eb4966bf0f617591a0821808esrs         which = use_gpt;
82fad064250bf6c49eb4966bf0f617591a0821808esrs         cout << "Using GPT and creating fresh protective MBR.\n";
83fad064250bf6c49eb4966bf0f617591a0821808esrs      } else which = use_new;
84fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if
85fad064250bf6c49eb4966bf0f617591a0821808esrs
86fad064250bf6c49eb4966bf0f617591a0821808esrs   // Nasty decisions here -- GPT is present, but corrupt (bad CRCs or other
87fad064250bf6c49eb4966bf0f617591a0821808esrs   // problems)
88fad064250bf6c49eb4966bf0f617591a0821808esrs   if (state == gpt_corrupt) {
89fad064250bf6c49eb4966bf0f617591a0821808esrs      if ((mbrState == mbr) || (mbrState == hybrid)) {
90fad064250bf6c49eb4966bf0f617591a0821808esrs         cout << "Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n"
91fad064250bf6c49eb4966bf0f617591a0821808esrs              << "GPT MAY permit recovery of GPT data.)\n";
92fad064250bf6c49eb4966bf0f617591a0821808esrs         answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
93fad064250bf6c49eb4966bf0f617591a0821808esrs         if (answer == 1) {
94fad064250bf6c49eb4966bf0f617591a0821808esrs            which = use_mbr;
95fad064250bf6c49eb4966bf0f617591a0821808esrs         } else if (answer == 2) {
96fad064250bf6c49eb4966bf0f617591a0821808esrs            which = use_gpt;
97fad064250bf6c49eb4966bf0f617591a0821808esrs         } else which = use_new;
98fad064250bf6c49eb4966bf0f617591a0821808esrs      } else if (mbrState == invalid) {
99fad064250bf6c49eb4966bf0f617591a0821808esrs         cout << "Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n"
100fad064250bf6c49eb4966bf0f617591a0821808esrs              << "GPT MAY permit recovery of GPT data.)\n";
1010283dae41a7db4563be0fe62241ed230e4a101c0srs         answer = GetNumber(1, 2, 1, " 1 - Use current GPT\n 2 - Create blank GPT\n\nYour answer: ");
102fad064250bf6c49eb4966bf0f617591a0821808esrs         if (answer == 1) {
103fad064250bf6c49eb4966bf0f617591a0821808esrs            which = use_gpt;
104fad064250bf6c49eb4966bf0f617591a0821808esrs         } else which = use_new;
105fad064250bf6c49eb4966bf0f617591a0821808esrs      } // if/else/else
106fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if (corrupt GPT)
107fad064250bf6c49eb4966bf0f617591a0821808esrs
108fad064250bf6c49eb4966bf0f617591a0821808esrs   return which;
109fad064250bf6c49eb4966bf0f617591a0821808esrs} // UseWhichPartitions()
110fad064250bf6c49eb4966bf0f617591a0821808esrs
111fad064250bf6c49eb4966bf0f617591a0821808esrs// Ask the user for a partition number; and prompt for verification
112fad064250bf6c49eb4966bf0f617591a0821808esrs// if the requested partition isn't of a known BSD type.
113fad064250bf6c49eb4966bf0f617591a0821808esrs// Lets the base-class function do the work, and returns its value (the
114fad064250bf6c49eb4966bf0f617591a0821808esrs// number of converted partitions).
115fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::XFormDisklabel(void) {
116fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t partNum;
117fad064250bf6c49eb4966bf0f617591a0821808esrs   uint16_t hexCode;
118fad064250bf6c49eb4966bf0f617591a0821808esrs   int goOn = 1, numDone = 0;
119fad064250bf6c49eb4966bf0f617591a0821808esrs   BSDData disklabel;
120fad064250bf6c49eb4966bf0f617591a0821808esrs
121fad064250bf6c49eb4966bf0f617591a0821808esrs   partNum = GetPartNum();
122fad064250bf6c49eb4966bf0f617591a0821808esrs
123fad064250bf6c49eb4966bf0f617591a0821808esrs   // Now see if the specified partition has a BSD type code....
124fad064250bf6c49eb4966bf0f617591a0821808esrs   hexCode = partitions[partNum].GetHexType();
125fad064250bf6c49eb4966bf0f617591a0821808esrs   if ((hexCode != 0xa500) && (hexCode != 0xa900)) {
126fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "Specified partition doesn't have a disklabel partition type "
127fad064250bf6c49eb4966bf0f617591a0821808esrs           << "code.\nContinue anyway? ";
128fad064250bf6c49eb4966bf0f617591a0821808esrs      goOn = (GetYN() == 'Y');
129fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if
130fad064250bf6c49eb4966bf0f617591a0821808esrs
131fad064250bf6c49eb4966bf0f617591a0821808esrs   if (goOn)
132fad064250bf6c49eb4966bf0f617591a0821808esrs      numDone = GPTData::XFormDisklabel(partNum);
133fad064250bf6c49eb4966bf0f617591a0821808esrs
134fad064250bf6c49eb4966bf0f617591a0821808esrs   return numDone;
1351eea9b0b51367472ce12efb59b0018c0ac96a463Roderick W. Smith} // GPTData::XFormDisklabel(void)
136fad064250bf6c49eb4966bf0f617591a0821808esrs
13755d926192adc984462509b2966e23bc0d1129bbdsrs
138fad064250bf6c49eb4966bf0f617591a0821808esrs/*********************************************************************
139fad064250bf6c49eb4966bf0f617591a0821808esrs *                                                                   *
140fad064250bf6c49eb4966bf0f617591a0821808esrs * Begin functions that obtain information from the users, and often *
141fad064250bf6c49eb4966bf0f617591a0821808esrs * do something with that information (call other functions)         *
142fad064250bf6c49eb4966bf0f617591a0821808esrs *                                                                   *
143fad064250bf6c49eb4966bf0f617591a0821808esrs *********************************************************************/
144fad064250bf6c49eb4966bf0f617591a0821808esrs
145a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Prompts user for partition number and returns the result. Returns "0"
146a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// (the first partition) if none are currently defined.
147fad064250bf6c49eb4966bf0f617591a0821808esrsuint32_t GPTDataTextUI::GetPartNum(void) {
148fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t partNum;
149fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t low, high;
150fad064250bf6c49eb4966bf0f617591a0821808esrs   ostringstream prompt;
151fad064250bf6c49eb4966bf0f617591a0821808esrs
152fad064250bf6c49eb4966bf0f617591a0821808esrs   if (GetPartRange(&low, &high) > 0) {
153fad064250bf6c49eb4966bf0f617591a0821808esrs      prompt << "Partition number (" << low + 1 << "-" << high + 1 << "): ";
154fad064250bf6c49eb4966bf0f617591a0821808esrs      partNum = GetNumber(low + 1, high + 1, low, prompt.str());
155fad064250bf6c49eb4966bf0f617591a0821808esrs   } else partNum = 1;
156fad064250bf6c49eb4966bf0f617591a0821808esrs   return (partNum - 1);
157fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::GetPartNum()
158fad064250bf6c49eb4966bf0f617591a0821808esrs
159fad064250bf6c49eb4966bf0f617591a0821808esrs// What it says: Resize the partition table. (Default is 128 entries.)
160fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::ResizePartitionTable(void) {
161fad064250bf6c49eb4966bf0f617591a0821808esrs   int newSize;
162fad064250bf6c49eb4966bf0f617591a0821808esrs   ostringstream prompt;
163fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t curLow, curHigh;
164fad064250bf6c49eb4966bf0f617591a0821808esrs
1650283dae41a7db4563be0fe62241ed230e4a101c0srs   cout << "Current partition table size is " << numParts << ".\n";
166fad064250bf6c49eb4966bf0f617591a0821808esrs   GetPartRange(&curLow, &curHigh);
167fad064250bf6c49eb4966bf0f617591a0821808esrs   curHigh++; // since GetPartRange() returns numbers starting from 0...
168fad064250bf6c49eb4966bf0f617591a0821808esrs   // There's no point in having fewer than four partitions....
169fad064250bf6c49eb4966bf0f617591a0821808esrs   if (curHigh < (blockSize / GPT_SIZE))
170fad064250bf6c49eb4966bf0f617591a0821808esrs      curHigh = blockSize / GPT_SIZE;
171fad064250bf6c49eb4966bf0f617591a0821808esrs   prompt << "Enter new size (" << curHigh << " up, default " << NUM_GPT_ENTRIES << "): ";
172fad064250bf6c49eb4966bf0f617591a0821808esrs   newSize = GetNumber(4, 65535, 128, prompt.str());
173fad064250bf6c49eb4966bf0f617591a0821808esrs   if (newSize < 128) {
174fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "Caution: The partition table size should officially be 16KB or larger,\n"
175fad064250bf6c49eb4966bf0f617591a0821808esrs           << "which works out to 128 entries. In practice, smaller tables seem to\n"
176fad064250bf6c49eb4966bf0f617591a0821808esrs           << "work with most OSes, but this practice is risky. I'm proceeding with\n"
177fad064250bf6c49eb4966bf0f617591a0821808esrs           << "the resize, but you may want to reconsider this action and undo it.\n\n";
178fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if
179fad064250bf6c49eb4966bf0f617591a0821808esrs   SetGPTSize(newSize);
180fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::ResizePartitionTable()
181fad064250bf6c49eb4966bf0f617591a0821808esrs
182fad064250bf6c49eb4966bf0f617591a0821808esrs// Interactively create a partition
183fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::CreatePartition(void) {
1845a081757ea2e32a491349544fea92826ccf739f6srs   uint64_t firstBlock, firstInLargest, lastBlock, sector, origSector;
185fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t firstFreePart = 0;
186fad064250bf6c49eb4966bf0f617591a0821808esrs   ostringstream prompt1, prompt2, prompt3;
187fad064250bf6c49eb4966bf0f617591a0821808esrs   int partNum;
188fad064250bf6c49eb4966bf0f617591a0821808esrs
189fad064250bf6c49eb4966bf0f617591a0821808esrs   // Find first free partition...
190fad064250bf6c49eb4966bf0f617591a0821808esrs   while (partitions[firstFreePart].GetFirstLBA() != 0) {
191fad064250bf6c49eb4966bf0f617591a0821808esrs      firstFreePart++;
192fad064250bf6c49eb4966bf0f617591a0821808esrs   } // while
193fad064250bf6c49eb4966bf0f617591a0821808esrs
194fad064250bf6c49eb4966bf0f617591a0821808esrs   if (((firstBlock = FindFirstAvailable()) != 0) &&
1950283dae41a7db4563be0fe62241ed230e4a101c0srs       (firstFreePart < numParts)) {
196fad064250bf6c49eb4966bf0f617591a0821808esrs      lastBlock = FindLastAvailable();
19755d926192adc984462509b2966e23bc0d1129bbdsrs      firstInLargest = FindFirstInLargest();
1980541b56fee4e92822340a2b2387508dd58d0ca7csrs      Align(&firstInLargest);
19955d926192adc984462509b2966e23bc0d1129bbdsrs
20055d926192adc984462509b2966e23bc0d1129bbdsrs      // Get partition number....
201f694803eca2074523b8e502d386ca03b5642a63bRoderick W. Smith      prompt1 << "Partition number (" << firstFreePart + 1 << "-" << numParts
202f694803eca2074523b8e502d386ca03b5642a63bRoderick W. Smith              << ", default " << firstFreePart + 1 << "): ";
20355d926192adc984462509b2966e23bc0d1129bbdsrs      do {
2040283dae41a7db4563be0fe62241ed230e4a101c0srs         partNum = GetNumber(firstFreePart + 1, numParts,
20555d926192adc984462509b2966e23bc0d1129bbdsrs                             firstFreePart + 1, prompt1.str()) - 1;
20655d926192adc984462509b2966e23bc0d1129bbdsrs         if (partitions[partNum].GetFirstLBA() != 0)
20755d926192adc984462509b2966e23bc0d1129bbdsrs            cout << "partition " << partNum + 1 << " is in use.\n";
20855d926192adc984462509b2966e23bc0d1129bbdsrs      } while (partitions[partNum].GetFirstLBA() != 0);
20955d926192adc984462509b2966e23bc0d1129bbdsrs
21055d926192adc984462509b2966e23bc0d1129bbdsrs      // Get first block for new partition...
21155d926192adc984462509b2966e23bc0d1129bbdsrs      prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = "
2120873e9d0e9345a2c4418b4718db525c9f1111c83srs              << firstInLargest << ") or {+-}size{KMGTP}: ";
21355d926192adc984462509b2966e23bc0d1129bbdsrs      do {
2140873e9d0e9345a2c4418b4718db525c9f1111c83srs         sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, blockSize, prompt2.str());
21555d926192adc984462509b2966e23bc0d1129bbdsrs      } while (IsFree(sector) == 0);
2165a081757ea2e32a491349544fea92826ccf739f6srs      origSector = sector;
2175a081757ea2e32a491349544fea92826ccf739f6srs      if (Align(&sector)) {
2185a081757ea2e32a491349544fea92826ccf739f6srs         cout << "Information: Moved requested sector from " << origSector << " to "
2195a081757ea2e32a491349544fea92826ccf739f6srs              << sector << " in\norder to align on " << sectorAlignment
2205a081757ea2e32a491349544fea92826ccf739f6srs              << "-sector boundaries.\n";
2215a081757ea2e32a491349544fea92826ccf739f6srs         if (!beQuiet)
2225a081757ea2e32a491349544fea92826ccf739f6srs            cout << "Use 'l' on the experts' menu to adjust alignment\n";
2235a081757ea2e32a491349544fea92826ccf739f6srs      } // if
2245a081757ea2e32a491349544fea92826ccf739f6srs      //      Align(&sector); // Align sector to correct multiple
22555d926192adc984462509b2966e23bc0d1129bbdsrs      firstBlock = sector;
22655d926192adc984462509b2966e23bc0d1129bbdsrs
22755d926192adc984462509b2966e23bc0d1129bbdsrs      // Get last block for new partitions...
22855d926192adc984462509b2966e23bc0d1129bbdsrs      lastBlock = FindLastInFree(firstBlock);
22955d926192adc984462509b2966e23bc0d1129bbdsrs      prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = "
2300873e9d0e9345a2c4418b4718db525c9f1111c83srs            << lastBlock << ") or {+-}size{KMGTP}: ";
23155d926192adc984462509b2966e23bc0d1129bbdsrs      do {
2320873e9d0e9345a2c4418b4718db525c9f1111c83srs         sector = GetSectorNum(firstBlock, lastBlock, lastBlock, blockSize, prompt3.str());
23355d926192adc984462509b2966e23bc0d1129bbdsrs      } while (IsFree(sector) == 0);
23455d926192adc984462509b2966e23bc0d1129bbdsrs      lastBlock = sector;
23555d926192adc984462509b2966e23bc0d1129bbdsrs
23655d926192adc984462509b2966e23bc0d1129bbdsrs      firstFreePart = GPTData::CreatePartition(partNum, firstBlock, lastBlock);
23755d926192adc984462509b2966e23bc0d1129bbdsrs      partitions[partNum].ChangeType();
23855d926192adc984462509b2966e23bc0d1129bbdsrs      partitions[partNum].SetDefaultDescription();
239fad064250bf6c49eb4966bf0f617591a0821808esrs   } else {
240bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      if (firstFreePart >= numParts)
241bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         cout << "No table partition entries left\n";
242bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      else
243bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         cout << "No free sectors available\n";
244fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if/else
245fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::CreatePartition()
246fad064250bf6c49eb4966bf0f617591a0821808esrs
247fad064250bf6c49eb4966bf0f617591a0821808esrs// Interactively delete a partition (duh!)
248fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::DeletePartition(void) {
249fad064250bf6c49eb4966bf0f617591a0821808esrs   int partNum;
250fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t low, high;
251fad064250bf6c49eb4966bf0f617591a0821808esrs   ostringstream prompt;
252fad064250bf6c49eb4966bf0f617591a0821808esrs
253fad064250bf6c49eb4966bf0f617591a0821808esrs   if (GetPartRange(&low, &high) > 0) {
254fad064250bf6c49eb4966bf0f617591a0821808esrs      prompt << "Partition number (" << low + 1 << "-" << high + 1 << "): ";
255fad064250bf6c49eb4966bf0f617591a0821808esrs      partNum = GetNumber(low + 1, high + 1, low, prompt.str());
256fad064250bf6c49eb4966bf0f617591a0821808esrs      GPTData::DeletePartition(partNum - 1);
257fad064250bf6c49eb4966bf0f617591a0821808esrs   } else {
258fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "No partitions\n";
259fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if/else
260fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::DeletePartition()
261fad064250bf6c49eb4966bf0f617591a0821808esrs
262fad064250bf6c49eb4966bf0f617591a0821808esrs// Prompt user for a partition number, then change its type code
263fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::ChangePartType(void) {
264fad064250bf6c49eb4966bf0f617591a0821808esrs   int partNum;
265fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t low, high;
26655d926192adc984462509b2966e23bc0d1129bbdsrs
267fad064250bf6c49eb4966bf0f617591a0821808esrs   if (GetPartRange(&low, &high) > 0) {
268fad064250bf6c49eb4966bf0f617591a0821808esrs      partNum = GetPartNum();
269fad064250bf6c49eb4966bf0f617591a0821808esrs      partitions[partNum].ChangeType();
270fad064250bf6c49eb4966bf0f617591a0821808esrs   } else {
271fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "No partitions\n";
272fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if/else
273fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::ChangePartType()
274fad064250bf6c49eb4966bf0f617591a0821808esrs
275815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// Prompt user for a partition number, then change its unique
276815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs// GUID.
277815fb65195106b8afe1b8dfec5dae605dbd7ccbesrsvoid GPTDataTextUI::ChangeUniqueGuid(void) {
278815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs   int partNum;
279815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs   uint32_t low, high;
280815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs   string guidStr;
281815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs
282815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs   if (GetPartRange(&low, &high) > 0) {
283815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      partNum = GetPartNum();
284815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      cout << "Enter the partition's new unique GUID ('R' to randomize): ";
285815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      guidStr = ReadString();
286815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      if ((guidStr.length() >= 32) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
287815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs         SetPartitionGUID(partNum, (GUIDData) guidStr);
288815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs         cout << "New GUID is " << partitions[partNum].GetUniqueGUID() << "\n";
289815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      } else {
290815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs         cout << "GUID is too short!\n";
291815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      } // if/else
292815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs   } else
293815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs      cout << "No partitions\n";
294815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs} // GPTDataTextUI::ChangeUniqueGuid()
295815fb65195106b8afe1b8dfec5dae605dbd7ccbesrs
296fad064250bf6c49eb4966bf0f617591a0821808esrs// Partition attributes seem to be rarely used, but I want a way to
297fad064250bf6c49eb4966bf0f617591a0821808esrs// adjust them for completeness....
298fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::SetAttributes(uint32_t partNum) {
2990873e9d0e9345a2c4418b4718db525c9f1111c83srs   partitions[partNum].SetAttributes();
300fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::SetAttributes()
301fad064250bf6c49eb4966bf0f617591a0821808esrs
302699941e25a1fcf0beec124203747c8ed20842989srs// Prompts the user for a partition name and sets the partition's
303699941e25a1fcf0beec124203747c8ed20842989srs// name. Returns 1 on success, 0 on failure (invalid partition
304699941e25a1fcf0beec124203747c8ed20842989srs// number). (Note that the function skips prompting when an
305699941e25a1fcf0beec124203747c8ed20842989srs// invalid partition number is detected.)
306699941e25a1fcf0beec124203747c8ed20842989srsint GPTDataTextUI::SetName(uint32_t partNum) {
307699941e25a1fcf0beec124203747c8ed20842989srs   UnicodeString theName = "";
308699941e25a1fcf0beec124203747c8ed20842989srs   int retval = 1;
309699941e25a1fcf0beec124203747c8ed20842989srs
310699941e25a1fcf0beec124203747c8ed20842989srs   if (IsUsedPartNum(partNum)) {
311699941e25a1fcf0beec124203747c8ed20842989srs      cout << "Enter name: ";
31284aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#ifdef USE_UTF16
313699941e25a1fcf0beec124203747c8ed20842989srs      theName = ReadUString();
31484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#else
31584aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith      theName = ReadString();
31684aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#endif
317699941e25a1fcf0beec124203747c8ed20842989srs      partitions[partNum].SetName(theName);
318699941e25a1fcf0beec124203747c8ed20842989srs   } else {
319699941e25a1fcf0beec124203747c8ed20842989srs      cerr << "Invalid partition number (" << partNum << ")\n";
320699941e25a1fcf0beec124203747c8ed20842989srs      retval = 0;
321699941e25a1fcf0beec124203747c8ed20842989srs   } // if/else
322699941e25a1fcf0beec124203747c8ed20842989srs
323699941e25a1fcf0beec124203747c8ed20842989srs   return retval;
324699941e25a1fcf0beec124203747c8ed20842989srs} // GPTDataTextUI::SetName()
325699941e25a1fcf0beec124203747c8ed20842989srs
326fad064250bf6c49eb4966bf0f617591a0821808esrs// Ask user for two partition numbers and swap them in the table. Note that
327fad064250bf6c49eb4966bf0f617591a0821808esrs// this just reorders table entries; it doesn't adjust partition layout on
328fad064250bf6c49eb4966bf0f617591a0821808esrs// the disk.
329fad064250bf6c49eb4966bf0f617591a0821808esrs// Returns 1 if successful, 0 if not. (If user enters identical numbers, it
330fad064250bf6c49eb4966bf0f617591a0821808esrs// counts as successful.)
331fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::SwapPartitions(void) {
332fad064250bf6c49eb4966bf0f617591a0821808esrs   int partNum1, partNum2, didIt = 0;
333fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t low, high;
334fad064250bf6c49eb4966bf0f617591a0821808esrs   ostringstream prompt;
335fad064250bf6c49eb4966bf0f617591a0821808esrs   GPTPart temp;
336fad064250bf6c49eb4966bf0f617591a0821808esrs
337fad064250bf6c49eb4966bf0f617591a0821808esrs   if (GetPartRange(&low, &high) > 0) {
338fad064250bf6c49eb4966bf0f617591a0821808esrs      partNum1 = GetPartNum();
3390283dae41a7db4563be0fe62241ed230e4a101c0srs      if (high >= numParts - 1)
340fad064250bf6c49eb4966bf0f617591a0821808esrs         high = 0;
3410283dae41a7db4563be0fe62241ed230e4a101c0srs      prompt << "New partition number (1-" << numParts
34255d926192adc984462509b2966e23bc0d1129bbdsrs             << ", default " << high + 2 << "): ";
3430283dae41a7db4563be0fe62241ed230e4a101c0srs      partNum2 = GetNumber(1, numParts, high + 2, prompt.str()) - 1;
344fad064250bf6c49eb4966bf0f617591a0821808esrs      didIt = GPTData::SwapPartitions(partNum1, partNum2);
345fad064250bf6c49eb4966bf0f617591a0821808esrs   } else {
346fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "No partitions\n";
347fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if/else
348fad064250bf6c49eb4966bf0f617591a0821808esrs   return didIt;
349fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::SwapPartitionNumbers()
350fad064250bf6c49eb4966bf0f617591a0821808esrs
351fad064250bf6c49eb4966bf0f617591a0821808esrs// This function destroys the on-disk GPT structures. Returns 1 if the user
352fad064250bf6c49eb4966bf0f617591a0821808esrs// confirms destruction, 0 if the user aborts or if there's a disk error.
353fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::DestroyGPTwPrompt(void) {
354fad064250bf6c49eb4966bf0f617591a0821808esrs   int allOK = 1;
355fad064250bf6c49eb4966bf0f617591a0821808esrs
356fad064250bf6c49eb4966bf0f617591a0821808esrs   if ((apmFound) || (bsdFound)) {
357fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "WARNING: APM or BSD disklabel structures detected! This operation could\n"
358fad064250bf6c49eb4966bf0f617591a0821808esrs           << "damage any APM or BSD partitions on this disk!\n";
359fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if APM or BSD
360fad064250bf6c49eb4966bf0f617591a0821808esrs   cout << "\a\aAbout to wipe out GPT on " << device << ". Proceed? ";
361fad064250bf6c49eb4966bf0f617591a0821808esrs   if (GetYN() == 'Y') {
362fad064250bf6c49eb4966bf0f617591a0821808esrs      if (DestroyGPT()) {
363fad064250bf6c49eb4966bf0f617591a0821808esrs         // Note on below: Touch the MBR only if the user wants it completely
364fad064250bf6c49eb4966bf0f617591a0821808esrs         // blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
365fad064250bf6c49eb4966bf0f617591a0821808esrs         // the MBR, but this could wipe out a valid MBR that the program
366fad064250bf6c49eb4966bf0f617591a0821808esrs         // had subsequently discarded (say, if it conflicted with older GPT
367fad064250bf6c49eb4966bf0f617591a0821808esrs         // structures).
368fad064250bf6c49eb4966bf0f617591a0821808esrs         cout << "Blank out MBR? ";
369fad064250bf6c49eb4966bf0f617591a0821808esrs         if (GetYN() == 'Y') {
370fad064250bf6c49eb4966bf0f617591a0821808esrs            DestroyMBR();
371fad064250bf6c49eb4966bf0f617591a0821808esrs         } else {
372fad064250bf6c49eb4966bf0f617591a0821808esrs            cout << "MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
373fad064250bf6c49eb4966bf0f617591a0821808esrs                 << "with fdisk or another tool.\n";
374fad064250bf6c49eb4966bf0f617591a0821808esrs         } // if/else
375fad064250bf6c49eb4966bf0f617591a0821808esrs      } else allOK = 0; // if GPT structures destroyed
376fad064250bf6c49eb4966bf0f617591a0821808esrs   } else allOK = 0; // if user confirms destruction
377fad064250bf6c49eb4966bf0f617591a0821808esrs   return (allOK);
378fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::DestroyGPTwPrompt()
379fad064250bf6c49eb4966bf0f617591a0821808esrs
380fad064250bf6c49eb4966bf0f617591a0821808esrs// Get partition number from user and then call ShowPartDetails(partNum)
381fad064250bf6c49eb4966bf0f617591a0821808esrs// to show its detailed information
382fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::ShowDetails(void) {
383fad064250bf6c49eb4966bf0f617591a0821808esrs   int partNum;
384fad064250bf6c49eb4966bf0f617591a0821808esrs   uint32_t low, high;
38555d926192adc984462509b2966e23bc0d1129bbdsrs
386fad064250bf6c49eb4966bf0f617591a0821808esrs   if (GetPartRange(&low, &high) > 0) {
387fad064250bf6c49eb4966bf0f617591a0821808esrs      partNum = GetPartNum();
388fad064250bf6c49eb4966bf0f617591a0821808esrs      ShowPartDetails(partNum);
389fad064250bf6c49eb4966bf0f617591a0821808esrs   } else {
390fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "No partitions\n";
391fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if/else
392fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::ShowDetails()
393fad064250bf6c49eb4966bf0f617591a0821808esrs
394fad064250bf6c49eb4966bf0f617591a0821808esrs// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
395fad064250bf6c49eb4966bf0f617591a0821808esrs// OSes that don't understand GPT.
396fad064250bf6c49eb4966bf0f617591a0821808esrsvoid GPTDataTextUI::MakeHybrid(void) {
397a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith   uint32_t partNums[3] = {0, 0, 0};
3985a6085310b7f8fe1c35e56bcab7de161808b488dsrs   string line;
399a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith   int numPartsToCvt = 0, numConverted = 0, i, j, mbrNum = 0;
40055d926192adc984462509b2966e23bc0d1129bbdsrs   unsigned int hexCode = 0;
401bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs   MBRPart hybridPart;
402bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs   MBRData hybridMBR;
403fad064250bf6c49eb4966bf0f617591a0821808esrs   char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
404fad064250bf6c49eb4966bf0f617591a0821808esrs
405058d4a58614e07921a306857294ed017991097a9srs   cout << "\nWARNING! Hybrid MBRs are flaky and dangerous! If you decide not to use one,\n"
406058d4a58614e07921a306857294ed017991097a9srs        << "just hit the Enter key at the below prompt and your MBR partition table will\n"
407058d4a58614e07921a306857294ed017991097a9srs        << "be untouched.\n\n\a";
408fad064250bf6c49eb4966bf0f617591a0821808esrs
4096aae2a9b70e9f88926baad94c1eea40e0b534f01srs   // Use a local MBR structure, copying from protectiveMBR to keep its
4106aae2a9b70e9f88926baad94c1eea40e0b534f01srs   // boot loader code intact....
4116aae2a9b70e9f88926baad94c1eea40e0b534f01srs   hybridMBR = protectiveMBR;
4126aae2a9b70e9f88926baad94c1eea40e0b534f01srs   hybridMBR.EmptyMBR(0);
4136aae2a9b70e9f88926baad94c1eea40e0b534f01srs
414fad064250bf6c49eb4966bf0f617591a0821808esrs   // Now get the numbers of up to three partitions to add to the
415fad064250bf6c49eb4966bf0f617591a0821808esrs   // hybrid MBR....
416fad064250bf6c49eb4966bf0f617591a0821808esrs   cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n"
417fad064250bf6c49eb4966bf0f617591a0821808esrs        << "added to the hybrid MBR, in sequence: ";
4185a6085310b7f8fe1c35e56bcab7de161808b488dsrs   line = ReadString();
4199b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith   istringstream inLine(line);
4209b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith   do {
421a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith      inLine >> partNums[numPartsToCvt];
422a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith      if (partNums[numPartsToCvt] > 0)
423a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         numPartsToCvt++;
4249b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith   } while (!inLine.eof() && (numPartsToCvt < 3));
425fad064250bf6c49eb4966bf0f617591a0821808esrs
4260283dae41a7db4563be0fe62241ed230e4a101c0srs   if (numPartsToCvt > 0) {
427fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? ";
428fad064250bf6c49eb4966bf0f617591a0821808esrs      eeFirst = GetYN();
429fad064250bf6c49eb4966bf0f617591a0821808esrs   } // if
430fad064250bf6c49eb4966bf0f617591a0821808esrs
4310283dae41a7db4563be0fe62241ed230e4a101c0srs   for (i = 0; i < numPartsToCvt; i++) {
432bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      j = partNums[i] - 1;
433a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith      if (partitions[j].IsUsed() && (partitions[j].IsSizedForMBR() != MBR_SIZED_BAD)) {
434058d4a58614e07921a306857294ed017991097a9srs         mbrNum = i + (eeFirst == 'Y');
435058d4a58614e07921a306857294ed017991097a9srs         cout << "\nCreating entry for GPT partition #" << j + 1
436058d4a58614e07921a306857294ed017991097a9srs              << " (MBR partition #" << mbrNum + 1 << ")\n";
437bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         hybridPart.SetType(GetMBRTypeCode(partitions[j].GetHexType() / 256));
438bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         hybridPart.SetLocation(partitions[j].GetFirstLBA(), partitions[j].GetLengthLBA());
439bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         hybridPart.SetInclusion(PRIMARY);
440058d4a58614e07921a306857294ed017991097a9srs         cout << "Set the bootable flag? ";
441058d4a58614e07921a306857294ed017991097a9srs         if (GetYN() == 'Y')
4426aae2a9b70e9f88926baad94c1eea40e0b534f01srs            hybridPart.SetStatus(0x80);
443058d4a58614e07921a306857294ed017991097a9srs         else
4446aae2a9b70e9f88926baad94c1eea40e0b534f01srs            hybridPart.SetStatus(0x00);
445bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         hybridPart.SetInclusion(PRIMARY);
446a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         if (partitions[j].IsSizedForMBR() == MBR_SIZED_IFFY)
447a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith            WarnAboutIffyMBRPart(j + 1);
448a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         numConverted++;
449058d4a58614e07921a306857294ed017991097a9srs      } else {
4509b338c50f298d04f47205f7fad082d8c21797ed7Roderick W. Smith         cerr << "\nGPT partition #" << j + 1 << " does not exist or is too big; skipping.\n";
451058d4a58614e07921a306857294ed017991097a9srs      } // if/else
452bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      hybridMBR.AddPart(mbrNum, hybridPart);
453fad064250bf6c49eb4966bf0f617591a0821808esrs   } // for
454fad064250bf6c49eb4966bf0f617591a0821808esrs
455a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith   if (numConverted > 0) { // User opted to create a hybrid MBR....
456fad064250bf6c49eb4966bf0f617591a0821808esrs      // Create EFI protective partition that covers the start of the disk.
457fad064250bf6c49eb4966bf0f617591a0821808esrs      // If this location (covering the main GPT data structures) is omitted,
458fad064250bf6c49eb4966bf0f617591a0821808esrs      // Linux won't find any partitions on the disk.
459bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      hybridPart.SetLocation(1, hybridMBR.FindLastInFree(1));
460bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      hybridPart.SetStatus(0);
461bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      hybridPart.SetType(0xEE);
462bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      hybridPart.SetInclusion(PRIMARY);
46355d926192adc984462509b2966e23bc0d1129bbdsrs      // newNote firstLBA and lastLBA are computed later...
46455d926192adc984462509b2966e23bc0d1129bbdsrs      if (eeFirst == 'Y') {
465bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         hybridMBR.AddPart(0, hybridPart);
46655d926192adc984462509b2966e23bc0d1129bbdsrs      } else {
467a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         hybridMBR.AddPart(numConverted, hybridPart);
46855d926192adc984462509b2966e23bc0d1129bbdsrs      } // else
469bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      hybridMBR.SetHybrid();
470fad064250bf6c49eb4966bf0f617591a0821808esrs
471fad064250bf6c49eb4966bf0f617591a0821808esrs      // ... and for good measure, if there are any partition spaces left,
472fad064250bf6c49eb4966bf0f617591a0821808esrs      // optionally create another protective EFI partition to cover as much
473fad064250bf6c49eb4966bf0f617591a0821808esrs      // space as possible....
474bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      if (hybridMBR.CountParts() < 4) { // unused entry....
47555d926192adc984462509b2966e23bc0d1129bbdsrs         cout << "\nUnused partition space(s) found. Use one to protect more partitions? ";
47655d926192adc984462509b2966e23bc0d1129bbdsrs         if (GetYN() == 'Y') {
4775a6085310b7f8fe1c35e56bcab7de161808b488dsrs            cout << "Note: Default is 0xEE, but this may confuse Mac OS X.\n";
4785a6085310b7f8fe1c35e56bcab7de161808b488dsrs            // Comment on above: Mac OS treats disks with more than one
4795a6085310b7f8fe1c35e56bcab7de161808b488dsrs            // 0xEE MBR partition as MBR disks, not as GPT disks.
4805a6085310b7f8fe1c35e56bcab7de161808b488dsrs            hexCode = GetMBRTypeCode(0xEE);
4815a6085310b7f8fe1c35e56bcab7de161808b488dsrs            hybridMBR.MakeBiggestPart(3, hexCode);
48255d926192adc984462509b2966e23bc0d1129bbdsrs         } // if (GetYN() == 'Y')
48355d926192adc984462509b2966e23bc0d1129bbdsrs      } // if unused entry
484bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      protectiveMBR = hybridMBR;
485a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith   } else {
486a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith      cout << "\nNo partitions converted; original protective/hybrid MBR is unmodified!\n";
487a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith   } // if/else (numConverted > 0)
488fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::MakeHybrid()
489fad064250bf6c49eb4966bf0f617591a0821808esrs
49055d926192adc984462509b2966e23bc0d1129bbdsrs// Convert the GPT to MBR form, storing partitions in the protectiveMBR
49155d926192adc984462509b2966e23bc0d1129bbdsrs// variable. This function is necessarily limited; it may not be able to
49255d926192adc984462509b2966e23bc0d1129bbdsrs// convert all partitions, depending on the disk size and available space
49355d926192adc984462509b2966e23bc0d1129bbdsrs// before each partition (one free sector is required to create a logical
49455d926192adc984462509b2966e23bc0d1129bbdsrs// partition, which are necessary to convert more than four partitions).
49555d926192adc984462509b2966e23bc0d1129bbdsrs// Returns the number of converted partitions; if this value
496fad064250bf6c49eb4966bf0f617591a0821808esrs// is over 0, the calling function should call DestroyGPT() to destroy
49755d926192adc984462509b2966e23bc0d1129bbdsrs// the GPT data, call SaveMBR() to save the MBR, and then exit.
498fad064250bf6c49eb4966bf0f617591a0821808esrsint GPTDataTextUI::XFormToMBR(void) {
49955d926192adc984462509b2966e23bc0d1129bbdsrs   uint32_t i;
50055d926192adc984462509b2966e23bc0d1129bbdsrs
5016aae2a9b70e9f88926baad94c1eea40e0b534f01srs   protectiveMBR.EmptyMBR(0);
502bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs   for (i = 0; i < numParts; i++) {
503bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      if (partitions[i].IsUsed()) {
504a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         if (partitions[i].IsSizedForMBR() == MBR_SIZED_IFFY)
505a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith            WarnAboutIffyMBRPart(i + 1);
506a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         // Note: MakePart() checks for oversized partitions, so don't
507a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith         // bother checking other IsSizedForMBR() return values....
508bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs         protectiveMBR.MakePart(i, partitions[i].GetFirstLBA(),
509bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs                                partitions[i].GetLengthLBA(),
510bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs                                partitions[i].GetHexType() / 0x0100, 0);
511bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs      } // if
512bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs   } // for
513bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs   protectiveMBR.MakeItLegal();
514bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs   return protectiveMBR.DoMenu();
515fad064250bf6c49eb4966bf0f617591a0821808esrs} // GPTDataTextUI::XFormToMBR()
516fad064250bf6c49eb4966bf0f617591a0821808esrs
517a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith/******************************************************
518a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith *                                                    *
519a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith * Display informational messages for the user....    *
520a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith *                                                    *
521a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith ******************************************************/
522a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith
523a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// Although an MBR partition that begins below sector 2^32 and is less than 2^32 sectors in
524a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// length is technically legal even if it ends above the 2^32-sector mark, such a partition
525a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// tends to confuse a lot of OSes, so warn the user about such partitions. This function is
526a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// called by XFormToMBR() and MakeHybrid(); it's a separate function just to consolidate the
527a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith// lengthy message in one place.
528a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smithvoid GPTDataTextUI::WarnAboutIffyMBRPart(int partNum) {
529a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith   cout << "\a\nWarning! GPT partition " << partNum << " ends after the 2^32 sector mark! The partition\n"
530a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith        << "begins before this point, and is smaller than 2^32 sectors. This is technically\n"
531a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith        << "legal, but will confuse some OSes. The partition IS being added to the MBR, but\n"
532a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith        << "if your OS misbehaves or can't see the partition, the partition may simply be\n"
533a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith        << "unusable in that OS and may need to be resized or omitted from the MBR.\n\n";
534a345a922606a88447d2d89e28189d5372a75ea07Roderick W. Smith} // GPTDataTextUI::WarnAboutIffyMBRPart()
535a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
536a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs/*********************************************************************
537a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs *                                                                   *
538a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * The following functions provide the main menus for the gdisk      *
539a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs * program....                                                       *
540a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs *                                                                   *
541a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs *********************************************************************/
542a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
543a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Accept a command and execute it. Returns only when the user
544a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// wants to exit (such as after a 'w' or 'q' command).
545a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::MainMenu(string filename) {
546a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   int goOn = 1;
547a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   PartType typeHelper;
548a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   uint32_t temp1, temp2;
549a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs
550a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   do {
551a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      cout << "\nCommand (? for help): ";
552a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      switch (ReadString()[0]) {
553a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case '\0':
554a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs            goOn = cin.good();
555a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
556a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'b': case 'B':
557a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Enter backup filename to save: ";
558a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            SaveGPTBackup(ReadString());
559a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
560a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'c': case 'C':
561a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (GetPartRange(&temp1, &temp2) > 0)
562a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               SetName(GetPartNum());
563a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            else
564a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               cout << "No partitions\n";
565a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
566a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'd': case 'D':
567a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            DeletePartition();
568a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
569a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'i': case 'I':
570a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ShowDetails();
571a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
572a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'l': case 'L':
573a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            typeHelper.ShowAllTypes();
574a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
575a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'n': case 'N':
576a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            CreatePartition();
577a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
578a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'o': case 'O':
579a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "This option deletes all partitions and creates a new protective MBR.\n"
580a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs                 << "Proceed? ";
581a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (GetYN() == 'Y') {
582a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               ClearGPTData();
583a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               MakeProtectiveMBR();
584a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if
585a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
586a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'p': case 'P':
587a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            DisplayGPTData();
588a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
589a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'q': case 'Q':
590a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
591a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
592a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'r': case 'R':
593a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            RecoveryMenu(filename);
594a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
595a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
596a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 's': case 'S':
597a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            SortGPT();
598a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "You may need to edit /etc/fstab and/or your boot loader configuration!\n";
599a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
600a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 't': case 'T':
601a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ChangePartType();
602a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
603a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'v': case 'V':
604a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            Verify();
605a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
606a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'w': case 'W':
607a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (SaveGPTData() == 1)
608a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               goOn = 0;
609a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
610a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'x': case 'X':
611a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ExpertsMenu(filename);
612a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
613a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
614a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         default:
615a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ShowCommands();
616a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
617a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      } // switch
618a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   } while (goOn);
619a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::MainMenu()
620a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
621a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ShowCommands(void) {
622a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "b\tback up GPT data to a file\n";
623a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "c\tchange a partition's name\n";
624a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "d\tdelete a partition\n";
625a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "i\tshow detailed information on a partition\n";
626a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "l\tlist known partition types\n";
627a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "n\tadd a new partition\n";
628a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "o\tcreate a new empty GUID partition table (GPT)\n";
629a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "p\tprint the partition table\n";
630a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "q\tquit without saving changes\n";
631a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "r\trecovery and transformation options (experts only)\n";
632a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "s\tsort partitions\n";
633a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "t\tchange a partition's type code\n";
634a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "v\tverify disk\n";
635a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "w\twrite table to disk and exit\n";
636a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "x\textra functionality (experts only)\n";
637a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "?\tprint this menu\n";
638a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ShowCommands()
639a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
640a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Accept a recovery & transformation menu command. Returns only when the user
641a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// issues an exit command, such as 'w' or 'q'.
642a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::RecoveryMenu(string filename) {
643a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   uint32_t numParts;
644a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   int goOn = 1, temp1;
645a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
646a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   do {
647a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      cout << "\nRecovery/transformation command (? for help): ";
648a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      switch (ReadString()[0]) {
649a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case '\0':
650a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs            goOn = cin.good();
651a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
652a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'b': case 'B':
653a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            RebuildMainHeader();
654a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
655a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'c': case 'C':
656a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
657a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            << "GPT form and haven't yet saved the GPT! Proceed? ";
658a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (GetYN() == 'Y')
659a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               LoadSecondTableAsMain();
660a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
661a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'd': case 'D':
662a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            RebuildSecondHeader();
663a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
664a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'e': case 'E':
665a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
666a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            << "GPT form and haven't yet saved the GPT! Proceed? ";
667a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (GetYN() == 'Y')
668a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               LoadMainTable();
669a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
670a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'f': case 'F':
671a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Warning! This will destroy the currently defined partitions! Proceed? ";
672a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (GetYN() == 'Y') {
673a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               if (LoadMBR(filename) == 1) { // successful load
674a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs                  XFormPartitions();
675a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               } else {
676a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs                  cout << "Problem loading MBR! GPT is untouched; regenerating protective MBR!\n";
677a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs                  MakeProtectiveMBR();
678a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               } // if/else
679a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if
680a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
681a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'g': case 'G':
682a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            numParts = GetNumParts();
683a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            temp1 = XFormToMBR();
684a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (temp1 > 0)
685a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               cout << "\nConverted " << temp1 << " partitions. Finalize and exit? ";
686a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if ((temp1 > 0) && (GetYN() == 'Y')) {
687a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               if ((DestroyGPT() > 0) && (SaveMBR())) {
688a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs                  goOn = 0;
689a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               } // if
690a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } else {
691a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               MakeProtectiveMBR();
692706e51217a531c46afc743b556e10fd5c0585fcfsrs               SetGPTSize(numParts, 0);
693a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               cout << "Note: New protective MBR created\n\n";
694a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if/else
695a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
696a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'h': case 'H':
697a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            MakeHybrid();
698a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
699a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'i': case 'I':
700a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ShowDetails();
701a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
702a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'l': case 'L':
703a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Enter backup filename to load: ";
704a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            LoadGPTBackup(ReadString());
705a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
706a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'm': case 'M':
707a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            MainMenu(filename);
708a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
709a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
710a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'o': case 'O':
711a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            DisplayMBRData();
712a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
713a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'p': case 'P':
714a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            DisplayGPTData();
715a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
716a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'q': case 'Q':
717a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
718a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
719a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 't': case 'T':
720a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            XFormDisklabel();
721a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
722a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'v': case 'V':
723a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            Verify();
724a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
725a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'w': case 'W':
726a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (SaveGPTData() == 1) {
727a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               goOn = 0;
728a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if
729a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
730a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'x': case 'X':
731a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ExpertsMenu(filename);
732a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
733a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
734a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         default:
735a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ShowRecoveryCommands();
736a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
737a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      } // switch
738a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   } while (goOn);
739a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::RecoveryMenu()
740a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
741a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ShowRecoveryCommands(void) {
742a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "b\tuse backup GPT header (rebuilding main)\n";
743a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "c\tload backup partition table from disk (rebuilding main)\n";
744a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "d\tuse main GPT header (rebuilding backup)\n";
745a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "e\tload main partition table from disk (rebuilding backup)\n";
746a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "f\tload MBR and build fresh GPT from it\n";
747a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "g\tconvert GPT into MBR and exit\n";
748a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "h\tmake hybrid MBR\n";
749a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "i\tshow detailed information on a partition\n";
750a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "l\tload partition data from a backup file\n";
751a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "m\treturn to main menu\n";
752a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "o\tprint protective MBR data\n";
753a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "p\tprint the partition table\n";
754a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "q\tquit without saving changes\n";
755a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "t\ttransform BSD disklabel partition\n";
756a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "v\tverify disk\n";
757a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "w\twrite table to disk and exit\n";
758a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "x\textra functionality (experts only)\n";
759a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "?\tprint this menu\n";
760a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ShowRecoveryCommands()
761a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
762a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Accept an experts' menu command. Returns only after the user
763a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// selects an exit command, such as 'w' or 'q'.
764a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ExpertsMenu(string filename) {
765a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   GPTData secondDevice;
766a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   uint32_t temp1, temp2;
767a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   int goOn = 1;
768a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   string guidStr, device;
769a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   GUIDData aGUID;
770a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   ostringstream prompt;
771a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
772a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   do {
773a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      cout << "\nExpert command (? for help): ";
774a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      switch (ReadString()[0]) {
775a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case '\0':
776a6297b8a2c24adc5aa6dcd03cdc766368cda898dsrs            goOn = cin.good();
777a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
778a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'a': case 'A':
779a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (GetPartRange(&temp1, &temp2) > 0)
780a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               SetAttributes(GetPartNum());
781a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            else
782a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               cout << "No partitions\n";
783a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
784a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'c': case 'C':
785a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ChangeUniqueGuid();
786a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
787a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'd': case 'D':
788a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Partitions will begin on " << GetAlignment()
789a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            << "-sector boundaries.\n";
790a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
791a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'e': case 'E':
792a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Relocating backup data structures to the end of the disk\n";
793a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            MoveSecondHeaderToEnd();
794a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
795a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'f': case 'F':
796a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            RandomizeGUIDs();
797a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
798a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'g': case 'G':
799a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Enter the disk's unique GUID ('R' to randomize): ";
800a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            guidStr = ReadString();
801a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if ((guidStr.length() >= 32) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
802a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               SetDiskGUID((GUIDData) guidStr);
803a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               cout << "The new disk GUID is " << GetDiskGUID() << "\n";
804a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } else {
805a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               cout << "GUID is too short!\n";
806a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if/else
807a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
808a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'h': case 'H':
809a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            RecomputeCHS();
810a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
811a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'i': case 'I':
812a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ShowDetails();
813a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
814a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'l': case 'L':
815a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            prompt.seekp(0);
816a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
817a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs                   << DEFAULT_ALIGNMENT << "): ";
818a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            temp1 = GetNumber(1, MAX_ALIGNMENT, DEFAULT_ALIGNMENT, prompt.str());
819a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            SetAlignment(temp1);
820a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
821a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'm': case 'M':
822a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            MainMenu(filename);
823a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
824a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
825a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'n': case 'N':
826a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            MakeProtectiveMBR();
827a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
828a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'o': case 'O':
829a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            DisplayMBRData();
830a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
831a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'p': case 'P':
832a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            DisplayGPTData();
833a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
834a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'q': case 'Q':
835a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
836a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
837a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'r': case 'R':
838a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            RecoveryMenu(filename);
839a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            goOn = 0;
840a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
841a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 's': case 'S':
842a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ResizePartitionTable();
843a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
844a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 't': case 'T':
845a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            SwapPartitions();
846a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
847a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'u': case 'U':
848a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            cout << "Type device filename, or press <Enter> to exit: ";
849a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            device = ReadString();
850a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (device.length() > 0) {
851a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               secondDevice = *this;
852a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               secondDevice.SetDisk(device);
853a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               secondDevice.SaveGPTData(0);
854a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if
855a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
856a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'v': case 'V':
857a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            Verify();
858a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
859a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'w': case 'W':
860a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (SaveGPTData() == 1) {
861a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               goOn = 0;
862a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            } // if
863a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
864a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         case 'z': case 'Z':
865a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            if (DestroyGPTwPrompt() == 1) {
866a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs               goOn = 0;
867a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            }
868a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
869a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs         default:
870a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            ShowExpertCommands();
871a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs            break;
872a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs      } // switch
873a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   } while (goOn);
874a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ExpertsMenu()
875a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
876a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsvoid GPTDataTextUI::ShowExpertCommands(void) {
877a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "a\tset attributes\n";
878a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "c\tchange partition GUID\n";
879a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "d\tdisplay the sector alignment value\n";
880a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "e\trelocate backup data structures to the end of the disk\n";
881a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "g\tchange disk GUID\n";
882a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "h\trecompute CHS values in protective/hybrid MBR\n";
883a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "i\tshow detailed information on a partition\n";
884a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "l\tset the sector alignment value\n";
885a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "m\treturn to main menu\n";
886a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "n\tcreate a new protective MBR\n";
887a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "o\tprint protective MBR data\n";
888a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "p\tprint the partition table\n";
889a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "q\tquit without saving changes\n";
890a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "r\trecovery and transformation options (experts only)\n";
891a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "s\tresize partition table\n";
892a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "t\ttranspose two partition table entries\n";
89384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith   cout << "u\treplicate partition table on new device\n";
894a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "v\tverify disk\n";
895a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "w\twrite table to disk and exit\n";
896a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "z\tzap (destroy) GPT data structures and exit\n";
897a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs   cout << "?\tprint this menu\n";
898a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs} // GPTDataTextUI::ShowExpertCommands()
899a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
900a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
901a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs
902699941e25a1fcf0beec124203747c8ed20842989srs/********************************
903699941e25a1fcf0beec124203747c8ed20842989srs *                              *
904699941e25a1fcf0beec124203747c8ed20842989srs * Non-class support functions. *
905699941e25a1fcf0beec124203747c8ed20842989srs *                              *
906699941e25a1fcf0beec124203747c8ed20842989srs ********************************/
907699941e25a1fcf0beec124203747c8ed20842989srs
908699941e25a1fcf0beec124203747c8ed20842989srs// GetMBRTypeCode() doesn't really belong in the class, since it's MBR-
909699941e25a1fcf0beec124203747c8ed20842989srs// specific, but it's also user I/O-related, so I want to keep it in
910699941e25a1fcf0beec124203747c8ed20842989srs// this file....
911fad064250bf6c49eb4966bf0f617591a0821808esrs
912fad064250bf6c49eb4966bf0f617591a0821808esrs// Get an MBR type code from the user and return it
913fad064250bf6c49eb4966bf0f617591a0821808esrsint GetMBRTypeCode(int defType) {
9145a6085310b7f8fe1c35e56bcab7de161808b488dsrs   string line;
915fad064250bf6c49eb4966bf0f617591a0821808esrs   int typeCode;
916fad064250bf6c49eb4966bf0f617591a0821808esrs
917fad064250bf6c49eb4966bf0f617591a0821808esrs   cout.setf(ios::uppercase);
918fad064250bf6c49eb4966bf0f617591a0821808esrs   cout.fill('0');
919fad064250bf6c49eb4966bf0f617591a0821808esrs   do {
920fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << "Enter an MBR hex code (default " << hex;
921fad064250bf6c49eb4966bf0f617591a0821808esrs      cout.width(2);
922fad064250bf6c49eb4966bf0f617591a0821808esrs      cout << defType << "): " << dec;
9235a6085310b7f8fe1c35e56bcab7de161808b488dsrs      line = ReadString();
9245a6085310b7f8fe1c35e56bcab7de161808b488dsrs      if (line[0] == '\0')
925fad064250bf6c49eb4966bf0f617591a0821808esrs         typeCode = defType;
926fad064250bf6c49eb4966bf0f617591a0821808esrs      else
9275a6085310b7f8fe1c35e56bcab7de161808b488dsrs         typeCode = StrToHex(line, 0);
928fad064250bf6c49eb4966bf0f617591a0821808esrs   } while ((typeCode <= 0) || (typeCode > 255));
929fad064250bf6c49eb4966bf0f617591a0821808esrs   cout.fill(' ');
930fad064250bf6c49eb4966bf0f617591a0821808esrs   return typeCode;
9311c6f8b013e7f5c166abf21c09e319d22b576c41asrs} // GetMBRTypeCode
932699941e25a1fcf0beec124203747c8ed20842989srs
93384aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#ifdef USE_UTF16
934699941e25a1fcf0beec124203747c8ed20842989srs// Note: ReadUString() is here rather than in support.cc so that the ICU
935699941e25a1fcf0beec124203747c8ed20842989srs// libraries need not be linked to fixparts.
936699941e25a1fcf0beec124203747c8ed20842989srs
937699941e25a1fcf0beec124203747c8ed20842989srs// Reads a Unicode string from stdin, returning it as an ICU-style string.
938699941e25a1fcf0beec124203747c8ed20842989srs// Note that the returned string will NOT include the carriage return
939699941e25a1fcf0beec124203747c8ed20842989srs// entered by the user. Relies on the ICU constructor from a string
940699941e25a1fcf0beec124203747c8ed20842989srs// encoded in the current codepage to work.
941699941e25a1fcf0beec124203747c8ed20842989srsUnicodeString ReadUString(void) {
942699941e25a1fcf0beec124203747c8ed20842989srs   return ReadString().c_str();
943699941e25a1fcf0beec124203747c8ed20842989srs} // ReadUString()
94484aaff6b9cf3b802c621781cf9acd006aa5a3e66Roderick W. Smith#endif
945699941e25a1fcf0beec124203747c8ed20842989srs
946