srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 1 | // gdisk.cc |
| 2 | // Program modelled after Linux fdisk, but it manipulates GPT partitions |
| 3 | // rather than MBR partitions. |
| 4 | // |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame^] | 5 | // by Rod Smith, project began February 2009 |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 6 | |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 7 | /* 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 | |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 10 | //#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); |
| 20 | int DoCommand(char* filename, struct GPTData* theGPT); |
| 21 | void ShowCommands(void); |
| 22 | void ShowExpertCommands(void); |
| 23 | int ExpertsMenu(char* filename, struct GPTData* theGPT); |
| 24 | |
| 25 | int main(int argc, char* argv[]) { |
| 26 | GPTData theGPT; |
| 27 | int doMore = 1; |
| 28 | char* device = NULL; |
| 29 | |
srs5694 | e4ac11e | 2009-08-31 10:13:04 -0400 | [diff] [blame^] | 30 | printf("GPT fdisk (gdisk) version 0.4.1\n\n"); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 31 | |
| 32 | if (argc == 2) { // basic usage |
| 33 | if (SizesOK()) { |
| 34 | doMore = theGPT.LoadPartitions(argv[1]); |
| 35 | while (doMore) { |
| 36 | doMore = DoCommand(argv[1], &theGPT); |
| 37 | } // while |
| 38 | } // if |
| 39 | } else if (argc == 3) { // usage with "-l" option |
| 40 | if (SizesOK()) { |
| 41 | if (strcmp(argv[1], "-l") == 0) { |
| 42 | device = argv[2]; |
| 43 | } else if (strcmp(argv[2], "-l") == 0) { |
| 44 | device = argv[1]; |
| 45 | } else { // 3 arguments, but none is "-l" |
| 46 | fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]); |
| 47 | } // if/elseif/else |
| 48 | if (device != NULL) { |
| 49 | doMore = theGPT.LoadPartitions(device); |
| 50 | if (doMore) theGPT.DisplayGPTData(); |
| 51 | } // if |
| 52 | } // if |
| 53 | } else { |
| 54 | fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]); |
| 55 | } // if/else |
| 56 | } // main |
| 57 | |
| 58 | // Accept a command and execute it. Returns 0 if the command includes |
| 59 | // an exit condition (such as a q or w command), 1 if more commands |
| 60 | // should be processed. |
| 61 | int DoCommand(char* filename, struct GPTData* theGPT) { |
| 62 | char command, line[255]; |
| 63 | int retval = 1; |
| 64 | PartTypes typeHelper; |
| 65 | uint32_t temp1, temp2; |
| 66 | |
| 67 | printf("\nCommand (m for help): "); |
| 68 | fgets(line, 255, stdin); |
| 69 | sscanf(line, "%c", &command); |
| 70 | switch (command) { |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 71 | case 'b': case 'B': |
| 72 | theGPT->XFormDisklabel(); |
| 73 | break; |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 74 | case 'c': case 'C': |
| 75 | if (theGPT->GetPartRange(&temp1, &temp2) > 0) |
| 76 | theGPT->SetName(theGPT->GetPartNum()); |
| 77 | else |
| 78 | printf("No partitions\n"); |
| 79 | break; |
| 80 | case 'd': case 'D': |
| 81 | theGPT->DeletePartition(); |
| 82 | break; |
| 83 | case 'i': case 'I': |
| 84 | theGPT->ShowDetails(); |
| 85 | break; |
| 86 | case 'l': case 'L': |
| 87 | typeHelper.ShowTypes(); |
| 88 | break; |
| 89 | case 'n': case 'N': |
| 90 | theGPT->CreatePartition(); |
| 91 | break; |
| 92 | case 'o': case 'O': |
| 93 | theGPT->ClearGPTData(); |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 94 | theGPT->MakeProtectiveMBR(); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 95 | // theGPT->BlankPartitions(); |
| 96 | break; |
| 97 | case 'p': case 'P': |
| 98 | theGPT->DisplayGPTData(); |
| 99 | break; |
| 100 | case 'q': case 'Q': |
| 101 | retval = 0; |
| 102 | break; |
| 103 | case 's': case 'S': |
| 104 | theGPT->SortGPT(); |
| 105 | printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n"); |
| 106 | break; |
| 107 | case 't': case 'T': |
| 108 | theGPT->ChangePartType(); |
| 109 | break; |
| 110 | case 'v': case 'V': |
| 111 | if (theGPT->Verify() > 0) { // problems found |
| 112 | printf("You may be able to correct the problems by using options on the experts\n" |
| 113 | "menu (press 'x' at the command prompt). Good luck!\n"); |
| 114 | } // if |
| 115 | break; |
| 116 | case 'w': case 'W': |
| 117 | if (theGPT->SaveGPTData() == 1) |
| 118 | retval = 0; |
| 119 | break; |
| 120 | case 'x': case 'X': |
| 121 | retval = ExpertsMenu(filename, theGPT); |
| 122 | break; |
| 123 | default: |
| 124 | ShowCommands(); |
| 125 | break; |
| 126 | } // switch |
| 127 | return (retval); |
| 128 | } // DoCommand() |
| 129 | |
| 130 | void ShowCommands(void) { |
srs5694 | 221e087 | 2009-08-29 15:00:31 -0400 | [diff] [blame] | 131 | printf("b\tconvert BSD disklabel partitions\n"); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 132 | printf("c\tchange a partition's name\n"); |
| 133 | printf("d\tdelete a partition\n"); |
| 134 | printf("i\tshow detailed information on a partition\n"); |
| 135 | printf("l\tlist available partition types\n"); |
| 136 | printf("m\tprint this menu\n"); |
| 137 | printf("n\tadd a new partition\n"); |
| 138 | printf("o\tcreate a new empty GUID partition table (GPT)\n"); |
| 139 | printf("p\tprint the partition table\n"); |
| 140 | printf("q\tquit without saving changes\n"); |
| 141 | printf("s\tsort partitions\n"); |
| 142 | printf("t\tchange a partition's type code\n"); |
| 143 | printf("v\tverify disk\n"); |
| 144 | printf("w\twrite table to disk and exit\n"); |
| 145 | printf("x\textra functionality (experts only)\n"); |
| 146 | } // ShowCommands() |
| 147 | |
| 148 | // Accept a command and execute it. Returns 0 if the command includes |
| 149 | // an exit condition (such as a q or w command), 1 if more commands |
| 150 | // should be processed. |
| 151 | int ExpertsMenu(char* filename, struct GPTData* theGPT) { |
| 152 | char command, line[255], buFile[255]; |
| 153 | int retval = 1; |
| 154 | PartTypes typeHelper; |
| 155 | uint32_t pn; |
| 156 | uint32_t temp1, temp2; |
| 157 | int goOn = 1; |
| 158 | |
| 159 | do { |
| 160 | printf("\nExpert command (m for help): "); |
| 161 | fgets(line, 255, stdin); |
| 162 | sscanf(line, "%c", &command); |
| 163 | switch (command) { |
| 164 | case 'a': case 'A': |
| 165 | if (theGPT->GetPartRange(&temp1, &temp2) > 0) |
| 166 | theGPT->SetAttributes(theGPT->GetPartNum()); |
| 167 | else |
| 168 | printf("No partitions\n"); |
| 169 | break; |
| 170 | case 'b': case 'B': |
| 171 | theGPT->RebuildMainHeader(); |
| 172 | break; |
| 173 | case 'c': case 'C': |
| 174 | printf("Warning! This will probably do weird things if you've converted an MBR to\n" |
| 175 | "GPT form and haven't yet saved the GPT! Proceed? "); |
| 176 | if (GetYN() == 'Y') |
| 177 | theGPT->LoadSecondTableAsMain(); |
| 178 | break; |
| 179 | case 'd': case 'D': |
| 180 | theGPT->RebuildSecondHeader(); |
| 181 | break; |
| 182 | case 'e': case 'E': |
| 183 | printf("Warning! This will probably do weird things if you've converted an MBR to\n" |
| 184 | "GPT form and haven't yet saved the GPT! Proceed? "); |
| 185 | if (GetYN() == 'Y') |
| 186 | theGPT->LoadMainTable(); |
| 187 | break; |
| 188 | case 'f': case 'F': |
| 189 | if (theGPT->GetPartRange(&temp1, &temp2) > 0) { |
| 190 | pn = theGPT->GetPartNum(); |
| 191 | printf("Enter the partition's new unique GUID:\n"); |
| 192 | theGPT->SetPartitionGUID(pn, GetGUID()); |
| 193 | } else printf("No partitions\n"); |
| 194 | break; |
| 195 | case 'g': case 'G': |
| 196 | printf("Enter the disk's unique GUID:\n"); |
| 197 | theGPT->SetDiskGUID(GetGUID()); |
| 198 | break; |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 199 | case 'h': case 'H': |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 200 | theGPT->MakeHybrid(); |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 201 | break; |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 202 | case 'i': case 'I': |
| 203 | theGPT->ShowDetails(); |
| 204 | break; |
| 205 | case 'k': case 'K': |
| 206 | printf("Enter backup filename to save: "); |
| 207 | fgets(line, 255, stdin); |
| 208 | sscanf(line, "%s", &buFile); |
| 209 | theGPT->SaveGPTBackup(buFile); |
| 210 | break; |
| 211 | case 'l': case 'L': |
| 212 | printf("Enter backup filename to load: "); |
| 213 | fgets(line, 255, stdin); |
| 214 | sscanf(line, "%s", &buFile); |
| 215 | theGPT->LoadGPTBackup(buFile); |
| 216 | break; |
| 217 | case 'n': case 'N': |
| 218 | theGPT->MakeProtectiveMBR(); |
| 219 | break; |
| 220 | case 'o': case 'O': |
| 221 | theGPT->DisplayMBRData(); |
| 222 | break; |
| 223 | case 'p': case 'P': |
| 224 | theGPT->DisplayGPTData(); |
| 225 | break; |
| 226 | case 'q': case 'Q': |
| 227 | retval = 0; |
| 228 | goOn = 0; |
| 229 | break; |
| 230 | case 'r': case 'R': |
| 231 | goOn = 0; |
| 232 | break; |
| 233 | case 's': case 'S': |
| 234 | theGPT->ResizePartitionTable(); |
| 235 | break; |
| 236 | case 'v': case 'V': |
| 237 | theGPT->Verify(); |
| 238 | break; |
| 239 | case 'w': case 'W': |
| 240 | if (theGPT->SaveGPTData() == 1) { |
| 241 | retval = 0; |
| 242 | goOn = 0; |
| 243 | } // if |
| 244 | break; |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 245 | case 'z': case 'Z': |
| 246 | if (theGPT->DestroyGPT() == 1) { |
| 247 | retval = 0; |
| 248 | goOn = 0; |
| 249 | } |
| 250 | break; |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 251 | default: |
| 252 | ShowExpertCommands(); |
| 253 | break; |
| 254 | } // switch |
| 255 | } while (goOn); |
| 256 | return (retval); |
| 257 | } // ExpertsMenu() |
| 258 | |
| 259 | void ShowExpertCommands(void) { |
| 260 | printf("a\tset attributes\n"); |
| 261 | printf("b\tuse backup GPT header (rebuilding main)\n"); |
| 262 | printf("c\tload backup partition table from disk (rebuilding main)\n"); |
| 263 | printf("d\tuse main GPT header (rebuilding backup)\n"); |
| 264 | printf("e\tload main partition table from disk (rebuilding backup)\n"); |
| 265 | printf("f\tchange partition GUID\n"); |
| 266 | printf("g\tchange disk GUID\n"); |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 267 | printf("h\tmake hybrid MBR\n"); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 268 | printf("i\tshow detailed information on a partition\n"); |
| 269 | printf("k\tsave partition data to a backup file\n"); |
| 270 | printf("l\tload partition data from a backup file\n"); |
| 271 | printf("m\tprint this menu\n"); |
| 272 | printf("n\tcreate a new protective MBR\n"); |
| 273 | printf("o\tprint protective MBR data\n"); |
| 274 | printf("p\tprint the partition table\n"); |
| 275 | printf("q\tquit without saving changes\n"); |
| 276 | printf("r\treturn to main menu\n"); |
| 277 | printf("s\tresize partition table\n"); |
| 278 | printf("v\tverify disk\n"); |
| 279 | printf("w\twrite table to disk and exit\n"); |
srs5694 | c0ca8f8 | 2009-08-20 21:35:25 -0400 | [diff] [blame] | 280 | printf("z\tDestroy GPT data structures and exit\n"); |
srs5694 | e7b4ff9 | 2009-08-18 13:16:10 -0400 | [diff] [blame] | 281 | } // ShowExpertCommands() |