2 * Copyright (c) 2002 Marcel Moolenaar
4 * Copyright (c) 2020 The DragonFly Project. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/types.h>
39 static void expand(int fd);
42 cmd_expand(int argc, char *argv[])
47 fprintf(stderr, "usage: gpt expand <device>...\n");
50 while (optind < argc) {
51 fd = gpt_open(argv[optind++]);
53 warn("unable to open device '%s'", device_name);
65 expand(int fd __unused)
83 pmbr = map_find(MAP_TYPE_PMBR);
85 warnx("%s: error: no PMBR to expand", device_name);
91 last = mediasz / secsz - 1LL;
93 gpt = map_find(MAP_TYPE_PRI_GPT_HDR);
95 warnx("%s: error: no primary GPT header; run create or recover",
99 tbl = map_find(MAP_TYPE_PRI_GPT_TBL);
101 warnx("%s: error: no primary partition table; "
102 "run create or recover",
106 blocks = tbl->map_size;
109 * Since the device may have changed size, gpt might not be able to
110 * find the backup table. Just ignore anytying we scanned and
111 * create new maps for the secondary gpt and table.
113 gpt2 = mkmap(last, 1LL, MAP_TYPE_SEC_GPT_HDR);
114 gpt2->map_data = calloc(1, secsz);
116 tbl2 = mkmap(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL);
117 tbl2->map_data = tbl->map_data;
122 if (last > 0xffffffff) {
123 mbr->mbr_part[0].part_size_lo = htole16(0xffff);
124 mbr->mbr_part[0].part_size_hi = htole16(0xffff);
126 mbr->mbr_part[0].part_size_lo = htole16(last);
127 mbr->mbr_part[0].part_size_hi = htole16(last >> 16);
131 * Calculate expansion size
133 * Update the primary gpt header, adjusting the pointer to the
137 delta = last - hdr->hdr_lba_alt;
138 hdr->hdr_lba_alt = htole64(last);
141 * Update the secondary gpt header.
144 printf("gpt already expanded to full device size\n");
146 printf("Expand GPT by %jd blocks\n", (intmax_t)delta);
150 * Create the secondary gpt header
152 hdr = gpt2->map_data;
153 *hdr = *(struct gpt_hdr *)gpt->map_data;
155 hdr->hdr_lba_self = htole64(gpt2->map_start);
156 hdr->hdr_lba_table = htole64(tbl2->map_start);
157 hdr->hdr_lba_alt = htole64(1);
161 for (i = 0; i < le32toh(hdr->hdr_entries); ++i) {
162 ent = (void *)((char *)tbl->map_data + i *
163 le32toh(hdr->hdr_entsz));
164 if (uuid_is_nil(&ent->ent_type, NULL))
170 hdr = gpt2->map_data;
173 uuid_to_string(&ent->ent_type, &name, NULL);
174 nblocks = last - blocks - le64toh(lent->ent_lba_start);
175 nblocks = (nblocks * secsz / (1024 * 1024)) * 1024 * 1024 /
178 if (le64toh(lent->ent_lba_end) ==
179 le64toh(lent->ent_lba_start) + nblocks - 1) {
180 printf("entry %d type=%s %ld,%ld unchanged\n",
182 le64toh(lent->ent_lba_start),
183 le64toh(lent->ent_lba_end));
185 printf("expand entry %d type=%s %ld,%ld to %ld\n",
187 le64toh(lent->ent_lba_start),
188 le64toh(lent->ent_lba_end),
189 le64toh(lent->ent_lba_start) + nblocks - 1);
190 lent->ent_lba_end = htole64(
191 le64toh(lent->ent_lba_start) +
200 hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
201 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
202 hdr->hdr_crc_self = 0;
203 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
205 hdr = gpt2->map_data;
206 hdr->hdr_crc_table = htole32(crc32(tbl2->map_data,
207 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
208 hdr->hdr_crc_self = 0;
209 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
212 * NOTE! We don't even try to manage the in-memory media links
213 * and tbl2's data is the same pointer as tbl's data. Don't
214 * try to clean up here or be fancy.
216 gpt_write(fd, tbl2); /* secondary partition table */
217 gpt_write(fd, gpt2); /* secondary header */
218 gpt_write(fd, gpt); /* primary partition table */
219 gpt_write(fd, tbl); /* primary header */
220 gpt_write(fd, pmbr); /* primary header */