blob: 81b0dfa10cfee06ade1903e2e162802909687a45 [file] [log] [blame]
Bill Richardsonf1372d92010-06-11 09:15:55 -07001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cgpt.h"
6
7#include <getopt.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <uuid/uuid.h>
12
13#include "cgptlib_internal.h"
14
15static void Usage(void)
16{
17 printf("\nUsage: %s add [OPTIONS] DRIVE\n\n"
18 "Add, edit, or remove a partition entry.\n\n"
19 "Options:\n"
20 " -i NUM Specify partition (default is next available)\n"
21 " -b NUM Beginning sector\n"
22 " -s NUM Size in sectors\n"
23 " -t GUID Partition Type GUID\n"
24 " -u GUID Partition Unique ID\n"
25 " -l LABEL Label\n"
26 " -S NUM set Successful flag (0|1)\n"
27 " -T NUM set Tries flag (0-15)\n"
28 " -P NUM set Priority flag (0-15)\n"
29 " -A NUM set raw 64-bit attribute value\n"
30 "\n"
31 "Use the -i option to modify an existing partition.\n"
32 "The -b, -s, and -t options must be given for new partitions.\n"
33 "\n", progname);
34 PrintTypes();
35}
36
37int cmd_add(int argc, char *argv[]) {
38 struct drive drive;
Bill Richardsonc4e92af2010-10-12 07:33:15 -070039 uint32_t partition = 0;
Bill Richardsonf1372d92010-06-11 09:15:55 -070040 uint64_t begin = 0;
41 uint64_t size = 0;
42 Guid type_guid;
43 Guid unique_guid;
44 char *label = 0;
45 int successful = 0;
46 int tries = 0;
47 int priority = 0;
vbendebf7a45cc2010-06-21 08:44:16 -070048 uint16_t raw_value = 0;
Bill Richardsonf1372d92010-06-11 09:15:55 -070049 int set_begin = 0;
50 int set_size = 0;
51 int set_type = 0;
52 int set_unique = 0;
53 int set_successful = 0;
54 int set_tries = 0;
55 int set_priority = 0;
56 int set_raw = 0;
57
58 int gpt_retval;
59 GptEntry *entry;
Bill Richardsonc4e92af2010-10-12 07:33:15 -070060 uint32_t index;
61
Bill Richardsonf1372d92010-06-11 09:15:55 -070062 int c;
63 int errorcnt = 0;
64 char *e = 0;
65
66 opterr = 0; // quiet, you
67 while ((c=getopt(argc, argv, ":hi:b:s:t:u:l:S:T:P:A:")) != -1)
68 {
69 switch (c)
70 {
71 case 'i':
72 partition = (uint32_t)strtoul(optarg, &e, 0);
73 if (!*optarg || (e && *e))
74 {
75 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
76 errorcnt++;
77 }
78 break;
79 case 'b':
80 set_begin = 1;
81 begin = strtoull(optarg, &e, 0);
82 if (!*optarg || (e && *e))
83 {
84 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
85 errorcnt++;
86 }
87 break;
88 case 's':
89 set_size = 1;
90 size = strtoull(optarg, &e, 0);
91 if (!*optarg || (e && *e))
92 {
93 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
94 errorcnt++;
95 }
96 break;
97 case 't':
98 set_type = 1;
99 if (CGPT_OK != SupportedType(optarg, &type_guid) &&
100 CGPT_OK != StrToGuid(optarg, &type_guid)) {
101 Error("invalid argument to -%c: %s\n", c, optarg);
102 errorcnt++;
103 }
104 break;
105 case 'u':
106 set_unique = 1;
107 if (CGPT_OK != StrToGuid(optarg, &unique_guid)) {
108 Error("invalid argument to -%c: %s\n", c, optarg);
109 errorcnt++;
110 }
111 break;
112 case 'l':
113 label = optarg;
114 break;
115 case 'S':
116 set_successful = 1;
117 successful = (uint32_t)strtoul(optarg, &e, 0);
118 if (!*optarg || (e && *e))
119 {
120 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
121 errorcnt++;
122 }
123 if (successful < 0 || successful > 1) {
124 Error("value for -%c must be between 0 and 1", c);
125 errorcnt++;
126 }
127 break;
128 case 'T':
129 set_tries = 1;
130 tries = (uint32_t)strtoul(optarg, &e, 0);
131 if (!*optarg || (e && *e))
132 {
133 fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n",
134 progname, c, optarg);
135 errorcnt++;
136 }
137 if (tries < 0 || tries > 15) {
138 Error("value for -%c must be between 0 and 15", c);
139 errorcnt++;
140 }
141 break;
142 case 'P':
143 set_priority = 1;
144 priority = (uint32_t)strtoul(optarg, &e, 0);
145 if (!*optarg || (e && *e))
146 {
147 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
148 errorcnt++;
149 }
150 if (priority < 0 || priority > 15) {
151 Error("value for -%c must be between 0 and 15", c);
152 errorcnt++;
153 }
154 break;
155 case 'A':
156 set_raw = 1;
157 raw_value = strtoull(optarg, &e, 0);
158 if (!*optarg || (e && *e))
159 {
160 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
161 errorcnt++;
162 }
163 break;
164
165 case 'h':
166 Usage();
167 return CGPT_OK;
168 case '?':
169 Error("unrecognized option: -%c\n", optopt);
170 errorcnt++;
171 break;
172 case ':':
173 Error("missing argument to -%c\n", optopt);
174 errorcnt++;
175 break;
176 default:
177 errorcnt++;
178 break;
179 }
180 }
181 if (errorcnt)
182 {
183 Usage();
184 return CGPT_FAILED;
185 }
186
187 if (optind >= argc) {
188 Error("missing drive argument\n");
189 return CGPT_FAILED;
190 }
191
192 if (CGPT_OK != DriveOpen(argv[optind], &drive))
193 return CGPT_FAILED;
194
195 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
196 Error("GptSanityCheck() returned %d: %s\n",
197 gpt_retval, GptError(gpt_retval));
198 return CGPT_FAILED;
199 }
200
Louis Yung-Chieh Lo2b23c022010-11-18 09:53:10 +0800201 if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
202 ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
203 Error("one of the GPT header/entries is invalid.\n"
204 "please run 'cgpt repair' before adding anything.\n");
205 return CGPT_FAILED;
206 }
207
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700208 uint32_t max_part = GetNumberOfEntries(&drive.gpt);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700209 if (partition) {
210 if (partition > max_part) {
211 Error("invalid partition number: %d\n", partition);
212 goto bad;
213 }
214 index = partition - 1;
215 entry = GetEntry(&drive.gpt, PRIMARY, index);
216 } else {
217 // find next empty partition
218 for (index = 0; index < max_part; index++) {
219 entry = GetEntry(&drive.gpt, PRIMARY, index);
220 if (IsZero(&entry->type)) {
221 partition = index + 1;
222 break;
223 }
224 }
225 if (index >= max_part) {
226 Error("no unused partitions available\n");
227 goto bad;
228 }
229 }
230
231 // New partitions must specify type, begin, and size.
232 if (IsZero(&entry->type)) {
233 if (!set_begin || !set_size || !set_type) {
234 Error("-t, -b, and -s options are required for new partitions\n");
235 goto bad;
236 }
237 if (IsZero(&type_guid)) {
238 Error("New partitions must have a type other than \"unused\"\n");
239 goto bad;
240 }
241 if (!set_unique)
242 uuid_generate((uint8_t *)&entry->unique);
243 }
244
245 if (set_begin)
246 entry->starting_lba = begin;
247 if (set_size)
248 entry->ending_lba = begin + size - 1;
249 if (set_type)
250 memcpy(&entry->type, &type_guid, sizeof(Guid));
251 if (set_unique)
252 memcpy(&entry->unique, &unique_guid, sizeof(Guid));
253 if (label) {
Louis Yung-Chieh Lo500b3c22010-11-22 18:19:11 +0800254 if (CGPT_OK != UTF8ToUTF16((uint8_t *)label, entry->name,
255 sizeof(entry->name) / sizeof(entry->name[0]))) {
256 Error("The label cannot be converted to UTF16.\n");
257 goto bad;
258 }
Bill Richardsonf1372d92010-06-11 09:15:55 -0700259 }
260 if (set_raw) {
vbendebf7a45cc2010-06-21 08:44:16 -0700261 entry->attrs.fields.gpt_att = raw_value;
Bill Richardsonf1372d92010-06-11 09:15:55 -0700262 } else {
263 if (set_successful)
264 SetSuccessful(&drive.gpt, PRIMARY, index, successful);
265 if (set_tries)
266 SetTries(&drive.gpt, PRIMARY, index, tries);
267 if (set_priority)
268 SetPriority(&drive.gpt, PRIMARY, index, priority);
269 }
270
271 RepairEntries(&drive.gpt, MASK_PRIMARY);
272 RepairHeader(&drive.gpt, MASK_PRIMARY);
273
274 drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
275 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
276 UpdateCrc(&drive.gpt);
277
278
279 // Write it all out
280 return DriveClose(&drive, 1);
281
282bad:
283 (void) DriveClose(&drive, 0);
284 return CGPT_FAILED;
285}