blob: f11207ee637eaa9024f5efe63c7cd5567e574eec [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
srs5694221e0872009-08-29 15:00:31 -04007/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
8 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>
12#include <string.h>
13#include <getopt.h>
14#include "mbr.h"
15#include "gpt.h"
16#include "support.h"
17
18// Function prototypes....
19// int ReadPartitions(char* filename, struct GPTData* theGPT);
srs5694978041c2009-09-21 20:51:47 -040020void MainMenu(char* filename, struct GPTData* theGPT);
srs5694e7b4ff92009-08-18 13:16:10 -040021void ShowCommands(void);
srs5694978041c2009-09-21 20:51:47 -040022void ExpertsMenu(char* filename, struct GPTData* theGPT);
srs5694e7b4ff92009-08-18 13:16:10 -040023void ShowExpertCommands(void);
srs5694978041c2009-09-21 20:51:47 -040024void RecoveryMenu(char* filename, struct GPTData* theGPT);
25void ShowRecoveryCommands(void);
srs5694e7b4ff92009-08-18 13:16:10 -040026
27int main(int argc, char* argv[]) {
28 GPTData theGPT;
29 int doMore = 1;
30 char* device = NULL;
31
srs56945d58fe02010-01-03 20:57:08 -050032 printf("GPT fdisk (gdisk) version 0.5.3\n\n");
srs5694e7b4ff92009-08-18 13:16:10 -040033
34 if (argc == 2) { // basic usage
35 if (SizesOK()) {
36 doMore = theGPT.LoadPartitions(argv[1]);
srs5694978041c2009-09-21 20:51:47 -040037 if (doMore) {
38 MainMenu(argv[1], &theGPT);
39 } // if (doMore)
40 } // if (SizesOK())
srs5694e7b4ff92009-08-18 13:16:10 -040041 } else if (argc == 3) { // usage with "-l" option
42 if (SizesOK()) {
43 if (strcmp(argv[1], "-l") == 0) {
44 device = argv[2];
45 } else if (strcmp(argv[2], "-l") == 0) {
46 device = argv[1];
47 } else { // 3 arguments, but none is "-l"
48 fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
49 } // if/elseif/else
50 if (device != NULL) {
srs56945d58fe02010-01-03 20:57:08 -050051 theGPT.JustLooking();
srs5694e7b4ff92009-08-18 13:16:10 -040052 doMore = theGPT.LoadPartitions(device);
53 if (doMore) theGPT.DisplayGPTData();
54 } // if
55 } // if
56 } else {
57 fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
58 } // if/else
59} // main
60
srs5694978041c2009-09-21 20:51:47 -040061// Accept a command and execute it. Returns only when the user
62// wants to exit (such as after a 'w' or 'q' command).
63void MainMenu(char* filename, struct GPTData* theGPT) {
64 char command, line[255], buFile[255];
srs56945d58fe02010-01-03 20:57:08 -050065 char* junk;
srs5694978041c2009-09-21 20:51:47 -040066 int goOn = 1;
srs5694e7b4ff92009-08-18 13:16:10 -040067 PartTypes typeHelper;
68 uint32_t temp1, temp2;
69
srs5694978041c2009-09-21 20:51:47 -040070 do {
71 printf("\nCommand (? for help): ");
srs56945d58fe02010-01-03 20:57:08 -050072 junk = fgets(line, 255, stdin);
srs5694978041c2009-09-21 20:51:47 -040073 sscanf(line, "%c", &command);
74 switch (command) {
75 case 'b': case 'B':
76 printf("Enter backup filename to save: ");
srs56945d58fe02010-01-03 20:57:08 -050077 junk = fgets(line, 255, stdin);
78 sscanf(line, "%s", (char*) &buFile);
srs5694978041c2009-09-21 20:51:47 -040079 theGPT->SaveGPTBackup(buFile);
80 break;
81 case 'c': case 'C':
82 if (theGPT->GetPartRange(&temp1, &temp2) > 0)
83 theGPT->SetName(theGPT->GetPartNum());
84 else
85 printf("No partitions\n");
86 break;
87 case 'd': case 'D':
88 theGPT->DeletePartition();
89 break;
90 case 'i': case 'I':
91 theGPT->ShowDetails();
92 break;
93 case 'l': case 'L':
94 typeHelper.ShowTypes();
95 break;
96 case 'n': case 'N':
97 theGPT->CreatePartition();
98 break;
99 case 'o': case 'O':
100 printf("This option deletes all partitions and creates a new "
101 "protective MBR.\nProceed? ");
102 if (GetYN() == 'Y') {
103 theGPT->ClearGPTData();
104 theGPT->MakeProtectiveMBR();
105 } // if
106 break;
107 case 'p': case 'P':
108 theGPT->DisplayGPTData();
109 break;
110 case 'q': case 'Q':
111 goOn = 0;
112 break;
113 case 'r': case 'R':
114 RecoveryMenu(filename, theGPT);
115 goOn = 0;
116 break;
117 case 's': case 'S':
118 theGPT->SortGPT();
119 printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
120 break;
121 case 't': case 'T':
122 theGPT->ChangePartType();
123 break;
124 case 'v': case 'V':
125 if (theGPT->Verify() > 0) { // problems found
126 printf("You may be able to correct the problems by using options on the experts\n"
127 "menu (press 'x' at the command prompt). Good luck!\n");
128 } // if
129 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) {
srs5694978041c2009-09-21 20:51:47 -0400146 printf("b\tback up GPT data to a file\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400147 printf("c\tchange a partition's name\n");
148 printf("d\tdelete a partition\n");
149 printf("i\tshow detailed information on a partition\n");
srs5694978041c2009-09-21 20:51:47 -0400150 printf("l\tlist known partition types\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400151 printf("n\tadd a new partition\n");
152 printf("o\tcreate a new empty GUID partition table (GPT)\n");
153 printf("p\tprint the partition table\n");
154 printf("q\tquit without saving changes\n");
srs5694978041c2009-09-21 20:51:47 -0400155 printf("r\trecovery and transformation options (experts only)\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400156 printf("s\tsort partitions\n");
157 printf("t\tchange a partition's type code\n");
158 printf("v\tverify disk\n");
159 printf("w\twrite table to disk and exit\n");
160 printf("x\textra functionality (experts only)\n");
srs5694978041c2009-09-21 20:51:47 -0400161 printf("?\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'.
166void RecoveryMenu(char* 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 {
174 printf("\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) {
178 case 'b': case 'B':
179 theGPT->RebuildMainHeader();
180 break;
181 case 'c': case 'C':
182 printf("Warning! This will probably do weird things if you've converted an MBR to\n"
183 "GPT form and haven't yet saved the GPT! Proceed? ");
184 if (GetYN() == 'Y')
185 theGPT->LoadSecondTableAsMain();
186 break;
187 case 'd': case 'D':
188 theGPT->RebuildSecondHeader();
189 break;
190 case 'e': case 'E':
191 printf("Warning! This will probably do weird things if you've converted an MBR to\n"
192 "GPT form and haven't yet saved the GPT! Proceed? ");
193 if (GetYN() == 'Y')
194 theGPT->LoadMainTable();
195 break;
196 case 'f': case 'F':
197 printf("Warning! This will destroy the currently defined partitions! Proceed? ");
198 if (GetYN() == 'Y') {
199 if (theGPT->LoadMBR(filename) == 1) { // successful load
200 theGPT->XFormPartitions();
201 } else {
202 printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
203 theGPT->MakeProtectiveMBR();
204 } // if/else
205 } // if
206 break;
207 case 'g': case 'G':
208 temp1 = theGPT->XFormToMBR();
209 if (temp1 > 0) {
210 printf("Converted %d partitions. Finalize and exit? ", temp1);
211 if (GetYN() == 'Y') {
212 if (theGPT->DestroyGPT(0) > 0)
213 goOn = 0;
214 } else {
215 theGPT->MakeProtectiveMBR();
216 printf("Note: New protective MBR created.\n");
217 } // if/else
218 } // if
219 break;
220 case 'h': case 'H':
221 theGPT->MakeHybrid();
222 break;
223 case 'i': case 'I':
224 theGPT->ShowDetails();
225 break;
226 case 'l': case 'L':
227 printf("Enter backup filename to load: ");
srs56945d58fe02010-01-03 20:57:08 -0500228 junk = fgets(line, 255, stdin);
229 sscanf(line, "%s", (char*) &buFile);
srs5694978041c2009-09-21 20:51:47 -0400230 theGPT->LoadGPTBackup(buFile);
231 break;
232 case 'm': case 'M':
233 MainMenu(filename, theGPT);
234 goOn = 0;
235 break;
236 case 'o': case 'O':
237 theGPT->DisplayMBRData();
238 break;
239 case 'p': case 'P':
240 theGPT->DisplayGPTData();
241 break;
242 case 'q': case 'Q':
243 goOn = 0;
244 break;
245 case 't': case 'T':
246 theGPT->XFormDisklabel();
247 break;
248 case 'v': case 'V':
249 theGPT->Verify();
250 break;
251 case 'w': case 'W':
252 if (theGPT->SaveGPTData() == 1) {
253 goOn = 0;
254 } // if
255 break;
256 case 'x': case 'X':
257 ExpertsMenu(filename, theGPT);
258 goOn = 0;
259 break;
260 default:
261 ShowRecoveryCommands();
262 break;
263 } // switch
264 } while (goOn);
265} // RecoveryMenu()
266
267void ShowRecoveryCommands(void) {
268 printf("b\tuse backup GPT header (rebuilding main)\n");
269 printf("c\tload backup partition table from disk (rebuilding main)\n");
270 printf("d\tuse main GPT header (rebuilding backup)\n");
271 printf("e\tload main partition table from disk (rebuilding backup)\n");
272 printf("f\tload MBR and build fresh GPT from it\n");
273 printf("g\tconvert GPT into MBR and exit\n");
274 printf("h\tmake hybrid MBR\n");
275 printf("i\tshow detailed information on a partition\n");
276 printf("l\tload partition data from a backup file\n");
277 printf("m\treturn to main menu\n");
278 printf("o\tprint protective MBR data\n");
279 printf("p\tprint the partition table\n");
280 printf("q\tquit without saving changes\n");
281 printf("t\ttransform BSD disklabel partition\n");
282 printf("v\tverify disk\n");
283 printf("w\twrite table to disk and exit\n");
284 printf("x\textra functionality (experts only)\n");
285 printf("?\tprint this menu\n");
286} // ShowRecoveryCommands()
287
288// Accept an experts' menu command. Returns only after the user
289// selects an exit command, such as 'w' or 'q'.
290void ExpertsMenu(char* filename, struct GPTData* theGPT) {
291 char command, line[255];
srs56945d58fe02010-01-03 20:57:08 -0500292 char* junk;
srs5694e7b4ff92009-08-18 13:16:10 -0400293 PartTypes typeHelper;
294 uint32_t pn;
295 uint32_t temp1, temp2;
296 int goOn = 1;
297
298 do {
srs5694978041c2009-09-21 20:51:47 -0400299 printf("\nExpert command (? for help): ");
srs56945d58fe02010-01-03 20:57:08 -0500300 junk = fgets(line, 255, stdin);
srs5694e7b4ff92009-08-18 13:16:10 -0400301 sscanf(line, "%c", &command);
302 switch (command) {
303 case 'a': case 'A':
304 if (theGPT->GetPartRange(&temp1, &temp2) > 0)
305 theGPT->SetAttributes(theGPT->GetPartNum());
306 else
307 printf("No partitions\n");
308 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400309 case 'c': case 'C':
srs5694e7b4ff92009-08-18 13:16:10 -0400310 if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
311 pn = theGPT->GetPartNum();
312 printf("Enter the partition's new unique GUID:\n");
313 theGPT->SetPartitionGUID(pn, GetGUID());
314 } else printf("No partitions\n");
315 break;
srs56941d1448a2009-12-31 21:20:19 -0500316 case 'd': case 'D':
srs56945d58fe02010-01-03 20:57:08 -0500317 printf("The number of logical sectors per physical sector is %d.\n",
srs56941d1448a2009-12-31 21:20:19 -0500318 theGPT->GetAlignment());
319 break;
srs56948bb78762009-11-24 15:43:49 -0500320 case 'e': case 'E':
321 printf("Relocating backup data structures to the end of the disk\n");
srs5694247657a2009-11-26 18:36:12 -0500322 theGPT->MoveSecondHeaderToEnd();
srs56948bb78762009-11-24 15:43:49 -0500323 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400324 case 'g': case 'G':
325 printf("Enter the disk's unique GUID:\n");
326 theGPT->SetDiskGUID(GetGUID());
327 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400328 case 'i': case 'I':
329 theGPT->ShowDetails();
330 break;
srs56941d1448a2009-12-31 21:20:19 -0500331 case 'l': case 'L':
332 temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
333 theGPT->SetAlignment(temp1);
334 break;
srs5694978041c2009-09-21 20:51:47 -0400335 case 'm': case 'M':
336 MainMenu(filename, theGPT);
337 goOn = 0;
srs5694e7b4ff92009-08-18 13:16:10 -0400338 break;
339 case 'n': case 'N':
340 theGPT->MakeProtectiveMBR();
341 break;
342 case 'o': case 'O':
343 theGPT->DisplayMBRData();
344 break;
345 case 'p': case 'P':
346 theGPT->DisplayGPTData();
347 break;
348 case 'q': case 'Q':
srs5694e7b4ff92009-08-18 13:16:10 -0400349 goOn = 0;
350 break;
351 case 'r': case 'R':
srs5694978041c2009-09-21 20:51:47 -0400352 RecoveryMenu(filename, theGPT);
srs5694e7b4ff92009-08-18 13:16:10 -0400353 goOn = 0;
354 break;
355 case 's': case 'S':
356 theGPT->ResizePartitionTable();
357 break;
358 case 'v': case 'V':
359 theGPT->Verify();
360 break;
361 case 'w': case 'W':
362 if (theGPT->SaveGPTData() == 1) {
srs5694e7b4ff92009-08-18 13:16:10 -0400363 goOn = 0;
364 } // if
365 break;
srs5694c0ca8f82009-08-20 21:35:25 -0400366 case 'z': case 'Z':
367 if (theGPT->DestroyGPT() == 1) {
srs5694978041c2009-09-21 20:51:47 -0400368 goOn = 0;
srs5694c0ca8f82009-08-20 21:35:25 -0400369 }
370 break;
srs5694e7b4ff92009-08-18 13:16:10 -0400371 default:
372 ShowExpertCommands();
373 break;
374 } // switch
375 } while (goOn);
srs5694e7b4ff92009-08-18 13:16:10 -0400376} // ExpertsMenu()
377
378void ShowExpertCommands(void) {
379 printf("a\tset attributes\n");
srs5694978041c2009-09-21 20:51:47 -0400380 printf("c\tchange partition GUID\n");
srs56941d1448a2009-12-31 21:20:19 -0500381 printf("d\tdisplay the number of logical sectors per physical sector\n");
srs56943f2fe992009-11-24 18:28:18 -0500382 printf("e\trelocate backup data structures to the end of the disk\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400383 printf("g\tchange disk GUID\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400384 printf("i\tshow detailed information on a partition\n");
srs56941d1448a2009-12-31 21:20:19 -0500385 printf("b\tset the number of logical sectors per physical sector\n");
srs5694978041c2009-09-21 20:51:47 -0400386 printf("m\treturn to main menu\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400387 printf("n\tcreate a new protective MBR\n");
388 printf("o\tprint protective MBR data\n");
389 printf("p\tprint the partition table\n");
390 printf("q\tquit without saving changes\n");
srs5694978041c2009-09-21 20:51:47 -0400391 printf("r\trecovery and transformation options (experts only)\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400392 printf("s\tresize partition table\n");
393 printf("v\tverify disk\n");
394 printf("w\twrite table to disk and exit\n");
srs5694978041c2009-09-21 20:51:47 -0400395 printf("z\tzap (destroy) GPT data structures and exit\n");
396 printf("?\tprint this menu\n");
srs5694e7b4ff92009-08-18 13:16:10 -0400397} // ShowExpertCommands()