blob: 9479afb4fcd5c1a90e1fe70299cc23d874b52735 [file] [log] [blame]
srs56941e093722010-01-05 00:14:19 -05001// sgdisk.cc
2// Program modelled after Linux sfdisk, but it manipulates GPT partitions
3// rather than MBR partitions. This is effectively a new user interface
4// to my gdisk program.
5//
6// by Rod Smith, project began February 2009
7
8/* This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
9 under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
10
11//#include <iostream>
12#include <stdio.h>
13#include <string.h>
14#include <getopt.h>
15#include "mbr.h"
16#include "gpt.h"
17#include "support.h"
18
19#define MAX_OPTIONS 50
20
21// Function prototypes....
22/* void MainMenu(char* filename, struct GPTData* theGPT);
23void ShowCommands(void);
24void ExpertsMenu(char* filename, struct GPTData* theGPT);
25void ShowExpertCommands(void);
26void RecoveryMenu(char* filename, struct GPTData* theGPT);
27void ShowRecoveryCommands(void); */
28
29enum Commands { NONE, LIST, VERIFY };
30
31struct Options {
32 Commands theCommand;
33 char* theArgument;
34}; // struct Options
35
36int verbose_flag;
37
38static struct option long_options[] =
39{
40 {"verify", no_argument, NULL, 'v'},
41 {"list", no_argument, NULL, 'l'},
42 {0, 0, NULL, 0}
43};
44
45int ParseOptions(int argc, char* argv[], Options* theOptions, char** device);
46
47int main(int argc, char* argv[]) {
48 GPTData theGPT;
49 int doMore = 1, opt, i, numOptions = 0;
50 char* device = NULL;
51 Options theOptions[MAX_OPTIONS];
52
53 printf("GPT fdisk (sgdisk) version 0.5.4-pre1\n\n");
54 numOptions = ParseOptions(argc, argv, theOptions, &device);
55
56 if (device != NULL) {
57 if (theGPT.LoadPartitions(device)) {
58 for (i = 0; i < numOptions; i++) {
59 switch (theOptions[i].theCommand) {
60 case LIST:
61 theGPT.JustLooking();
62 theGPT.DisplayGPTData();
63 break;
64 case VERIFY:
65 theGPT.JustLooking();
66 theGPT.Verify();
67 break;
68 case NONE:
69 printf("Usage: %s {-lv} device\n", argv[0]);
70 break;
71 } // switch
72 } // for
73 } // if loaded OK
74 } // if (device != NULL)
75
76 return 0;
77} // main
78
79// Parse command-line options. Returns the number of arguments retrieved
80int ParseOptions(int argc, char* argv[], Options* theOptions, char** device) {
81 int opt, i, numOptions = 0;
82 int verbose_flag;
83
84 // Use getopt() to extract commands and their arguments
85 /* getopt_long stores the option index here. */
86 int option_index = 0;
87
88// c = getopt_long (argc, argv, "abc:d:f:",
89// long_options, &option_index);
90
91 while (((opt = getopt_long(argc, argv, "vl", long_options, &option_index)) != -1)
92 && (numOptions < MAX_OPTIONS)) {
93 printf("opt is %c, option_index is %d\n", opt, option_index);
94 switch (opt) {
95 case 'l':
96 printf("Entering list option, numOptions = %d!\n", numOptions);
97 theOptions[numOptions].theCommand = LIST;
98 theOptions[numOptions++].theArgument = NULL;
99 break;
100 case 'v':
101 theOptions[numOptions].theCommand = VERIFY;
102 theOptions[numOptions++].theArgument = NULL;
103 break;
104 default:
105 printf("Default switch; opt is %c\n", opt);
106 break;
107// abort();
108 } // switch
109 } // while
110
111 // Find non-option arguments. If the user types a legal command, there
112 // will be only one of these: The device filename....
113 opt = 0;
114 printf("Searching for device filename; optind is %d\n", optind);
115 for (i = optind; i < argc; i++) {
116 *device = argv[i];
117 printf("Setting device to %s\n", argv[i]);
118 opt++;
119 } // for
120 if (opt > 1) {
121 fprintf(stderr, "Warning! Found stray unrecognized arguments! Program may misbehave!\n");
122 } // if
123
124 return numOptions;
125} // ParseOptions()
126
127/* // Accept a command and execute it. Returns only when the user
128// wants to exit (such as after a 'w' or 'q' command).
129void MainMenu(char* filename, struct GPTData* theGPT) {
130 char command, line[255], buFile[255];
131 char* junk;
132 int goOn = 1;
133 PartTypes typeHelper;
134 uint32_t temp1, temp2;
135
136 do {
137 printf("\nCommand (? for help): ");
138 junk = fgets(line, 255, stdin);
139 sscanf(line, "%c", &command);
140 switch (command) {
141 case 'b': case 'B':
142 printf("Enter backup filename to save: ");
143 junk = fgets(line, 255, stdin);
144 sscanf(line, "%s", (char*) &buFile);
145 theGPT->SaveGPTBackup(buFile);
146 break;
147 case 'c': case 'C':
148 if (theGPT->GetPartRange(&temp1, &temp2) > 0)
149 theGPT->SetName(theGPT->GetPartNum());
150 else
151 printf("No partitions\n");
152 break;
153 case 'd': case 'D':
154 theGPT->DeletePartition();
155 break;
156 case 'i': case 'I':
157 theGPT->ShowDetails();
158 break;
159 case 'l': case 'L':
160 typeHelper.ShowTypes();
161 break;
162 case 'n': case 'N':
163 theGPT->CreatePartition();
164 break;
165 case 'o': case 'O':
166 printf("This option deletes all partitions and creates a new "
167 "protective MBR.\nProceed? ");
168 if (GetYN() == 'Y') {
169 theGPT->ClearGPTData();
170 theGPT->MakeProtectiveMBR();
171 } // if
172 break;
173 case 'p': case 'P':
174 theGPT->DisplayGPTData();
175 break;
176 case 'q': case 'Q':
177 goOn = 0;
178 break;
179 case 'r': case 'R':
180 RecoveryMenu(filename, theGPT);
181 goOn = 0;
182 break;
183 case 's': case 'S':
184 theGPT->SortGPT();
185 printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
186 break;
187 case 't': case 'T':
188 theGPT->ChangePartType();
189 break;
190 case 'v': case 'V':
191 if (theGPT->Verify() > 0) { // problems found
192 printf("You may be able to correct the problems by using options on the experts\n"
193 "menu (press 'x' at the command prompt). Good luck!\n");
194 } // if
195 break;
196 case 'w': case 'W':
197 if (theGPT->SaveGPTData() == 1)
198 goOn = 0;
199 break;
200 case 'x': case 'X':
201 ExpertsMenu(filename, theGPT);
202 goOn = 0;
203 break;
204 default:
205 ShowCommands();
206 break;
207 } // switch
208 } while (goOn);
209} // MainMenu()
210
211void ShowCommands(void) {
212 printf("b\tback up GPT data to a file\n");
213 printf("c\tchange a partition's name\n");
214 printf("d\tdelete a partition\n");
215 printf("i\tshow detailed information on a partition\n");
216 printf("l\tlist known partition types\n");
217 printf("n\tadd a new partition\n");
218 printf("o\tcreate a new empty GUID partition table (GPT)\n");
219 printf("p\tprint the partition table\n");
220 printf("q\tquit without saving changes\n");
221 printf("r\trecovery and transformation options (experts only)\n");
222 printf("s\tsort partitions\n");
223 printf("t\tchange a partition's type code\n");
224 printf("v\tverify disk\n");
225 printf("w\twrite table to disk and exit\n");
226 printf("x\textra functionality (experts only)\n");
227 printf("?\tprint this menu\n");
228} // ShowCommands()
229
230// Accept a recovery & transformation menu command. Returns only when the user
231// issues an exit command, such as 'w' or 'q'.
232void RecoveryMenu(char* filename, struct GPTData* theGPT) {
233 char command, line[255], buFile[255];
234 char* junk;
235 PartTypes typeHelper;
236 uint32_t temp1;
237 int goOn = 1;
238
239 do {
240 printf("\nrecovery/transformation command (? for help): ");
241 junk = fgets(line, 255, stdin);
242 sscanf(line, "%c", &command);
243 switch (command) {
244 case 'b': case 'B':
245 theGPT->RebuildMainHeader();
246 break;
247 case 'c': case 'C':
248 printf("Warning! This will probably do weird things if you've converted an MBR to\n"
249 "GPT form and haven't yet saved the GPT! Proceed? ");
250 if (GetYN() == 'Y')
251 theGPT->LoadSecondTableAsMain();
252 break;
253 case 'd': case 'D':
254 theGPT->RebuildSecondHeader();
255 break;
256 case 'e': case 'E':
257 printf("Warning! This will probably do weird things if you've converted an MBR to\n"
258 "GPT form and haven't yet saved the GPT! Proceed? ");
259 if (GetYN() == 'Y')
260 theGPT->LoadMainTable();
261 break;
262 case 'f': case 'F':
263 printf("Warning! This will destroy the currently defined partitions! Proceed? ");
264 if (GetYN() == 'Y') {
265 if (theGPT->LoadMBR(filename) == 1) { // successful load
266 theGPT->XFormPartitions();
267 } else {
268 printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
269 theGPT->MakeProtectiveMBR();
270 } // if/else
271 } // if
272 break;
273 case 'g': case 'G':
274 temp1 = theGPT->XFormToMBR();
275 if (temp1 > 0) {
276 printf("Converted %d partitions. Finalize and exit? ", temp1);
277 if (GetYN() == 'Y') {
278 if (theGPT->DestroyGPT(0) > 0)
279 goOn = 0;
280 } else {
281 theGPT->MakeProtectiveMBR();
282 printf("Note: New protective MBR created.\n");
283 } // if/else
284 } // if
285 break;
286 case 'h': case 'H':
287 theGPT->MakeHybrid();
288 break;
289 case 'i': case 'I':
290 theGPT->ShowDetails();
291 break;
292 case 'l': case 'L':
293 printf("Enter backup filename to load: ");
294 junk = fgets(line, 255, stdin);
295 sscanf(line, "%s", (char*) &buFile);
296 theGPT->LoadGPTBackup(buFile);
297 break;
298 case 'm': case 'M':
299 MainMenu(filename, theGPT);
300 goOn = 0;
301 break;
302 case 'o': case 'O':
303 theGPT->DisplayMBRData();
304 break;
305 case 'p': case 'P':
306 theGPT->DisplayGPTData();
307 break;
308 case 'q': case 'Q':
309 goOn = 0;
310 break;
311 case 't': case 'T':
312 theGPT->XFormDisklabel();
313 break;
314 case 'v': case 'V':
315 theGPT->Verify();
316 break;
317 case 'w': case 'W':
318 if (theGPT->SaveGPTData() == 1) {
319 goOn = 0;
320 } // if
321 break;
322 case 'x': case 'X':
323 ExpertsMenu(filename, theGPT);
324 goOn = 0;
325 break;
326 default:
327 ShowRecoveryCommands();
328 break;
329 } // switch
330 } while (goOn);
331} // RecoveryMenu()
332
333void ShowRecoveryCommands(void) {
334 printf("b\tuse backup GPT header (rebuilding main)\n");
335 printf("c\tload backup partition table from disk (rebuilding main)\n");
336 printf("d\tuse main GPT header (rebuilding backup)\n");
337 printf("e\tload main partition table from disk (rebuilding backup)\n");
338 printf("f\tload MBR and build fresh GPT from it\n");
339 printf("g\tconvert GPT into MBR and exit\n");
340 printf("h\tmake hybrid MBR\n");
341 printf("i\tshow detailed information on a partition\n");
342 printf("l\tload partition data from a backup file\n");
343 printf("m\treturn to main menu\n");
344 printf("o\tprint protective MBR data\n");
345 printf("p\tprint the partition table\n");
346 printf("q\tquit without saving changes\n");
347 printf("t\ttransform BSD disklabel partition\n");
348 printf("v\tverify disk\n");
349 printf("w\twrite table to disk and exit\n");
350 printf("x\textra functionality (experts only)\n");
351 printf("?\tprint this menu\n");
352} // ShowRecoveryCommands()
353
354// Accept an experts' menu command. Returns only after the user
355// selects an exit command, such as 'w' or 'q'.
356void ExpertsMenu(char* filename, struct GPTData* theGPT) {
357 char command, line[255];
358 char* junk;
359 PartTypes typeHelper;
360 uint32_t pn;
361 uint32_t temp1, temp2;
362 int goOn = 1;
363
364 do {
365 printf("\nExpert command (? for help): ");
366 junk = fgets(line, 255, stdin);
367 sscanf(line, "%c", &command);
368 switch (command) {
369 case 'a': case 'A':
370 if (theGPT->GetPartRange(&temp1, &temp2) > 0)
371 theGPT->SetAttributes(theGPT->GetPartNum());
372 else
373 printf("No partitions\n");
374 break;
375 case 'c': case 'C':
376 if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
377 pn = theGPT->GetPartNum();
378 printf("Enter the partition's new unique GUID:\n");
379 theGPT->SetPartitionGUID(pn, GetGUID());
380 } else printf("No partitions\n");
381 break;
382 case 'd': case 'D':
383 printf("The number of logical sectors per physical sector is %d.\n",
384 theGPT->GetAlignment());
385 break;
386 case 'e': case 'E':
387 printf("Relocating backup data structures to the end of the disk\n");
388 theGPT->MoveSecondHeaderToEnd();
389 break;
390 case 'g': case 'G':
391 printf("Enter the disk's unique GUID:\n");
392 theGPT->SetDiskGUID(GetGUID());
393 break;
394 case 'i': case 'I':
395 theGPT->ShowDetails();
396 break;
397 case 'l': case 'L':
398 temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
399 theGPT->SetAlignment(temp1);
400 break;
401 case 'm': case 'M':
402 MainMenu(filename, theGPT);
403 goOn = 0;
404 break;
405 case 'n': case 'N':
406 theGPT->MakeProtectiveMBR();
407 break;
408 case 'o': case 'O':
409 theGPT->DisplayMBRData();
410 break;
411 case 'p': case 'P':
412 theGPT->DisplayGPTData();
413 break;
414 case 'q': case 'Q':
415 goOn = 0;
416 break;
417 case 'r': case 'R':
418 RecoveryMenu(filename, theGPT);
419 goOn = 0;
420 break;
421 case 's': case 'S':
422 theGPT->ResizePartitionTable();
423 break;
424 case 'v': case 'V':
425 theGPT->Verify();
426 break;
427 case 'w': case 'W':
428 if (theGPT->SaveGPTData() == 1) {
429 goOn = 0;
430 } // if
431 break;
432 case 'z': case 'Z':
433 if (theGPT->DestroyGPT() == 1) {
434 goOn = 0;
435 }
436 break;
437 default:
438 ShowExpertCommands();
439 break;
440 } // switch
441 } while (goOn);
442} // ExpertsMenu()
443
444void ShowExpertCommands(void) {
445 printf("a\tset attributes\n");
446 printf("c\tchange partition GUID\n");
447 printf("d\tdisplay the number of logical sectors per physical sector\n");
448 printf("e\trelocate backup data structures to the end of the disk\n");
449 printf("g\tchange disk GUID\n");
450 printf("i\tshow detailed information on a partition\n");
451 printf("b\tset the number of logical sectors per physical sector\n");
452 printf("m\treturn to main menu\n");
453 printf("n\tcreate a new protective MBR\n");
454 printf("o\tprint protective MBR data\n");
455 printf("p\tprint the partition table\n");
456 printf("q\tquit without saving changes\n");
457 printf("r\trecovery and transformation options (experts only)\n");
458 printf("s\tresize partition table\n");
459 printf("v\tverify disk\n");
460 printf("w\twrite table to disk and exit\n");
461 printf("z\tzap (destroy) GPT data structures and exit\n");
462 printf("?\tprint this menu\n");
463} // ShowExpertCommands()
464*/