blob: 2329fac7296fee9fbf152b5619e2a5a0345874f8 [file] [log] [blame]
srs5694e7b4ff92009-08-18 13:16:10 -04001// gdisk.cc
2// Program modelled after Linux fdisk, but it manipulates GPT partitions
3// rather than MBR partitions.
4//
srs5694e4ac11e2009-08-31 10:13:04 -04005// by Rod Smith, project began February 2009
srs5694e7b4ff92009-08-18 13:16:10 -04006
srs56941e093722010-01-05 00:14:19 -05007/* This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
srs5694221e0872009-08-29 15:00:31 -04008 under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
9
srs5694e7b4ff92009-08-18 13:16:10 -040010//#include <iostream>
11#include <stdio.h>
srs5694e7b4ff92009-08-18 13:16:10 -040012#include <getopt.h>
srs5694fed16d02010-01-27 23:03:40 -050013#include <string.h>
14#include <string>
15#include <iostream>
srs5694e7b4ff92009-08-18 13:16:10 -040016#include "mbr.h"
17#include "gpt.h"
18#include "support.h"
19
20// Function prototypes....
srs5694fed16d02010-01-27 23:03:40 -050021void MainMenu(string filename, struct GPTData* theGPT);
srs5694e7b4ff92009-08-18 13:16:10 -040022void ShowCommands(void);
srs5694fed16d02010-01-27 23:03:40 -050023void ExpertsMenu(string filename, struct GPTData* theGPT);
srs5694e7b4ff92009-08-18 13:16:10 -040024void ShowExpertCommands(void);
srs5694fed16d02010-01-27 23:03:40 -050025void RecoveryMenu(string filename, struct GPTData* theGPT);
srs5694978041c2009-09-21 20:51:47 -040026void ShowRecoveryCommands(void);
srs5694e7b4ff92009-08-18 13:16:10 -040027
28int main(int argc, char* argv[]) {
29 GPTData theGPT;
30 int doMore = 1;
31 char* device = NULL;
32
srs5694fed16d02010-01-27 23:03:40 -050033 cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
srs5694e7b4ff92009-08-18 13:16:10 -040034
35 if (argc == 2) { // basic usage
36 if (SizesOK()) {
37 doMore = theGPT.LoadPartitions(argv[1]);
srs5694978041c2009-09-21 20:51:47 -040038 if (doMore) {
39 MainMenu(argv[1], &theGPT);
40 } // if (doMore)
41 } // if (SizesOK())
srs5694e7b4ff92009-08-18 13:16:10 -040042 } else if (argc == 3) { // usage with "-l" option
43 if (SizesOK()) {
44 if (strcmp(argv[1], "-l") == 0) {
45 device = argv[2];
46 } else if (strcmp(argv[2], "-l") == 0) {
47 device = argv[1];
48 } else { // 3 arguments, but none is "-l"
srs5694fed16d02010-01-27 23:03:40 -050049 cerr << "Usage: " << argv[0] << " [-l] device_file\n";
srs5694e7b4ff92009-08-18 13:16:10 -040050 } // if/elseif/else
51 if (device != NULL) {
srs56945d58fe02010-01-03 20:57:08 -050052 theGPT.JustLooking();
srs5694fed16d02010-01-27 23:03:40 -050053 doMore = theGPT.LoadPartitions((string) device);
srs5694e7b4ff92009-08-18 13:16:10 -040054 if (doMore) theGPT.DisplayGPTData();
55 } // if
56 } // if
57 } else {
srs5694fed16d02010-01-27 23:03:40 -050058 cerr << "Usage: " << argv[0] << " [-l] device_file\n";
srs5694e7b4ff92009-08-18 13:16:10 -040059 } // if/else
60} // main
61
srs5694978041c2009-09-21 20:51:47 -040062// Accept a command and execute it. Returns only when the user
63// wants to exit (such as after a 'w' or 'q' command).
srs5694fed16d02010-01-27 23:03:40 -050064void MainMenu(string filename, struct GPTData* theGPT) {
srs5694978041c2009-09-21 20:51:47 -040065 char command, line[255], buFile[255];
srs56945d58fe02010-01-03 20:57:08 -050066 char* junk;
srs5694978041c2009-09-21 20:51:47 -040067 int goOn = 1;
srs5694e7b4ff92009-08-18 13:16:10 -040068 PartTypes typeHelper;
69 uint32_t temp1, temp2;
70
srs5694978041c2009-09-21 20:51:47 -040071 do {
srs5694fed16d02010-01-27 23:03:40 -050072 cout << "\nCommand (? for help): ";
srs56945d58fe02010-01-03 20:57:08 -050073 junk = fgets(line, 255, stdin);
srs5694978041c2009-09-21 20:51:47 -040074 sscanf(line, "%c", &command);
75 switch (command) {
srs5694fed16d02010-01-27 23:03:40 -050076 case '\n':
77 break;
srs5694978041c2009-09-21 20:51:47 -040078 case 'b': case 'B':
srs5694fed16d02010-01-27 23:03:40 -050079 cout << "Enter backup filename to save: ";
srs56945d58fe02010-01-03 20:57:08 -050080 junk = fgets(line, 255, stdin);
81 sscanf(line, "%s", (char*) &buFile);
srs5694978041c2009-09-21 20:51:47 -040082 theGPT->SaveGPTBackup(buFile);
83 break;
84 case 'c': case 'C':
85 if (theGPT->GetPartRange(&temp1, &temp2) > 0)
86 theGPT->SetName(theGPT->GetPartNum());
87 else
srs5694fed16d02010-01-27 23:03:40 -050088 cout << "No partitions\n";
srs5694978041c2009-09-21 20:51:47 -040089 break;
90 case 'd': case 'D':
91 theGPT->DeletePartition();
92 break;
93 case 'i': case 'I':
94 theGPT->ShowDetails();
95 break;
96 case 'l': case 'L':
97 typeHelper.ShowTypes();
98 break;
99 case 'n': case 'N':
100 theGPT->CreatePartition();
101 break;
102 case 'o': case 'O':
srs5694fed16d02010-01-27 23:03:40 -0500103 cout << "This option deletes all partitions and creates a new protective MBR.\n"
104 << "Proceed? ";
srs5694978041c2009-09-21 20:51:47 -0400105 if (GetYN() == 'Y') {
106 theGPT->ClearGPTData();
107 theGPT->MakeProtectiveMBR();
108 } // if
109 break;
110 case 'p': case 'P':
111 theGPT->DisplayGPTData();
112 break;
113 case 'q': case 'Q':
114 goOn = 0;
115 break;
116 case 'r': case 'R':
117 RecoveryMenu(filename, theGPT);
118 goOn = 0;
119 break;
120 case 's': case 'S':
121 theGPT->SortGPT();
srs5694fed16d02010-01-27 23:03:40 -0500122 cout << "You may need to edit /etc/fstab and/or your boot loader configuration!\n";
srs5694978041c2009-09-21 20:51:47 -0400123 break;
124 case 't': case 'T':
125 theGPT->ChangePartType();
126 break;
127 case 'v': case 'V':
srs5694546a9c72010-01-26 16:00:26 -0500128 theGPT->Verify();
srs5694978041c2009-09-21 20:51:47 -0400129 break;
130 case 'w': case 'W':
131 if (theGPT->SaveGPTData() == 1)
132 goOn = 0;
133 break;
134 case 'x': case 'X':
135 ExpertsMenu(filename, theGPT);
136 goOn = 0;
137 break;
138 default:
139 ShowCommands();
140 break;
141 } // switch
142 } while (goOn);
143} // MainMenu()
srs5694e7b4ff92009-08-18 13:16:10 -0400144
145void ShowCommands(void) {
srs5694fed16d02010-01-27 23:03:40 -0500146 cout << "b\tback up GPT data to a file\n";
147 cout << "c\tchange a partition's name\n";
148 cout << "d\tdelete a partition\n";
149 cout << "i\tshow detailed information on a partition\n";
150 cout << "l\tlist known partition types\n";
151 cout << "n\tadd a new partition\n";
152 cout << "o\tcreate a new empty GUID partition table (GPT)\n";
153 cout << "p\tprint the partition table\n";
154 cout << "q\tquit without saving changes\n";
155 cout << "r\trecovery and transformation options (experts only)\n";
156 cout << "s\tsort partitions\n";
157 cout << "t\tchange a partition's type code\n";
158 cout << "v\tverify disk\n";
159 cout << "w\twrite table to disk and exit\n";
160 cout << "x\textra functionality (experts only)\n";
161 cout << "?\tprint this menu\n";
srs5694e7b4ff92009-08-18 13:16:10 -0400162} // ShowCommands()
163
srs5694978041c2009-09-21 20:51:47 -0400164// Accept a recovery & transformation menu command. Returns only when the user
165// issues an exit command, such as 'w' or 'q'.
srs5694fed16d02010-01-27 23:03:40 -0500166void RecoveryMenu(string filename, struct GPTData* theGPT) {
srs5694e7b4ff92009-08-18 13:16:10 -0400167 char command, line[255], buFile[255];
srs56945d58fe02010-01-03 20:57:08 -0500168 char* junk;
srs5694978041c2009-09-21 20:51:47 -0400169 PartTypes typeHelper;
170 uint32_t temp1;
171 int goOn = 1;
172
173 do {
srs5694fed16d02010-01-27 23:03:40 -0500174 cout << "\nRecovery/transformation command (? for help): ";
srs56945d58fe02010-01-03 20:57:08 -0500175 junk = fgets(line, 255, stdin);
srs5694978041c2009-09-21 20:51:47 -0400176 sscanf(line, "%c", &command);
177 switch (command) {
srs5694fed16d02010-01-27 23:03:40 -0500178 case '\n':
179 break;
srs5694978041c2009-09-21 20:51:47 -0400180 case 'b': case 'B':
181 theGPT->RebuildMainHeader();
182 break;
183 case 'c': case 'C':
srs5694fed16d02010-01-27 23:03:40 -0500184 cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
185 << "GPT form and haven't yet saved the GPT! Proceed? ";
srs5694978041c2009-09-21 20:51:47 -0400186 if (GetYN() == 'Y')
187 theGPT->LoadSecondTableAsMain();
188 break;
189 case 'd': case 'D':
190 theGPT->RebuildSecondHeader();
191 break;
192 case 'e': case 'E':
srs5694fed16d02010-01-27 23:03:40 -0500193 cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
194 << "GPT form and haven't yet saved the GPT! Proceed? ";
srs5694978041c2009-09-21 20:51:47 -0400195 if (GetYN() == 'Y')
196 theGPT->LoadMainTable();
197 break;
198 case 'f': case 'F':
srs5694fed16d02010-01-27 23:03:40 -0500199 cout << "Warning! This will destroy the currently defined partitions! Proceed? ";
srs5694978041c2009-09-21 20:51:47 -0400200 if (GetYN() == 'Y') {
201 if (theGPT->LoadMBR(filename) == 1) { // successful load
202 theGPT->XFormPartitions();
203 } else {
srs5694fed16d02010-01-27 23:03:40 -0500204 cout << "Problem loading MBR! GPT is untouched; regenerating protective MBR!\n";
srs5694978041c2009-09-21 20:51:47 -0400205 theGPT->MakeProtectiveMBR();
206 } // if/else
207 } // if
208 break;
209 case 'g': case 'G':
210 temp1 = theGPT->XFormToMBR();
211 if (temp1 > 0) {
srs5694fed16d02010-01-27 23:03:40 -0500212 cout << "Converted " << temp1 << " partitions. Finalize and exit? ";
srs5694978041c2009-09-21 20:51:47 -0400213 if (GetYN() == 'Y') {
214 if (theGPT->DestroyGPT(0) > 0)
215 goOn = 0;
216 } else {
217 theGPT->MakeProtectiveMBR();
srs5694fed16d02010-01-27 23:03:40 -0500218 cout << "Note: New protective MBR created.\n";
srs5694978041c2009-09-21 20:51:47 -0400219 } // if/else
220 } // if
221 break;
222 case 'h': case 'H':
223 theGPT->MakeHybrid();
224 break;
225 case 'i': case 'I':
226 theGPT->ShowDetails();
227 break;
228 case 'l': case 'L':
srs5694fed16d02010-01-27 23:03:40 -0500229 cout << "Enter backup filename to load: ";
srs56945d58fe02010-01-03 20:57:08 -0500230 junk = fgets(line, 255, stdin);
231 sscanf(line, "%s", (char*) &buFile);
srs5694978041c2009-09-21 20:51:47 -0400232 theGPT->LoadGPTBackup(buFile);
233 break;
234 case 'm': case 'M':
235 MainMenu(filename, theGPT);
236 goOn = 0;
237 break;
238 case 'o': case 'O':
239 theGPT->DisplayMBRData();
240 break;
241 case 'p': case 'P':
242 theGPT->DisplayGPTData();
243 break;
244 case 'q': case 'Q':
245 goOn = 0;
246 break;
247 case 't': case 'T':
248 theGPT->XFormDisklabel();
249 break;
250 case 'v': case 'V':
251 theGPT->Verify();
252 break;
253 case 'w': case 'W':
254 if (theGPT->SaveGPTData() == 1) {
255 goOn = 0;
256 } // if
257 break;
258 case 'x': case 'X':
259 ExpertsMenu(filename, theGPT);
260 goOn = 0;
261 break;
262 default:
263 ShowRecoveryCommands();
264 break;
265 } // switch
266 } while (goOn);
267} // RecoveryMenu()
268
269void ShowRecoveryCommands(void) {
srs5694fed16d02010-01-27 23:03:40 -0500270 cout << "b\tuse backup GPT header (rebuilding main)\n";
271 cout << "c\tload backup partition table from disk (rebuilding main)\n";
272 cout << "d\tuse main GPT header (rebuilding backup)\n";
273 cout << "e\tload main partition table from disk (rebuilding backup)\n";
274 cout << "f\tload MBR and build fresh GPT from it\n";
275 cout << "g\tconvert GPT into MBR and exit\n";
276 cout << "h\tmake hybrid MBR\n";
277 cout << "i\tshow detailed information on a partition\n";
278 cout << "l\tload partition data from a backup file\n";
279 cout << "m\treturn to main menu\n";
280 cout << "o\tprint protective MBR data\n";
281 cout << "p\tprint the partition table\n";
282 cout << "q\tquit without saving changes\n";
283 cout << "t\ttransform BSD disklabel partition\n";
284 cout << "v\tverify disk\n";
285 cout << "w\twrite table to disk and exit\n";
286 cout << "x\textra functionality (experts only)\n";
287 cout << "?\tprint this menu\n";
srs5694978041c2009-09-21 20:51:47 -0400288} // ShowRecoveryCommands()
289
290// Accept an experts' menu command. Returns only after the user
291// selects an exit command, such as 'w' or 'q'.
srs5694fed16d02010-01-27 23:03:40 -0500292void ExpertsMenu(string filename, struct GPTData* theGPT) {
srs5694978041c2009-09-21 20:51:47 -0400293 char command, line[255];
srs56945d58fe02010-01-03 20:57:08 -0500294 char* junk;
srs5694e7b4ff92009-08-18 13:16:10 -0400295 PartTypes typeHelper;
296 uint32_t pn;
297 uint32_t temp1, temp2;
298 int goOn = 1;
299
300 do {
srs5694fed16d02010-01-27 23:03:40 -0500301 cout << "\nExpert command (? for help): ";
srs56945d58fe02010-01-03 20:57:08 -0500302 junk = fgets(line, 255, stdin);
srs5694e7b4ff92009-08-18 13:16:10 -0400303 sscanf(line, "%c", &command);
304 switch (command) {
srs5694fed16d02010-01-27 23:03:40 -0500305 case '\n':
306 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400307 case 'a': case 'A':
308 if (theGPT->GetPartRange(&temp1, &temp2) > 0)
309 theGPT->SetAttributes(theGPT->GetPartNum());
310 else
srs5694fed16d02010-01-27 23:03:40 -0500311 cout << "No partitions\n";
srs5694e7b4ff92009-08-18 13:16:10 -0400312 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400313 case 'c': case 'C':
srs5694e7b4ff92009-08-18 13:16:10 -0400314 if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
315 pn = theGPT->GetPartNum();
srs5694fed16d02010-01-27 23:03:40 -0500316 cout << "Enter the partition's new unique GUID:\n";
srs5694e7b4ff92009-08-18 13:16:10 -0400317 theGPT->SetPartitionGUID(pn, GetGUID());
srs5694fed16d02010-01-27 23:03:40 -0500318 } else cout << "No partitions\n";
srs5694e7b4ff92009-08-18 13:16:10 -0400319 break;
srs56941d1448a2009-12-31 21:20:19 -0500320 case 'd': case 'D':
srs5694fed16d02010-01-27 23:03:40 -0500321 cout << "Partitions will begin on " << theGPT->GetAlignment()
322 << "-sector boundaries.\n";
srs56941d1448a2009-12-31 21:20:19 -0500323 break;
srs56948bb78762009-11-24 15:43:49 -0500324 case 'e': case 'E':
srs5694fed16d02010-01-27 23:03:40 -0500325 cout << "Relocating backup data structures to the end of the disk\n";
srs5694247657a2009-11-26 18:36:12 -0500326 theGPT->MoveSecondHeaderToEnd();
srs56948bb78762009-11-24 15:43:49 -0500327 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400328 case 'g': case 'G':
srs5694fed16d02010-01-27 23:03:40 -0500329 cout << "Enter the disk's unique GUID:\n";
srs5694e7b4ff92009-08-18 13:16:10 -0400330 theGPT->SetDiskGUID(GetGUID());
331 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400332 case 'i': case 'I':
333 theGPT->ShowDetails();
334 break;
srs56941d1448a2009-12-31 21:20:19 -0500335 case 'l': case 'L':
srs5694fed16d02010-01-27 23:03:40 -0500336 temp1 = GetNumber(1, 128, 8, (string)
337 "Enter the sector alignment value (1-128, default = 8): ");
srs56941d1448a2009-12-31 21:20:19 -0500338 theGPT->SetAlignment(temp1);
339 break;
srs5694978041c2009-09-21 20:51:47 -0400340 case 'm': case 'M':
341 MainMenu(filename, theGPT);
342 goOn = 0;
srs5694e7b4ff92009-08-18 13:16:10 -0400343 break;
344 case 'n': case 'N':
345 theGPT->MakeProtectiveMBR();
346 break;
347 case 'o': case 'O':
348 theGPT->DisplayMBRData();
349 break;
350 case 'p': case 'P':
351 theGPT->DisplayGPTData();
352 break;
353 case 'q': case 'Q':
srs5694e7b4ff92009-08-18 13:16:10 -0400354 goOn = 0;
355 break;
356 case 'r': case 'R':
srs5694978041c2009-09-21 20:51:47 -0400357 RecoveryMenu(filename, theGPT);
srs5694e7b4ff92009-08-18 13:16:10 -0400358 goOn = 0;
359 break;
360 case 's': case 'S':
361 theGPT->ResizePartitionTable();
362 break;
363 case 'v': case 'V':
364 theGPT->Verify();
365 break;
366 case 'w': case 'W':
367 if (theGPT->SaveGPTData() == 1) {
srs5694e7b4ff92009-08-18 13:16:10 -0400368 goOn = 0;
369 } // if
370 break;
srs5694c0ca8f82009-08-20 21:35:25 -0400371 case 'z': case 'Z':
372 if (theGPT->DestroyGPT() == 1) {
srs5694978041c2009-09-21 20:51:47 -0400373 goOn = 0;
srs5694c0ca8f82009-08-20 21:35:25 -0400374 }
375 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400376 default:
377 ShowExpertCommands();
378 break;
379 } // switch
380 } while (goOn);
srs5694e7b4ff92009-08-18 13:16:10 -0400381} // ExpertsMenu()
382
383void ShowExpertCommands(void) {
srs5694fed16d02010-01-27 23:03:40 -0500384 cout << "a\tset attributes\n";
385 cout << "c\tchange partition GUID\n";
386 cout << "d\tdisplay the sector alignment value\n";
387 cout << "e\trelocate backup data structures to the end of the disk\n";
388 cout << "g\tchange disk GUID\n";
389 cout << "i\tshow detailed information on a partition\n";
390 cout << "l\tset the sector alignment value\n";
391 cout << "m\treturn to main menu\n";
392 cout << "n\tcreate a new protective MBR\n";
393 cout << "o\tprint protective MBR data\n";
394 cout << "p\tprint the partition table\n";
395 cout << "q\tquit without saving changes\n";
396 cout << "r\trecovery and transformation options (experts only)\n";
397 cout << "s\tresize partition table\n";
398 cout << "v\tverify disk\n";
399 cout << "w\twrite table to disk and exit\n";
400 cout << "z\tzap (destroy) GPT data structures and exit\n";
401 cout << "?\tprint this menu\n";
srs5694e7b4ff92009-08-18 13:16:10 -0400402} // ShowExpertCommands()