blob: 027e37f11d996304e054e00a4641996081473564 [file] [log] [blame]
srs56941e093722010-01-05 00:14:19 -05001// sgdisk.cc
srs569473ba4792010-01-12 18:18:17 -05002// Command-line-based version of gdisk. This program is named after sfdisk,
3// and it can serve a similar role (easily scripted, etc.), but it's used
4// strictly via command-line arguments, and it doesn't bear much resemblance
5// to sfdisk in actual use.
srs56941e093722010-01-05 00:14:19 -05006//
srs569473ba4792010-01-12 18:18:17 -05007// by Rod Smith, project began February 2009; sgdisk begun January 2010.
srs56941e093722010-01-05 00:14:19 -05008
9/* This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
10 under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
11
srs56941e093722010-01-05 00:14:19 -050012#include <stdio.h>
srs569473ba4792010-01-12 18:18:17 -050013#include <string>
14#include <popt.h>
15#include <errno.h>
srs56941e093722010-01-05 00:14:19 -050016#include "mbr.h"
17#include "gpt.h"
18#include "support.h"
srs569473ba4792010-01-12 18:18:17 -050019#include "parttypes.h"
20
21using namespace std;
srs56941e093722010-01-05 00:14:19 -050022
23#define MAX_OPTIONS 50
24
srs569473ba4792010-01-12 18:18:17 -050025uint64_t GetInt(char* Info, int itemNum);
26string GetString(char* Info, int itemNum);
srs56941e093722010-01-05 00:14:19 -050027
srs569473ba4792010-01-12 18:18:17 -050028int main(int argc, char *argv[]) {
srs56941e093722010-01-05 00:14:19 -050029 GPTData theGPT;
srs569473ba4792010-01-12 18:18:17 -050030 int opt, i, numOptions = 0, saveData = 0, neverSaveData = 0;
31 int partNum = 0, deletePartNum = 0, infoPartNum = 0, bsdPartNum = 0, saveNonGPT = 1;
32 int alignment = 8, retval = 0, pretend = 0;
33 uint16_t hexCode;
34 uint32_t tableSize = 128;
35 uint64_t startSector, endSector;
srs56941e093722010-01-05 00:14:19 -050036 char* device = NULL;
srs569473ba4792010-01-12 18:18:17 -050037 char *argument = NULL, *newPartInfo = NULL, *typeCode = NULL, *partName;
38 char *backupFile = NULL;
srs56941e093722010-01-05 00:14:19 -050039 PartTypes typeHelper;
srs56941e093722010-01-05 00:14:19 -050040
srs569473ba4792010-01-12 18:18:17 -050041 poptContext poptCon;
42 struct poptOption theOptions[] =
43 {
44 {"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
45 {"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
46 {"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
47 {"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
48 {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
49 {"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
50 {"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
51 {"mbrtogpt", 'g', POPT_ARG_NONE, NULL, 'g', "convert MBR to GPT", ""},
52 {"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
53 {"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
54 {"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""},
55 {"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
56 {"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
57 {"print", 'p', POPT_ARG_NONE, NULL, 'p', "print partition table", ""},
58 {"pretend", 'P', POPT_ARG_NONE, NULL, 'P', "make changes in memory, but don't write them", ""},
59 {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
60 {"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
61 {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:hexcode"},
62 {"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
63 {"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
64 {"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""},
65 {"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT data structures", ""},
66 POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
67 };
68
69 // Create popt context...
70 poptCon = poptGetContext(NULL, argc, (const char**) argv, theOptions, 0);
71
72 poptSetOtherOptionHelp(poptCon, " [OPTION...] <device>");
73
74 if (argc < 2) {
75 poptPrintUsage(poptCon, stderr, 0);
76 exit(1);
77 }
78
79 // Do one loop through the options to find the device filename and deal
80 // with options that don't require a device filename....
81 while ((opt = poptGetNextOpt(poptCon)) > 0) {
82 switch (opt) {
83 case 'L':
srs56941e093722010-01-05 00:14:19 -050084 typeHelper.ShowTypes();
85 break;
srs569473ba4792010-01-12 18:18:17 -050086 case 'P':
87 pretend = 1;
srs56941e093722010-01-05 00:14:19 -050088 break;
srs569473ba4792010-01-12 18:18:17 -050089 case 'V':
90 printf("GPT fdisk (sgdisk) version 0.5.4-pre1\n\n");
srs56941e093722010-01-05 00:14:19 -050091 break;
92 default:
srs56941e093722010-01-05 00:14:19 -050093 break;
94 } // switch
srs569473ba4792010-01-12 18:18:17 -050095 numOptions++;
96 } // while
srs56941e093722010-01-05 00:14:19 -050097
srs569473ba4792010-01-12 18:18:17 -050098 // Assume first non-option argument is the device filename....
99 device = (char*) poptGetArg(poptCon);
100 poptResetContext(poptCon);
srs56941e093722010-01-05 00:14:19 -0500101
srs569473ba4792010-01-12 18:18:17 -0500102 if (device != NULL) {
103 theGPT.JustLooking(); // reset as necessary
104 theGPT.BeQuiet(); // Tell called functions to be less verbose & interactive
105 if (theGPT.LoadPartitions(device)) {
106 if ((theGPT.WhichWasUsed() == use_mbr) || (theGPT.WhichWasUsed() == use_bsd))
107 saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
108 while ((opt = poptGetNextOpt(poptCon)) > 0) {
109 switch (opt) {
110 case 'a':
111 theGPT.SetAlignment(alignment);
112 break;
113 case 'b':
114 theGPT.SaveGPTBackup(backupFile);
115 free(backupFile);
116 break;
117 case 'c':
118 theGPT.JustLooking(0);
119 partNum = (int) GetInt(partName, 1) - 1;
120 if (theGPT.SetName(partNum, (char*) GetString(partName, 2).c_str())) {
121 saveData = 1;
122 } else {
123 fprintf(stderr, "Unable set set partition %d's name to '%s'!\n",
124 partNum + 1, GetString(partName, 2).c_str());
125 neverSaveData = 1;
126 } // if/else
127 free(partName);
128 break;
129 case 'd':
130 theGPT.JustLooking(0);
131 if (theGPT.DeletePartition(deletePartNum - 1) == 0) {
132 fprintf(stderr, "Error %d deleting partition!\n", errno);
133 neverSaveData = 1;
134 } else saveData = 1;
135 break;
136 case 'e':
137 theGPT.JustLooking(0);
138 theGPT.MoveSecondHeaderToEnd();
139 saveData = 1;
140 break;
141 case 'E':
142 printf("%llu\n", (unsigned long long) theGPT.FindLastAvailable(theGPT.FindFirstInLargest()));
143 break;
144 case 'f':
145 printf("%llu\n", (unsigned long long) theGPT.FindFirstInLargest());
146 break;
147 case 'g':
148 theGPT.JustLooking(0);
149 saveData = 1;
150 saveNonGPT = 1;
151 break;
152 case 'i':
153 theGPT.ShowPartDetails(infoPartNum - 1);
154 break;
155 case 'l':
156 if (theGPT.LoadGPTBackup(backupFile) == 1)
157 saveData = 1;
158 else {
159 saveData = 0;
160 neverSaveData = 1;
161 fprintf(stderr, "Error loading backup file!\n");
162 } // else
163 free(backupFile);
164 break;
165 case 'L':
166 break;
167 case 'n':
168 theGPT.JustLooking(0);
169 partNum = (int) GetInt(newPartInfo, 1) - 1;
170 startSector = GetInt(newPartInfo, 2);
171 endSector = GetInt(newPartInfo, 3);
172 if (theGPT.CreatePartition(partNum, startSector, endSector)) {
173 saveData = 1;
174 } else {
175 fprintf(stderr, "Could not create partition %d from %llu to %llu!\n",
176 partNum, startSector, endSector);
177 neverSaveData = 1;
178 } // if/else
179 free(newPartInfo);
180 break;
181 case 'o':
182 theGPT.JustLooking(0);
183 theGPT.ClearGPTData();
184 saveData = 1;
185 break;
186 case 'p':
187 theGPT.DisplayGPTData();
188 break;
189 case 'P':
190 pretend = 1;
191 break;
192 case 's':
193 theGPT.JustLooking(0);
194 theGPT.SortGPT();
195 saveData = 1;
196 break;
197 case 'S':
198 theGPT.JustLooking(0);
199 if (theGPT.SetGPTSize(tableSize) == 0)
200 neverSaveData = 1;
201 else
202 saveData = 1;
203 break;
204 case 't':
205 theGPT.JustLooking(0);
206 partNum = (int) GetInt(typeCode, 1) - 1;
207 sscanf(GetString(typeCode, 2).c_str(), "%x", &hexCode);
208 if (theGPT.ChangePartType(partNum, hexCode)) {
209 saveData = 1;
210 } else {
211 fprintf(stderr, "Could not change partition %d's type code to %x!\n",
212 partNum + 1, hexCode);
213 neverSaveData = 1;
214 } // if/else
215 free(typeCode);
216 break;
217 case 'T':
218 theGPT.JustLooking(0);
219 theGPT.XFormDisklabel(bsdPartNum);
220 saveData = 1;
221 break;
222 case 'v':
223 theGPT.Verify();
224 break;
225 case 'z':
226 if (!pretend)
227 theGPT.DestroyGPT(-1);
228 saveNonGPT = 0;
229 break;
230 default:
231 printf("Unknown option (-%c)!\n", opt);
232 break;
233 } // switch
234 } // while
235 if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend))
236 theGPT.SaveGPTData(1);
237 if (saveData && (!saveNonGPT)) {
238 printf("Non-GPT disk; not saving changes. Use -g to override.\n");
239 retval = 3;
240 } // if
241 if (neverSaveData) {
242 printf("Error encountered; not saving changes.\n");
243 retval = 4;
244 } // if
245 } else { // if loaded OK
246 retval = 2;
247 } // if/else loaded OK
248 } // if (device != NULL)
249 poptFreeContext(poptCon);
srs56941e093722010-01-05 00:14:19 -0500250
srs569473ba4792010-01-12 18:18:17 -0500251 return retval;
252} // main
srs56941e093722010-01-05 00:14:19 -0500253
srs569473ba4792010-01-12 18:18:17 -0500254// Extract integer data from argument string, which should be colon-delimited
255uint64_t GetInt(char* argument, int itemNum) {
256 int startPos = -1, endPos = -1;
257 uint64_t retval = 0;
258 string Info;
srs56941e093722010-01-05 00:14:19 -0500259
srs569473ba4792010-01-12 18:18:17 -0500260 Info = argument;
261 while (itemNum-- > 0) {
262 startPos = endPos + 1;
263 endPos = Info.find(':', startPos);
264 }
265 if (endPos == string::npos)
266 endPos = Info.length();
267 endPos--;
srs56941e093722010-01-05 00:14:19 -0500268
srs569473ba4792010-01-12 18:18:17 -0500269 sscanf(Info.substr(startPos, endPos - startPos + 1).c_str(), "%llu", &retval);
270/* printf("In GetInt(), startPos = %d, endPos = %d, retval = %llu\n", startPos,
271 endPos, (unsigned long long) retval); */
272 return retval;
273} // GetInt()
srs56941e093722010-01-05 00:14:19 -0500274
srs569473ba4792010-01-12 18:18:17 -0500275// Extract string data from argument string, which should be colon-delimited
276string GetString(char* argument, int itemNum) {
277 int startPos = -1, endPos = -1;
278 string Info;
279
280 Info = argument;
281 while (itemNum-- > 0) {
282 startPos = endPos + 1;
283 endPos = Info.find(':', startPos);
284 }
285 if (endPos == string::npos)
286 endPos = Info.length();
287 endPos--;
288
289 return Info.substr(startPos, endPos - startPos + 1);
290} // GetString()