]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/gpt.c
isosize: avoid reading more data than what is needed
[thirdparty/util-linux.git] / libfdisk / src / gpt.c
CommitLineData
5dbff4c0 1/*
766d5156
DB
2 * Copyright (C) 2007 Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
4 *
5 * GUID Partition Table (GPT) support. Based on UEFI Specs 2.3.1
6 * Chapter 5: GUID Partition Table (GPT) Disk Layout (Jun 27th, 2012).
7 * Some ideas and inspiration from GNU parted and gptfdisk.
5dbff4c0 8 */
5dbff4c0
KZ
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <inttypes.h>
13#include <sys/stat.h>
5dbff4c0
KZ
14#include <sys/utsname.h>
15#include <sys/types.h>
16#include <fcntl.h>
17#include <unistd.h>
18#include <errno.h>
766d5156
DB
19#include <ctype.h>
20#include <uuid.h>
5dbff4c0 21
62d50bbe
KZ
22#include "fdiskP.h"
23
766d5156 24#include "crc32.h"
810f986b 25#include "blkdev.h"
9eca9d0d 26#include "bitops.h"
766d5156 27#include "strutils.h"
19613111 28#include "all-io.h"
3457d90e 29#include "pt-mbr.h"
766d5156 30
0077e7cd
KZ
31/**
32 * SECTION: gpt
705854f3
KZ
33 * @title: UEFI GPT
34 * @short_description: specific functionality
0077e7cd
KZ
35 */
36
766d5156
DB
37#define GPT_HEADER_SIGNATURE 0x5452415020494645LL /* EFI PART */
38#define GPT_HEADER_REVISION_V1_02 0x00010200
39#define GPT_HEADER_REVISION_V1_00 0x00010000
40#define GPT_HEADER_REVISION_V0_99 0x00009900
e9bf0935 41#define GPT_HEADER_MINSZ 92 /* bytes */
766d5156
DB
42
43#define GPT_PMBR_LBA 0
44#define GPT_MBR_PROTECTIVE 1
45#define GPT_MBR_HYBRID 2
46
0a7cdf80 47#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001ULL
766d5156
DB
48
49#define EFI_PMBR_OSTYPE 0xEE
50#define MSDOS_MBR_SIGNATURE 0xAA55
e39966c6 51#define GPT_PART_NAME_LEN (72 / sizeof(uint16_t))
74760053 52#define GPT_NPARTITIONS FDISK_GPT_NPARTITIONS_DEFAULT
766d5156
DB
53
54/* Globally unique identifier */
55struct gpt_guid {
56 uint32_t time_low;
57 uint16_t time_mid;
58 uint16_t time_hi_and_version;
59 uint8_t clock_seq_hi;
60 uint8_t clock_seq_low;
61 uint8_t node[6];
62};
63
64
65/* only checking that the GUID is 0 is enough to verify an empty partition. */
66#define GPT_UNUSED_ENTRY_GUID \
67 ((struct gpt_guid) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
68 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
69
70/* Linux native partition type */
c0d14b09 71#define GPT_DEFAULT_ENTRY_TYPE "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
766d5156
DB
72
73/*
74 * Attribute bits
75 */
01086b80
KZ
76enum {
77 /* UEFI specific */
78 GPT_ATTRBIT_REQ = 0,
79 GPT_ATTRBIT_NOBLOCK = 1,
80 GPT_ATTRBIT_LEGACY = 2,
81
82 /* GUID specific (range 48..64)*/
83 GPT_ATTRBIT_GUID_FIRST = 48,
84 GPT_ATTRBIT_GUID_COUNT = 16
85};
c83f772e 86
d1b7bfe5
SR
87#define GPT_ATTRSTR_REQ "RequiredPartition"
88#define GPT_ATTRSTR_REQ_TYPO "RequiredPartiton"
01086b80
KZ
89#define GPT_ATTRSTR_NOBLOCK "NoBlockIOProtocol"
90#define GPT_ATTRSTR_LEGACY "LegacyBIOSBootable"
c83f772e 91
766d5156
DB
92/* The GPT Partition entry array contains an array of GPT entries. */
93struct gpt_entry {
d45fa25d
KZ
94 struct gpt_guid type; /* purpose and type of the partition */
95 struct gpt_guid partition_guid;
766d5156
DB
96 uint64_t lba_start;
97 uint64_t lba_end;
01086b80 98 uint64_t attrs;
d45fa25d 99 uint16_t name[GPT_PART_NAME_LEN];
766d5156
DB
100} __attribute__ ((packed));
101
102/* GPT header */
103struct gpt_header {
104 uint64_t signature; /* header identification */
105 uint32_t revision; /* header version */
106 uint32_t size; /* in bytes */
107 uint32_t crc32; /* header CRC checksum */
108 uint32_t reserved1; /* must be 0 */
9ed38607 109 uint64_t my_lba; /* LBA of block that contains this struct (LBA 1) */
766d5156
DB
110 uint64_t alternative_lba; /* backup GPT header */
111 uint64_t first_usable_lba; /* first usable logical block for partitions */
112 uint64_t last_usable_lba; /* last usable logical block for partitions */
3f731001 113 struct gpt_guid disk_guid; /* unique disk identifier */
9ed38607 114 uint64_t partition_entry_lba; /* LBA of start of partition entries array */
766d5156
DB
115 uint32_t npartition_entries; /* total partition entries - normally 128 */
116 uint32_t sizeof_partition_entry; /* bytes for each GUID pt */
117 uint32_t partition_entry_array_crc32; /* partition CRC checksum */
9ed38607 118 uint8_t reserved2[512 - 92]; /* must all be 0 */
766d5156
DB
119} __attribute__ ((packed));
120
121struct gpt_record {
122 uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */
123 uint8_t start_head; /* unused by EFI, pt start in CHS */
124 uint8_t start_sector; /* unused by EFI, pt start in CHS */
125 uint8_t start_track;
126 uint8_t os_type; /* EFI and legacy non-EFI OS types */
127 uint8_t end_head; /* unused by EFI, pt end in CHS */
128 uint8_t end_sector; /* unused by EFI, pt end in CHS */
129 uint8_t end_track; /* unused by EFI, pt end in CHS */
130 uint32_t starting_lba; /* used by EFI - start addr of the on disk pt */
131 uint32_t size_in_lba; /* used by EFI - size of pt in LBA */
132} __attribute__ ((packed));
133
134/* Protected MBR and legacy MBR share same structure */
135struct gpt_legacy_mbr {
136 uint8_t boot_code[440];
137 uint32_t unique_mbr_signature;
138 uint16_t unknown;
139 struct gpt_record partition_record[4];
140 uint16_t signature;
141} __attribute__ ((packed));
142
143/*
144 * Here be dragons!
145 * See: http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs
146 */
147#define DEF_GUID(_u, _n) \
148 { \
149 .typestr = (_u), \
150 .name = (_n), \
151 }
152
5aa8d13b
KZ
153/* Probably the most complete list of the GUIDs are at:
154 * https://wikipedia.org/wiki/GUID_Partition_Table
155 */
766d5156
DB
156static struct fdisk_parttype gpt_parttypes[] =
157{
158 /* Generic OS */
159 DEF_GUID("C12A7328-F81F-11D2-BA4B-00A0C93EC93B", N_("EFI System")),
160
161 DEF_GUID("024DEE41-33E7-11D3-9D69-0008C781F39F", N_("MBR partition scheme")),
ae488940
KZ
162 DEF_GUID("D3BFE2DE-3DAF-11DF-BA40-E3A556D89593", N_("Intel Fast Flash")),
163
766d5156 164 /* Hah!IdontneedEFI */
5a1b4999 165 DEF_GUID("21686148-6449-6E6F-744E-656564454649", N_("BIOS boot")),
766d5156 166
5aa8d13b
KZ
167 /* NIH syndrome */
168 DEF_GUID("F4019732-066E-4E12-8273-346C5641494F", N_("Sony boot partition")),
169 DEF_GUID("BFBFAFE7-A34F-448A-9A5B-6213EB736C22", N_("Lenovo boot partition")),
170
171 /* PowerPC reference platform boot partition */
172 DEF_GUID("9E1A2D38-C612-4316-AA26-8B49521E5A8B", N_("PowerPC PReP boot")),
173
174 /* Open Network Install Environment */
175 DEF_GUID("7412F7D5-A156-4B13-81DC-867174929325", N_("ONIE boot")),
176 DEF_GUID("D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149", N_("ONIE config")),
177
766d5156
DB
178 /* Windows */
179 DEF_GUID("E3C9E316-0B5C-4DB8-817D-F92DF00215AE", N_("Microsoft reserved")),
180 DEF_GUID("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", N_("Microsoft basic data")),
181 DEF_GUID("5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", N_("Microsoft LDM metadata")),
182 DEF_GUID("AF9B60A0-1431-4F62-BC68-3311714A69AD", N_("Microsoft LDM data")),
0d0d12ad 183 DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery environment")),
766d5156 184 DEF_GUID("37AFFC90-EF7D-4E96-91C3-2D7AE055B174", N_("IBM General Parallel Fs")),
210d4595 185 DEF_GUID("E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", N_("Microsoft Storage Spaces")),
766d5156
DB
186
187 /* HP-UX */
5a1b4999
KZ
188 DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data")),
189 DEF_GUID("E2A1E728-32E3-11D6-A682-7B03A0000000", N_("HP-UX service")),
766d5156 190
5a1b4999
KZ
191 /* Linux (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec) */
192 DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")),
766d5156 193 DEF_GUID("0FC63DAF-8483-4772-8E79-3D69D8477DE4", N_("Linux filesystem")),
5a1b4999
KZ
194 DEF_GUID("3B8F8425-20E0-4F3B-907F-1A25A76F98E8", N_("Linux server data")),
195 DEF_GUID("44479540-F297-41B2-9AF7-D131D5F0458A", N_("Linux root (x86)")),
4b7248c0 196 DEF_GUID("69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", N_("Linux root (ARM)")),
5a1b4999 197 DEF_GUID("4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", N_("Linux root (x86-64)")),
4b7248c0 198 DEF_GUID("B921B045-1DF0-41C3-AF44-4C6F280D3FAE", N_("Linux root (ARM-64)")),
f136260a 199 DEF_GUID("993D8D3D-F80E-4225-855A-9DAF8ED7EA97", N_("Linux root (IA-64)")),
5a1b4999
KZ
200 DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")),
201 DEF_GUID("933AC7E1-2EB4-4F13-B844-0E14E2AEF915", N_("Linux home")),
766d5156 202 DEF_GUID("A19D880F-05FC-4D3B-A006-743F0F84911E", N_("Linux RAID")),
5a1b4999 203 DEF_GUID("BC13C2FF-59E6-4262-A352-B275FD6F7172", N_("Linux extended boot")),
766d5156 204 DEF_GUID("E6D6D379-F507-44C2-A23C-238F2A3DF928", N_("Linux LVM")),
5aa8d13b
KZ
205 /* ... too crazy, ignore for now:
206 DEF_GUID("7FFEC5C9-2D00-49B7-8941-3EA10A5586B7", N_("Linux plain dm-crypt")),
207 DEF_GUID("CA7D7CCB-63ED-4C53-861C-1742536059CC", N_("Linux LUKS")),
208 */
766d5156 209
e9bf0935 210 /* FreeBSD */
766d5156
DB
211 DEF_GUID("516E7CB4-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD data")),
212 DEF_GUID("83BD6B9D-7F41-11DC-BE0B-001560B84F0F", N_("FreeBSD boot")),
213 DEF_GUID("516E7CB5-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD swap")),
214 DEF_GUID("516E7CB6-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD UFS")),
215 DEF_GUID("516E7CBA-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD ZFS")),
216 DEF_GUID("516E7CB8-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD Vinum")),
217
218 /* Apple OSX */
219 DEF_GUID("48465300-0000-11AA-AA11-00306543ECAC", N_("Apple HFS/HFS+")),
220 DEF_GUID("55465300-0000-11AA-AA11-00306543ECAC", N_("Apple UFS")),
221 DEF_GUID("52414944-0000-11AA-AA11-00306543ECAC", N_("Apple RAID")),
222 DEF_GUID("52414944-5F4F-11AA-AA11-00306543ECAC", N_("Apple RAID offline")),
223 DEF_GUID("426F6F74-0000-11AA-AA11-00306543ECAC", N_("Apple boot")),
224 DEF_GUID("4C616265-6C00-11AA-AA11-00306543ECAC", N_("Apple label")),
225 DEF_GUID("5265636F-7665-11AA-AA11-00306543ECAC", N_("Apple TV recovery")),
226 DEF_GUID("53746F72-6167-11AA-AA11-00306543ECAC", N_("Apple Core storage")),
227
228 /* Solaris */
229 DEF_GUID("6A82CB45-1DD2-11B2-99A6-080020736631", N_("Solaris boot")),
230 DEF_GUID("6A85CF4D-1DD2-11B2-99A6-080020736631", N_("Solaris root")),
231 /* same as Apple ZFS */
232 DEF_GUID("6A898CC3-1DD2-11B2-99A6-080020736631", N_("Solaris /usr & Apple ZFS")),
233 DEF_GUID("6A87C46F-1DD2-11B2-99A6-080020736631", N_("Solaris swap")),
234 DEF_GUID("6A8B642B-1DD2-11B2-99A6-080020736631", N_("Solaris backup")),
235 DEF_GUID("6A8EF2E9-1DD2-11B2-99A6-080020736631", N_("Solaris /var")),
236 DEF_GUID("6A90BA39-1DD2-11B2-99A6-080020736631", N_("Solaris /home")),
237 DEF_GUID("6A9283A5-1DD2-11B2-99A6-080020736631", N_("Solaris alternate sector")),
238 DEF_GUID("6A945A3B-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 1")),
239 DEF_GUID("6A9630D1-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 2")),
240 DEF_GUID("6A980767-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 3")),
241 DEF_GUID("6A96237F-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 4")),
242 DEF_GUID("6A8D2AC7-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 5")),
243
244 /* NetBSD */
245 DEF_GUID("49F48D32-B10E-11DC-B99B-0019D1879648", N_("NetBSD swap")),
246 DEF_GUID("49F48D5A-B10E-11DC-B99B-0019D1879648", N_("NetBSD FFS")),
247 DEF_GUID("49F48D82-B10E-11DC-B99B-0019D1879648", N_("NetBSD LFS")),
248 DEF_GUID("2DB519C4-B10E-11DC-B99B-0019D1879648", N_("NetBSD concatenated")),
249 DEF_GUID("2DB519EC-B10E-11DC-B99B-0019D1879648", N_("NetBSD encrypted")),
250 DEF_GUID("49F48DAA-B10E-11DC-B99B-0019D1879648", N_("NetBSD RAID")),
251
252 /* ChromeOS */
253 DEF_GUID("FE3A2A5D-4F32-41A7-B725-ACCC3285A309", N_("ChromeOS kernel")),
254 DEF_GUID("3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", N_("ChromeOS root fs")),
255 DEF_GUID("2E0A753D-9E48-43B0-8337-B15192CB1B5E", N_("ChromeOS reserved")),
256
257 /* MidnightBSD */
258 DEF_GUID("85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD data")),
259 DEF_GUID("85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD boot")),
260 DEF_GUID("85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD swap")),
5adcb6c7 261 DEF_GUID("0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD UFS")),
766d5156
DB
262 DEF_GUID("85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD ZFS")),
263 DEF_GUID("85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD Vinum")),
b8d07d9b 264
5aa8d13b
KZ
265 /* Ceph */
266 DEF_GUID("45B0969E-9B03-4F30-B4C6-B4B80CEFF106", N_("Ceph Journal")),
267 DEF_GUID("45B0969E-9B03-4F30-B4C6-5EC00CEFF106", N_("Ceph Encrypted Journal")),
268 DEF_GUID("4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D", N_("Ceph OSD")),
269 DEF_GUID("4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D", N_("Ceph crypt OSD")),
270 DEF_GUID("89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE", N_("Ceph disk in creation")),
271 DEF_GUID("89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE", N_("Ceph crypt disk in creation")),
272
273 /* OpenBSD */
274 DEF_GUID("824CC7A0-36A8-11E3-890A-952519AD3F61", N_("OpenBSD data")),
275
276 /* QNX */
277 DEF_GUID("CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1", N_("QNX6 file system")),
278
279 /* Plan 9 */
280 DEF_GUID("C91818F9-8025-47AF-89D2-F030D7000C2C", N_("Plan 9 partition"))
766d5156
DB
281};
282
d71ef5a4 283/* gpt_entry macros */
874aa9c3
KZ
284#define gpt_partition_start(_e) le64_to_cpu((_e)->lba_start)
285#define gpt_partition_end(_e) le64_to_cpu((_e)->lba_end)
286
d71ef5a4
KZ
287/*
288 * in-memory fdisk GPT stuff
289 */
290struct fdisk_gpt_label {
291 struct fdisk_label head; /* generic part */
292
293 /* gpt specific part */
294 struct gpt_header *pheader; /* primary header */
295 struct gpt_header *bheader; /* backup header */
b28df75e
KZ
296
297 unsigned char *ents; /* entries (partitions) */
d71ef5a4
KZ
298};
299
300static void gpt_deinit(struct fdisk_label *lb);
301
9ffeb235 302static inline struct fdisk_gpt_label *self_label(struct fdisk_context *cxt)
d71ef5a4 303{
d71ef5a4
KZ
304 return (struct fdisk_gpt_label *) cxt->label;
305}
306
874aa9c3
KZ
307/*
308 * Returns the partition length, or 0 if end is before beginning.
309 */
310static uint64_t gpt_partition_size(const struct gpt_entry *e)
311{
312 uint64_t start = gpt_partition_start(e);
313 uint64_t end = gpt_partition_end(e);
314
315 return start > end ? 0 : end - start + 1ULL;
316}
317
c0d14b09 318/* prints UUID in the real byte order! */
88141067 319static void gpt_debug_uuid(const char *mesg, struct gpt_guid *guid)
c0d14b09
KZ
320{
321 const unsigned char *uuid = (unsigned char *) guid;
322
323 fprintf(stderr, "%s: "
324 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
325 mesg,
326 uuid[0], uuid[1], uuid[2], uuid[3],
327 uuid[4], uuid[5],
328 uuid[6], uuid[7],
329 uuid[8], uuid[9],
330 uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
331}
c0d14b09 332
766d5156
DB
333/*
334 * UUID is traditionally 16 byte big-endian array, except Intel EFI
335 * specification where the UUID is a structure of little-endian fields.
336 */
337static void swap_efi_guid(struct gpt_guid *uid)
338{
339 uid->time_low = swab32(uid->time_low);
340 uid->time_mid = swab16(uid->time_mid);
341 uid->time_hi_and_version = swab16(uid->time_hi_and_version);
5dbff4c0
KZ
342}
343
c0d14b09 344static int string_to_guid(const char *in, struct gpt_guid *guid)
766d5156 345{
4044d244
KZ
346 if (uuid_parse(in, (unsigned char *) guid)) { /* BE */
347 DBG(LABEL, ul_debug("GPT: failed to parse GUID: %s", in));
348 return -EINVAL;
349 }
c0d14b09 350 swap_efi_guid(guid); /* LE */
766d5156
DB
351 return 0;
352}
353
7f539277 354static char *guid_to_string(const struct gpt_guid *guid, char *out)
766d5156 355{
c0d14b09
KZ
356 struct gpt_guid u = *guid; /* LE */
357
358 swap_efi_guid(&u); /* BE */
359 uuid_unparse_upper((unsigned char *) &u, out);
360
46667ba4 361 return out;
766d5156
DB
362}
363
7f539277
KZ
364static struct fdisk_parttype *gpt_partition_parttype(
365 struct fdisk_context *cxt,
366 const struct gpt_entry *e)
367{
368 struct fdisk_parttype *t;
369 char str[37];
92e486f8 370 struct gpt_guid guid = e->type;
7f539277 371
92e486f8 372 guid_to_string(&guid, str);
a745611d 373 t = fdisk_label_get_parttype_from_string(cxt->label, str);
7f539277
KZ
374 return t ? : fdisk_new_unknown_parttype(0, str);
375}
376
b0a484a8
KZ
377static void gpt_entry_set_type(struct gpt_entry *e, struct gpt_guid *uuid)
378{
379 e->type = *uuid;
92e486f8 380 DBG(LABEL, gpt_debug_uuid("new type", uuid));
b0a484a8
KZ
381}
382
383static void gpt_entry_set_name(struct gpt_entry *e, char *str)
384{
385 char name[GPT_PART_NAME_LEN] = { 0 };
386 size_t i, sz = strlen(str);
387
388 if (sz) {
389 if (sz > GPT_PART_NAME_LEN)
390 sz = GPT_PART_NAME_LEN;
391 memcpy(name, str, sz);
392 }
393
394 for (i = 0; i < GPT_PART_NAME_LEN; i++)
395 e->name[i] = cpu_to_le16((uint16_t) name[i]);
396}
397
398static int gpt_entry_set_uuid(struct gpt_entry *e, char *str)
399{
400 struct gpt_guid uuid;
401 int rc;
402
403 rc = string_to_guid(str, &uuid);
404 if (rc)
405 return rc;
406
407 e->partition_guid = uuid;
408 return 0;
409}
7f539277 410
02a376f2
KZ
411static inline int gpt_entry_is_used(const struct gpt_entry *e)
412{
413 return memcmp(&e->type, &GPT_UNUSED_ENTRY_GUID,
414 sizeof(struct gpt_guid)) != 0;
415}
416
7f539277 417
766d5156
DB
418static const char *gpt_get_header_revstr(struct gpt_header *header)
419{
420 if (!header)
421 goto unknown;
422
43a2b094 423 switch (le32_to_cpu(header->revision)) {
766d5156
DB
424 case GPT_HEADER_REVISION_V1_02:
425 return "1.2";
426 case GPT_HEADER_REVISION_V1_00:
427 return "1.0";
428 case GPT_HEADER_REVISION_V0_99:
429 return "0.99";
430 default:
431 goto unknown;
432 }
433
434unknown:
435 return "unknown";
436}
437
b28df75e
KZ
438static inline unsigned char *gpt_get_entry_ptr(struct fdisk_gpt_label *gpt, size_t i)
439{
440 return gpt->ents + le32_to_cpu(gpt->pheader->sizeof_partition_entry) * i;
441}
442
443static inline struct gpt_entry *gpt_get_entry(struct fdisk_gpt_label *gpt, size_t i)
444{
445 return (struct gpt_entry *) gpt_get_entry_ptr(gpt, i);
446}
447
448static inline struct gpt_entry *gpt_zeroize_entry(struct fdisk_gpt_label *gpt, size_t i)
449{
450 return (struct gpt_entry *) memset(gpt_get_entry_ptr(gpt, i),
451 0, le32_to_cpu(gpt->pheader->sizeof_partition_entry));
452}
453
b683c081
KZ
454/* Use to access array of entries, for() loops, etc. But don't use when
455 * you directly do something with GPT header, then use uint32_t.
456 */
457static inline size_t gpt_get_nentries(struct fdisk_gpt_label *gpt)
458{
459 return (size_t) le32_to_cpu(gpt->pheader->npartition_entries);
460}
461
9e320545
KZ
462static inline int gpt_calculate_sizeof_ents(struct gpt_header *hdr, uint32_t nents, size_t *sz)
463{
464 uint32_t esz = le32_to_cpu(hdr->sizeof_partition_entry);
465
466 if (nents == 0 || esz == 0 || SIZE_MAX/esz < nents) {
467 DBG(LABEL, ul_debug("GPT entreis array size check failed"));
468 return -ERANGE;
469 }
470
471 *sz = nents * esz;
472 return 0;
473}
474
475static inline int gpt_sizeof_ents(struct gpt_header *hdr, size_t *sz)
476{
477 return gpt_calculate_sizeof_ents(hdr, le32_to_cpu(hdr->npartition_entries), sz);
478}
479
766d5156 480
5989556a
KZ
481static char *gpt_get_header_id(struct gpt_header *header)
482{
483 char str[37];
92e486f8 484 struct gpt_guid guid = header->disk_guid;
5989556a 485
92e486f8 486 guid_to_string(&guid, str);
5989556a
KZ
487
488 return strdup(str);
489}
490
3f731001
DB
491/*
492 * Builds a clean new valid protective MBR - will wipe out any existing data.
493 * Returns 0 on success, otherwise < 0 on error.
494 */
495static int gpt_mknew_pmbr(struct fdisk_context *cxt)
496{
497 struct gpt_legacy_mbr *pmbr = NULL;
7c2cfb18 498 int rc;
3f731001
DB
499
500 if (!cxt || !cxt->firstsector)
501 return -ENOSYS;
502
3457d90e
KZ
503 if (fdisk_has_protected_bootbits(cxt))
504 rc = fdisk_init_firstsector_buffer(cxt, 0, MBR_PT_BOOTBITS_SIZE);
505 else
506 rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
7c2cfb18
KZ
507 if (rc)
508 return rc;
3f731001
DB
509
510 pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
511
512 pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE);
513 pmbr->partition_record[0].os_type = EFI_PMBR_OSTYPE;
514 pmbr->partition_record[0].start_sector = 1;
515 pmbr->partition_record[0].end_head = 0xFE;
516 pmbr->partition_record[0].end_sector = 0xFF;
517 pmbr->partition_record[0].end_track = 0xFF;
518 pmbr->partition_record[0].starting_lba = cpu_to_le32(1);
519 pmbr->partition_record[0].size_in_lba =
0a7cdf80 520 cpu_to_le32((uint32_t) min( cxt->total_sectors - 1ULL, 0xFFFFFFFFULL) );
3f731001
DB
521
522 return 0;
523}
524
525/* some universal differences between the headers */
526static void gpt_mknew_header_common(struct fdisk_context *cxt,
527 struct gpt_header *header, uint64_t lba)
528{
529 if (!cxt || !header)
530 return;
531
532 header->my_lba = cpu_to_le64(lba);
533
534 if (lba == GPT_PRIMARY_PARTITION_TABLE_LBA) { /* primary */
0a7cdf80
KZ
535 header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1ULL);
536 header->partition_entry_lba = cpu_to_le64(2ULL);
3f731001 537 } else { /* backup */
5eaeb585
KZ
538 uint64_t esz = (uint64_t) le32_to_cpu(header->npartition_entries)
539 * sizeof(struct gpt_entry);
3f731001
DB
540 uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size;
541
542 header->alternative_lba = cpu_to_le64(GPT_PRIMARY_PARTITION_TABLE_LBA);
0a7cdf80 543 header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1ULL - esects);
3f731001
DB
544 }
545}
546
547/*
548 * Builds a new GPT header (at sector lba) from a backup header2.
549 * If building a primary header, then backup is the secondary, and vice versa.
550 *
551 * Always pass a new (zeroized) header to build upon as we don't
552 * explicitly zero-set some values such as CRCs and reserved.
553 *
554 * Returns 0 on success, otherwise < 0 on error.
555 */
556static int gpt_mknew_header_from_bkp(struct fdisk_context *cxt,
557 struct gpt_header *header,
558 uint64_t lba,
559 struct gpt_header *header2)
560{
561 if (!cxt || !header || !header2)
562 return -ENOSYS;
563
564 header->signature = header2->signature;
565 header->revision = header2->revision;
566 header->size = header2->size;
567 header->npartition_entries = header2->npartition_entries;
568 header->sizeof_partition_entry = header2->sizeof_partition_entry;
569 header->first_usable_lba = header2->first_usable_lba;
570 header->last_usable_lba = header2->last_usable_lba;
571
572 memcpy(&header->disk_guid,
573 &header2->disk_guid, sizeof(header2->disk_guid));
574 gpt_mknew_header_common(cxt, header, lba);
575
576 return 0;
577}
578
45ddb828
KZ
579static struct gpt_header *gpt_copy_header(struct fdisk_context *cxt,
580 struct gpt_header *src)
581{
582 struct gpt_header *res;
583
584 if (!cxt || !src)
585 return NULL;
586
4bb82a45
KZ
587 assert(cxt->sector_size >= sizeof(struct gpt_header));
588
589 res = calloc(1, cxt->sector_size);
45ddb828
KZ
590 if (!res) {
591 fdisk_warn(cxt, _("failed to allocate GPT header"));
592 return NULL;
593 }
594
595 res->my_lba = src->alternative_lba;
596 res->alternative_lba = src->my_lba;
597
598 res->signature = src->signature;
599 res->revision = src->revision;
600 res->size = src->size;
601 res->npartition_entries = src->npartition_entries;
602 res->sizeof_partition_entry = src->sizeof_partition_entry;
603 res->first_usable_lba = src->first_usable_lba;
604 res->last_usable_lba = src->last_usable_lba;
605
606 memcpy(&res->disk_guid, &src->disk_guid, sizeof(src->disk_guid));
607
608
609 if (res->my_lba == GPT_PRIMARY_PARTITION_TABLE_LBA)
0a7cdf80 610 res->partition_entry_lba = cpu_to_le64(2ULL);
45ddb828 611 else {
5eaeb585 612 uint64_t esz = (uint64_t) le32_to_cpu(src->npartition_entries) * sizeof(struct gpt_entry);
45ddb828
KZ
613 uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size;
614
0a7cdf80 615 res->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1ULL - esects);
45ddb828
KZ
616 }
617
618 return res;
619}
620
b7c67e64
KZ
621static int get_script_u64(struct fdisk_context *cxt, uint64_t *num, const char *name)
622{
623 const char *str;
624 int pwr = 0, rc = 0;
625
626 assert(cxt);
627
628 *num = 0;
629
630 if (!cxt->script)
631 return 1;
632
633 str = fdisk_script_get_header(cxt->script, name);
634 if (!str)
635 return 1;
636
637 rc = parse_size(str, (uintmax_t *) num, &pwr);
638 if (rc < 0)
639 return rc;
640 if (pwr)
641 *num /= cxt->sector_size;
642 return 0;
643}
644
645static int count_first_last_lba(struct fdisk_context *cxt,
1240f549
KZ
646 uint64_t *first, uint64_t *last)
647{
b7c67e64
KZ
648 int rc = 0;
649 uint64_t flba, llba;
650
1240f549
KZ
651 uint64_t esz = 0;
652
653 assert(cxt);
b7c67e64
KZ
654 assert(first);
655 assert(last);
656
657 *first = *last = 0;
1240f549 658
b7c67e64 659 /* UEFI default */
1240f549 660 esz = sizeof(struct gpt_entry) * GPT_NPARTITIONS / cxt->sector_size;
0a7cdf80
KZ
661 llba = cxt->total_sectors - 2ULL - esz;
662 flba = esz + 2ULL;
1240f549 663
b7c67e64
KZ
664 /* script default */
665 if (cxt->script) {
666 rc = get_script_u64(cxt, first, "first-lba");
667 if (rc < 0)
668 return rc;
669
fdbd7bb9
RM
670 DBG(LABEL, ul_debug("FirstLBA: script=%"PRIu64", uefi=%"PRIu64", topology=%ju.",
671 *first, flba, (uintmax_t)cxt->first_lba));
b7c67e64
KZ
672
673 if (rc == 0 && (*first < flba || *first > llba)) {
674 fdisk_warnx(cxt, _("First LBA specified by script is out of range."));
675 return -ERANGE;
676 }
677
678 rc = get_script_u64(cxt, last, "last-lba");
679 if (rc < 0)
680 return rc;
681
fdbd7bb9
RM
682 DBG(LABEL, ul_debug("LastLBA: script=%"PRIu64", uefi=%"PRIu64", topology=%ju.",
683 *last, llba, (uintmax_t)cxt->last_lba));
b7c67e64
KZ
684
685 if (rc == 0 && (*last > llba || *last < flba)) {
686 fdisk_warnx(cxt, _("Last LBA specified by script is out of range."));
687 return -ERANGE;
688 }
689 }
690
691 if (!*last)
692 *last = llba;
693
694 /* default by topology */
695 if (!*first)
696 *first = flba < cxt->first_lba &&
697 cxt->first_lba < *last ? cxt->first_lba : flba;
698 return 0;
1240f549
KZ
699}
700
3f731001
DB
701/*
702 * Builds a clean new GPT header (currently under revision 1.0).
703 *
704 * Always pass a new (zeroized) header to build upon as we don't
705 * explicitly zero-set some values such as CRCs and reserved.
706 *
707 * Returns 0 on success, otherwise < 0 on error.
708 */
709static int gpt_mknew_header(struct fdisk_context *cxt,
710 struct gpt_header *header, uint64_t lba)
711{
1240f549 712 uint64_t first, last;
b7c67e64 713 int has_id = 0, rc;
3f731001
DB
714
715 if (!cxt || !header)
716 return -ENOSYS;
717
3f731001
DB
718 header->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
719 header->revision = cpu_to_le32(GPT_HEADER_REVISION_V1_00);
4bb82a45
KZ
720
721 /* According to EFI standard it's valid to count all the first
722 * sector into header size, but some tools may have a problem
9e930041 723 * to accept it, so use the header without the zeroed area.
4bb82a45
KZ
724 * This does not have any impact to CRC, etc. --kzak Jan-2015
725 */
726 header->size = cpu_to_le32(sizeof(struct gpt_header)
727 - sizeof(header->reserved2));
3f731001
DB
728
729 /*
09af3db4 730 * 128 partitions are the default. It can go beyond that, but
3f731001
DB
731 * we're creating a de facto header here, so no funny business.
732 */
733 header->npartition_entries = cpu_to_le32(GPT_NPARTITIONS);
734 header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry));
b4184690 735
b7c67e64
KZ
736 rc = count_first_last_lba(cxt, &first, &last);
737 if (rc)
738 return rc;
739
b4184690
KZ
740 header->first_usable_lba = cpu_to_le64(first);
741 header->last_usable_lba = cpu_to_le64(last);
3f731001
DB
742
743 gpt_mknew_header_common(cxt, header, lba);
3f731001 744
4b43f7c9
KZ
745 if (cxt->script) {
746 const char *id = fdisk_script_get_header(cxt->script, "label-id");
92e486f8
RM
747 struct gpt_guid guid = header->disk_guid;
748 if (id && string_to_guid(id, &guid) == 0)
4b43f7c9 749 has_id = 1;
92e486f8 750 header->disk_guid = guid;
4b43f7c9
KZ
751 }
752
753 if (!has_id) {
92e486f8
RM
754 struct gpt_guid guid;
755
4b43f7c9 756 uuid_generate_random((unsigned char *) &header->disk_guid);
92e486f8
RM
757 guid = header->disk_guid;
758 swap_efi_guid(&guid);
4b43f7c9 759 }
3f731001
DB
760 return 0;
761}
762
766d5156
DB
763/*
764 * Checks if there is a valid protective MBR partition table.
765 * Returns 0 if it is invalid or failure. Otherwise, return
9e930041 766 * GPT_MBR_PROTECTIVE or GPT_MBR_HYBRID, depending on the detection.
766d5156
DB
767 */
768static int valid_pmbr(struct fdisk_context *cxt)
769{
879fadf1 770 int i, part = 0, ret = 0; /* invalid by default */
766d5156
DB
771 struct gpt_legacy_mbr *pmbr = NULL;
772
773 if (!cxt->firstsector)
774 goto done;
775
776 pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
777
f67c524e 778 if (le16_to_cpu(pmbr->signature) != MSDOS_MBR_SIGNATURE)
766d5156
DB
779 goto done;
780
766d5156 781 /* seems like a valid MBR was found, check DOS primary partitions */
f67c524e 782 for (i = 0; i < 4; i++) {
766d5156
DB
783 if (pmbr->partition_record[i].os_type == EFI_PMBR_OSTYPE) {
784 /*
785 * Ok, we at least know that there's a protective MBR,
786 * now check if there are other partition types for
787 * hybrid MBR.
788 */
879fadf1 789 part = i;
766d5156 790 ret = GPT_MBR_PROTECTIVE;
c6bf5c09 791 break;
766d5156 792 }
f67c524e 793 }
ac920fed 794
766d5156
DB
795 if (ret != GPT_MBR_PROTECTIVE)
796 goto done;
c6bf5c09
MM
797
798 /* LBA of the GPT partition header */
799 if (pmbr->partition_record[part].starting_lba !=
800 cpu_to_le32(GPT_PRIMARY_PARTITION_TABLE_LBA))
801 goto done;
802
f67c524e 803 for (i = 0 ; i < 4; i++) {
766d5156
DB
804 if ((pmbr->partition_record[i].os_type != EFI_PMBR_OSTYPE) &&
805 (pmbr->partition_record[i].os_type != 0x00))
806 ret = GPT_MBR_HYBRID;
f67c524e 807 }
766d5156
DB
808
809 /*
810 * Protective MBRs take up the lesser of the whole disk
811 * or 2 TiB (32bit LBA), ignoring the rest of the disk.
1fd10841
DB
812 * Some partitioning programs, nonetheless, choose to set
813 * the size to the maximum 32-bit limitation, disregarding
814 * the disk size.
766d5156
DB
815 *
816 * Hybrid MBRs do not necessarily comply with this.
59db52ad
KZ
817 *
818 * Consider a bad value here to be a warning to support dd-ing
819 * an image from a smaller disk to a bigger disk.
766d5156 820 */
f67c524e 821 if (ret == GPT_MBR_PROTECTIVE) {
0a7cdf80
KZ
822 uint64_t sz_lba = (uint64_t) le32_to_cpu(pmbr->partition_record[part].size_in_lba);
823 if (sz_lba != cxt->total_sectors - 1ULL && sz_lba != 0xFFFFFFFFULL) {
824 fdisk_warnx(cxt, _("GPT PMBR size mismatch (%"PRIu64" != %"PRIu64") "
59db52ad 825 "will be corrected by w(rite)."),
0a7cdf80 826 sz_lba, cxt->total_sectors - 1ULL);
1572fb3e 827 fdisk_label_set_changed(cxt->label, 1);
59db52ad 828 }
f67c524e 829 }
766d5156
DB
830done:
831 return ret;
832}
833
834static uint64_t last_lba(struct fdisk_context *cxt)
5dbff4c0 835{
5dbff4c0 836 struct stat s;
cbebd20d 837 uint64_t sectors = 0;
5dbff4c0 838
766d5156
DB
839 memset(&s, 0, sizeof(s));
840 if (fstat(cxt->dev_fd, &s) == -1) {
83df5feb 841 fdisk_warn(cxt, _("gpt: stat() failed"));
5dbff4c0
KZ
842 return 0;
843 }
766d5156 844
5dbff4c0 845 if (S_ISBLK(s.st_mode))
0a7cdf80 846 sectors = cxt->total_sectors - 1ULL;
cbebd20d
KZ
847 else if (S_ISREG(s.st_mode))
848 sectors = ((uint64_t) s.st_size /
849 (uint64_t) cxt->sector_size) - 1ULL;
850 else
83df5feb 851 fdisk_warnx(cxt, _("gpt: cannot handle files with mode %o"), s.st_mode);
cbebd20d 852
fdbd7bb9 853 DBG(LABEL, ul_debug("GPT last LBA: %"PRIu64"", sectors));
cbebd20d 854 return sectors;
5dbff4c0
KZ
855}
856
766d5156
DB
857static ssize_t read_lba(struct fdisk_context *cxt, uint64_t lba,
858 void *buffer, const size_t bytes)
5dbff4c0 859{
766d5156 860 off_t offset = lba * cxt->sector_size;
5dbff4c0 861
bbe8e6a9
KZ
862 if (lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1)
863 return -1;
b9710f1f 864 return (size_t)read(cxt->dev_fd, buffer, bytes) != bytes;
5dbff4c0
KZ
865}
866
766d5156
DB
867
868/* Returns the GPT entry array */
b28df75e 869static unsigned char *gpt_read_entries(struct fdisk_context *cxt,
d71ef5a4 870 struct gpt_header *header)
5dbff4c0 871{
9e320545
KZ
872 size_t sz;
873 ssize_t ssz;
874
b28df75e 875 unsigned char *ret = NULL;
d71ef5a4
KZ
876 off_t offset;
877
878 assert(cxt);
879 assert(header);
880
9e320545 881 if (gpt_sizeof_ents(header, &sz))
f71b96bf 882 return NULL;
f71b96bf 883
a8294f40
KZ
884 if (sz > (size_t) SSIZE_MAX) {
885 DBG(LABEL, ul_debug("GPT entries array too large to read()"));
886 return NULL;
887 }
888
46667ba4 889 ret = calloc(1, sz);
d71ef5a4
KZ
890 if (!ret)
891 return NULL;
9e320545 892
5eaeb585 893 offset = (off_t) le64_to_cpu(header->partition_entry_lba) *
766d5156
DB
894 cxt->sector_size;
895
896 if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
d71ef5a4 897 goto fail;
9e320545
KZ
898
899 ssz = read(cxt->dev_fd, ret, sz);
900 if (ssz < 0 || (size_t) ssz != sz)
d71ef5a4 901 goto fail;
766d5156
DB
902
903 return ret;
d71ef5a4
KZ
904
905fail:
906 free(ret);
907 return NULL;
766d5156
DB
908}
909
7020de0b
KZ
910static inline uint32_t count_crc32(const unsigned char *buf, size_t len,
911 size_t ex_off, size_t ex_len)
766d5156 912{
7f0d4d56 913 return (ul_crc32_exclude_offset(~0L, buf, len, ex_off, ex_len) ^ ~0L);
766d5156
DB
914}
915
7020de0b
KZ
916static inline uint32_t gpt_header_count_crc32(struct gpt_header *header)
917{
918 return count_crc32((unsigned char *) header, /* buffer */
919 le32_to_cpu(header->size), /* size of buffer */
920 offsetof(struct gpt_header, crc32), /* exclude */
921 sizeof(header->crc32)); /* size of excluded area */
922}
923
b28df75e 924static inline uint32_t gpt_entryarr_count_crc32(struct gpt_header *header, unsigned char *ents)
7020de0b
KZ
925{
926 size_t arysz = 0;
927
9e320545
KZ
928 if (gpt_sizeof_ents(header, &arysz))
929 return 0;
7020de0b 930
b28df75e 931 return count_crc32(ents, arysz, 0, 0);
7020de0b
KZ
932}
933
934
766d5156
DB
935/*
936 * Recompute header and partition array 32bit CRC checksums.
937 * This function does not fail - if there's corruption, then it
9e930041 938 * will be reported when checksumming it again (ie: probing or verify).
766d5156 939 */
b28df75e 940static void gpt_recompute_crc(struct gpt_header *header, unsigned char *ents)
766d5156 941{
766d5156
DB
942 if (!header)
943 return;
944
7020de0b
KZ
945 header->partition_entry_array_crc32 =
946 cpu_to_le32( gpt_entryarr_count_crc32(header, ents) );
766d5156 947
7020de0b 948 header->crc32 = cpu_to_le32( gpt_header_count_crc32(header) );
766d5156
DB
949}
950
951/*
952 * Compute the 32bit CRC checksum of the partition table header.
953 * Returns 1 if it is valid, otherwise 0.
954 */
b28df75e 955static int gpt_check_header_crc(struct gpt_header *header, unsigned char *ents)
766d5156 956{
7020de0b
KZ
957 uint32_t orgcrc = le32_to_cpu(header->crc32),
958 crc = gpt_header_count_crc32(header);
766d5156 959
7020de0b 960 if (crc == orgcrc)
d71ef5a4
KZ
961 return 1;
962
766d5156 963 /*
7020de0b
KZ
964 * If we have checksum mismatch it may be due to stale data, like a
965 * partition being added or deleted. Recompute the CRC again and make
966 * sure this is not the case.
766d5156 967 */
d71ef5a4 968 if (ents) {
766d5156 969 gpt_recompute_crc(header, ents);
7020de0b 970 return gpt_header_count_crc32(header) == orgcrc;
d71ef5a4
KZ
971 }
972
973 return 0;
766d5156
DB
974}
975
976/*
977 * It initializes the partition entry array.
978 * Returns 1 if the checksum is valid, otherwise 0.
979 */
b28df75e 980static int gpt_check_entryarr_crc(struct gpt_header *header, unsigned char *ents)
766d5156 981{
d71ef5a4 982 if (!header || !ents)
7020de0b 983 return 0;
766d5156 984
7020de0b
KZ
985 return gpt_entryarr_count_crc32(header, ents) ==
986 le32_to_cpu(header->partition_entry_array_crc32);
766d5156
DB
987}
988
989static int gpt_check_lba_sanity(struct fdisk_context *cxt, struct gpt_header *header)
990{
991 int ret = 0;
992 uint64_t lu, fu, lastlba = last_lba(cxt);
993
994 fu = le64_to_cpu(header->first_usable_lba);
995 lu = le64_to_cpu(header->last_usable_lba);
996
997 /* check if first and last usable LBA make sense */
998 if (lu < fu) {
88141067 999 DBG(LABEL, ul_debug("error: header last LBA is before first LBA"));
766d5156 1000 goto done;
5dbff4c0 1001 }
766d5156
DB
1002
1003 /* check if first and last usable LBAs with the disk's last LBA */
1004 if (fu > lastlba || lu > lastlba) {
88141067 1005 DBG(LABEL, ul_debug("error: header LBAs are after the disk's last LBA"));
766d5156
DB
1006 goto done;
1007 }
1008
1009 /* the header has to be outside usable range */
1010 if (fu < GPT_PRIMARY_PARTITION_TABLE_LBA &&
1011 GPT_PRIMARY_PARTITION_TABLE_LBA < lu) {
88141067 1012 DBG(LABEL, ul_debug("error: header outside of usable range"));
766d5156
DB
1013 goto done;
1014 }
1015
1016 ret = 1; /* sane */
1017done:
1018 return ret;
1019}
1020
1021/* Check if there is a valid header signature */
1022static int gpt_check_signature(struct gpt_header *header)
1023{
1024 return header->signature == cpu_to_le64(GPT_HEADER_SIGNATURE);
1025}
1026
1027/*
1028 * Return the specified GPT Header, or NULL upon failure/invalid.
1029 * Note that all tests must pass to ensure a valid header,
1030 * we do not rely on only testing the signature for a valid probe.
1031 */
d71ef5a4
KZ
1032static struct gpt_header *gpt_read_header(struct fdisk_context *cxt,
1033 uint64_t lba,
b28df75e 1034 unsigned char **_ents)
766d5156
DB
1035{
1036 struct gpt_header *header = NULL;
b28df75e 1037 unsigned char *ents = NULL;
e9bf0935 1038 uint32_t hsz;
766d5156
DB
1039
1040 if (!cxt)
1041 return NULL;
1042
4bb82a45
KZ
1043 /* always allocate all sector, the area after GPT header
1044 * has to be fill by zeros */
1045 assert(cxt->sector_size >= sizeof(struct gpt_header));
1046
1047 header = calloc(1, cxt->sector_size);
46667ba4
KZ
1048 if (!header)
1049 return NULL;
766d5156 1050
d71ef5a4 1051 /* read and verify header */
4bb82a45 1052 if (read_lba(cxt, lba, header, cxt->sector_size) != 0)
766d5156
DB
1053 goto invalid;
1054
1055 if (!gpt_check_signature(header))
1056 goto invalid;
1057
9c6f3de6
KZ
1058 /* make sure header size is between 92 and sector size bytes */
1059 hsz = le32_to_cpu(header->size);
1060 if (hsz < GPT_HEADER_MINSZ || hsz > cxt->sector_size)
1061 goto invalid;
1062
d71ef5a4
KZ
1063 if (!gpt_check_header_crc(header, NULL))
1064 goto invalid;
1065
1066 /* read and verify entries */
1067 ents = gpt_read_entries(cxt, header);
1068 if (!ents)
1069 goto invalid;
1070
1071 if (!gpt_check_entryarr_crc(header, ents))
766d5156
DB
1072 goto invalid;
1073
1074 if (!gpt_check_lba_sanity(cxt, header))
1075 goto invalid;
1076
1077 /* valid header must be at MyLBA */
1078 if (le64_to_cpu(header->my_lba) != lba)
1079 goto invalid;
1080
d71ef5a4
KZ
1081 if (_ents)
1082 *_ents = ents;
1083 else
1084 free(ents);
1085
fdbd7bb9 1086 DBG(LABEL, ul_debug("found valid GPT Header on LBA %"PRIu64"", lba));
766d5156
DB
1087 return header;
1088invalid:
1089 free(header);
d71ef5a4 1090 free(ents);
45ddb828 1091
fdbd7bb9 1092 DBG(LABEL, ul_debug("read GPT Header on LBA %"PRIu64" failed", lba));
766d5156
DB
1093 return NULL;
1094}
1095
775001ad
KZ
1096
1097static int gpt_locate_disklabel(struct fdisk_context *cxt, int n,
9bbcf43f 1098 const char **name, uint64_t *offset, size_t *size)
775001ad
KZ
1099{
1100 struct fdisk_gpt_label *gpt;
1101
1102 assert(cxt);
1103
1104 *name = NULL;
1105 *offset = 0;
1106 *size = 0;
1107
1108 switch (n) {
1109 case 0:
1110 *name = "PMBR";
1111 *offset = 0;
1112 *size = 512;
1113 break;
1114 case 1:
1115 *name = _("GPT Header");
9bbcf43f 1116 *offset = (uint64_t) GPT_PRIMARY_PARTITION_TABLE_LBA * cxt->sector_size;
775001ad
KZ
1117 *size = sizeof(struct gpt_header);
1118 break;
1119 case 2:
1120 *name = _("GPT Entries");
1121 gpt = self_label(cxt);
5eaeb585
KZ
1122 *offset = (uint64_t) le64_to_cpu(gpt->pheader->partition_entry_lba) *
1123 cxt->sector_size;
9e320545 1124 return gpt_sizeof_ents(gpt->pheader, size);
775001ad
KZ
1125 default:
1126 return 1; /* no more chunks */
1127 }
1128
1129 return 0;
1130}
1131
5989556a
KZ
1132static int gpt_get_disklabel_item(struct fdisk_context *cxt, struct fdisk_labelitem *item)
1133{
1134 struct gpt_header *h;
1135 int rc = 0;
1136
1137 assert(cxt);
1138 assert(cxt->label);
1139 assert(fdisk_is_label(cxt, GPT));
1140
1141 h = self_label(cxt)->pheader;
775001ad 1142
5989556a
KZ
1143 switch (item->id) {
1144 case GPT_LABELITEM_ID:
1145 item->name = _("Disk identifier");
1146 item->type = 's';
1147 item->data.str = gpt_get_header_id(h);
1148 if (!item->data.str)
1149 rc = -ENOMEM;
1150 break;
1151 case GPT_LABELITEM_FIRSTLBA:
1152 item->name = _("First LBA");
1153 item->type = 'j';
1154 item->data.num64 = le64_to_cpu(h->first_usable_lba);
1155 break;
1156 case GPT_LABELITEM_LASTLBA:
1157 item->name = _("Last LBA");
1158 item->type = 'j';
1159 item->data.num64 = le64_to_cpu(h->last_usable_lba);
1160 break;
1161 case GPT_LABELITEM_ALTLBA:
1162 /* TRANSLATORS: The LBA (Logical Block Address) of the backup GPT header. */
1163 item->name = _("Alternative LBA");
1164 item->type = 'j';
1165 item->data.num64 = le64_to_cpu(h->alternative_lba);
1166 break;
1167 case GPT_LABELITEM_ENTRIESLBA:
1168 /* TRANSLATORS: The start of the array of partition entries. */
1169 item->name = _("Partition entries LBA");
1170 item->type = 'j';
1171 item->data.num64 = le64_to_cpu(h->partition_entry_lba);
1172 break;
1173 case GPT_LABELITEM_ENTRIESALLOC:
1174 item->name = _("Allocated partition entries");
1175 item->type = 'j';
1176 item->data.num64 = le32_to_cpu(h->npartition_entries);
1177 break;
1178 default:
1179 if (item->id < __FDISK_NLABELITEMS)
9e930041 1180 rc = 1; /* unsupported generic item */
5989556a
KZ
1181 else
1182 rc = 2; /* out of range */
1183 break;
1184 }
1185
1186 return rc;
1187}
775001ad 1188
766d5156
DB
1189/*
1190 * Returns the number of partitions that are in use.
1191 */
b683c081 1192static size_t partitions_in_use(struct fdisk_gpt_label *gpt)
766d5156 1193{
b683c081 1194 size_t i, used = 0;
766d5156 1195
b28df75e
KZ
1196 assert(gpt);
1197 assert(gpt->pheader);
1198 assert(gpt->ents);
1199
b683c081 1200 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e 1201 struct gpt_entry *e = gpt_get_entry(gpt, i);
766d5156 1202
02a376f2 1203 if (gpt_entry_is_used(e))
766d5156 1204 used++;
b28df75e 1205 }
766d5156
DB
1206 return used;
1207}
1208
766d5156
DB
1209
1210/*
1211 * Check if a partition is too big for the disk (sectors).
1212 * Returns the faulting partition number, otherwise 0.
1213 */
b28df75e 1214static uint32_t check_too_big_partitions(struct fdisk_gpt_label *gpt, uint64_t sectors)
766d5156 1215{
b683c081 1216 size_t i;
766d5156 1217
b28df75e
KZ
1218 assert(gpt);
1219 assert(gpt->pheader);
1220 assert(gpt->ents);
1221
b683c081 1222 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e
KZ
1223 struct gpt_entry *e = gpt_get_entry(gpt, i);
1224
02a376f2 1225 if (!gpt_entry_is_used(e))
766d5156 1226 continue;
b28df75e 1227 if (gpt_partition_end(e) >= sectors)
766d5156 1228 return i + 1;
5dbff4c0 1229 }
766d5156
DB
1230
1231 return 0;
5dbff4c0
KZ
1232}
1233
766d5156
DB
1234/*
1235 * Check if a partition ends before it begins
1236 * Returns the faulting partition number, otherwise 0.
5dbff4c0 1237 */
b28df75e 1238static uint32_t check_start_after_end_partitions(struct fdisk_gpt_label *gpt)
5dbff4c0 1239{
b683c081 1240 size_t i;
5dbff4c0 1241
b28df75e
KZ
1242 assert(gpt);
1243 assert(gpt->pheader);
1244 assert(gpt->ents);
1245
b683c081 1246 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e
KZ
1247 struct gpt_entry *e = gpt_get_entry(gpt, i);
1248
02a376f2 1249 if (!gpt_entry_is_used(e))
766d5156 1250 continue;
b28df75e 1251 if (gpt_partition_start(e) > gpt_partition_end(e))
766d5156 1252 return i + 1;
5dbff4c0 1253 }
766d5156
DB
1254
1255 return 0;
5dbff4c0
KZ
1256}
1257
766d5156 1258/*
09af3db4 1259 * Check if partition e1 overlaps with partition e2.
766d5156 1260 */
874aa9c3 1261static inline int partition_overlap(struct gpt_entry *e1, struct gpt_entry *e2)
5dbff4c0 1262{
874aa9c3
KZ
1263 uint64_t start1 = gpt_partition_start(e1);
1264 uint64_t end1 = gpt_partition_end(e1);
1265 uint64_t start2 = gpt_partition_start(e2);
1266 uint64_t end2 = gpt_partition_end(e2);
1267
1268 return (start1 && start2 && (start1 <= end2) != (end1 < start2));
766d5156
DB
1269}
1270
1271/*
09af3db4 1272 * Find any partitions that overlap.
766d5156 1273 */
b28df75e 1274static uint32_t check_overlap_partitions(struct fdisk_gpt_label *gpt)
766d5156 1275{
b683c081 1276 size_t i, j;
766d5156 1277
b28df75e
KZ
1278 assert(gpt);
1279 assert(gpt->pheader);
1280 assert(gpt->ents);
1281
b683c081 1282 for (i = 0; i < gpt_get_nentries(gpt); i++)
766d5156 1283 for (j = 0; j < i; j++) {
b28df75e
KZ
1284 struct gpt_entry *ei = gpt_get_entry(gpt, i);
1285 struct gpt_entry *ej = gpt_get_entry(gpt, j);
1286
02a376f2 1287 if (!gpt_entry_is_used(ei) || !gpt_entry_is_used(ej))
766d5156 1288 continue;
b28df75e 1289 if (partition_overlap(ei, ej)) {
b683c081 1290 DBG(LABEL, ul_debug("GPT partitions overlap detected [%zu vs. %zu]", i, j));
766d5156 1291 return i + 1;
c15aec86 1292 }
766d5156
DB
1293 }
1294
1295 return 0;
1296}
1297
1298/*
1299 * Find the first available block after the starting point; returns 0 if
1300 * there are no available blocks left, or error. From gdisk.
1301 */
b28df75e 1302static uint64_t find_first_available(struct fdisk_gpt_label *gpt, uint64_t start)
766d5156 1303{
b683c081 1304 int first_moved = 0;
766d5156 1305 uint64_t first;
602ebe7d
KZ
1306 uint64_t fu, lu;
1307
b28df75e
KZ
1308 assert(gpt);
1309 assert(gpt->pheader);
1310 assert(gpt->ents);
766d5156 1311
b28df75e
KZ
1312 fu = le64_to_cpu(gpt->pheader->first_usable_lba);
1313 lu = le64_to_cpu(gpt->pheader->last_usable_lba);
602ebe7d 1314
766d5156
DB
1315 /*
1316 * Begin from the specified starting point or from the first usable
1317 * LBA, whichever is greater...
1318 */
602ebe7d 1319 first = start < fu ? fu : start;
766d5156
DB
1320
1321 /*
1322 * Now search through all partitions; if first is within an
1323 * existing partition, move it to the next sector after that
1324 * partition and repeat. If first was moved, set firstMoved
1325 * flag; repeat until firstMoved is not set, so as to catch
1326 * cases where partitions are out of sequential order....
1327 */
1328 do {
b683c081
KZ
1329 size_t i;
1330
766d5156 1331 first_moved = 0;
b683c081 1332 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e
KZ
1333 struct gpt_entry *e = gpt_get_entry(gpt, i);
1334
02a376f2 1335 if (!gpt_entry_is_used(e))
766d5156 1336 continue;
b28df75e 1337 if (first < gpt_partition_start(e))
766d5156 1338 continue;
b28df75e
KZ
1339 if (first <= gpt_partition_end(e)) {
1340 first = gpt_partition_end(e) + 1;
766d5156
DB
1341 first_moved = 1;
1342 }
1343 }
1344 } while (first_moved == 1);
1345
602ebe7d 1346 if (first > lu)
766d5156
DB
1347 first = 0;
1348
1349 return first;
5dbff4c0
KZ
1350}
1351
766d5156
DB
1352
1353/* Returns last available sector in the free space pointed to by start. From gdisk. */
b28df75e 1354static uint64_t find_last_free(struct fdisk_gpt_label *gpt, uint64_t start)
5dbff4c0 1355{
b683c081 1356 size_t i;
766d5156
DB
1357 uint64_t nearest_start;
1358
b28df75e
KZ
1359 assert(gpt);
1360 assert(gpt->pheader);
1361 assert(gpt->ents);
766d5156 1362
b28df75e 1363 nearest_start = le64_to_cpu(gpt->pheader->last_usable_lba);
602ebe7d 1364
b683c081 1365 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e
KZ
1366 struct gpt_entry *e = gpt_get_entry(gpt, i);
1367 uint64_t ps = gpt_partition_start(e);
602ebe7d
KZ
1368
1369 if (nearest_start > ps && ps > start)
0a7cdf80 1370 nearest_start = ps - 1ULL;
5dbff4c0 1371 }
766d5156
DB
1372
1373 return nearest_start;
5dbff4c0 1374}
766d5156
DB
1375
1376/* Returns the last free sector on the disk. From gdisk. */
b28df75e 1377static uint64_t find_last_free_sector(struct fdisk_gpt_label *gpt)
766d5156 1378{
b683c081 1379 int last_moved;
766d5156
DB
1380 uint64_t last = 0;
1381
b28df75e
KZ
1382 assert(gpt);
1383 assert(gpt->pheader);
1384 assert(gpt->ents);
766d5156
DB
1385
1386 /* start by assuming the last usable LBA is available */
b28df75e 1387 last = le64_to_cpu(gpt->pheader->last_usable_lba);
766d5156 1388 do {
b683c081
KZ
1389 size_t i;
1390
766d5156 1391 last_moved = 0;
b683c081 1392 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e
KZ
1393 struct gpt_entry *e = gpt_get_entry(gpt, i);
1394
1395 if (last >= gpt_partition_start(e) &&
1396 last <= gpt_partition_end(e)) {
1397 last = gpt_partition_start(e) - 1ULL;
766d5156
DB
1398 last_moved = 1;
1399 }
1400 }
1401 } while (last_moved == 1);
b28df75e 1402
766d5156
DB
1403 return last;
1404}
1405
1406/*
1407 * Finds the first available sector in the largest block of unallocated
1408 * space on the disk. Returns 0 if there are no available blocks left.
1409 * From gdisk.
1410 */
b28df75e 1411static uint64_t find_first_in_largest(struct fdisk_gpt_label *gpt)
766d5156
DB
1412{
1413 uint64_t start = 0, first_sect, last_sect;
1414 uint64_t segment_size, selected_size = 0, selected_segment = 0;
1415
b28df75e
KZ
1416 assert(gpt);
1417 assert(gpt->pheader);
1418 assert(gpt->ents);
766d5156
DB
1419
1420 do {
b28df75e 1421 first_sect = find_first_available(gpt, start);
766d5156 1422 if (first_sect != 0) {
b28df75e 1423 last_sect = find_last_free(gpt, first_sect);
0a7cdf80 1424 segment_size = last_sect - first_sect + 1ULL;
766d5156
DB
1425
1426 if (segment_size > selected_size) {
1427 selected_size = segment_size;
1428 selected_segment = first_sect;
1429 }
0a7cdf80 1430 start = last_sect + 1ULL;
766d5156
DB
1431 }
1432 } while (first_sect != 0);
1433
766d5156
DB
1434 return selected_segment;
1435}
1436
1437/*
1438 * Find the total number of free sectors, the number of segments in which
1439 * they reside, and the size of the largest of those segments. From gdisk.
1440 */
b28df75e
KZ
1441static uint64_t get_free_sectors(struct fdisk_context *cxt,
1442 struct fdisk_gpt_label *gpt,
1443 uint32_t *nsegments,
766d5156
DB
1444 uint64_t *largest_segment)
1445{
1446 uint32_t num = 0;
1447 uint64_t first_sect, last_sect;
1448 uint64_t largest_seg = 0, segment_sz;
1449 uint64_t totfound = 0, start = 0; /* starting point for each search */
1450
1451 if (!cxt->total_sectors)
1452 goto done;
1453
b28df75e
KZ
1454 assert(gpt);
1455 assert(gpt->pheader);
1456 assert(gpt->ents);
1457
766d5156 1458 do {
b28df75e 1459 first_sect = find_first_available(gpt, start);
766d5156 1460 if (first_sect) {
b28df75e 1461 last_sect = find_last_free(gpt, first_sect);
766d5156
DB
1462 segment_sz = last_sect - first_sect + 1;
1463
1464 if (segment_sz > largest_seg)
1465 largest_seg = segment_sz;
1466 totfound += segment_sz;
1467 num++;
0a7cdf80 1468 start = last_sect + 1ULL;
766d5156
DB
1469 }
1470 } while (first_sect);
1471
1472done:
512a430f
KZ
1473 if (nsegments)
1474 *nsegments = num;
1475 if (largest_segment)
1476 *largest_segment = largest_seg;
766d5156
DB
1477
1478 return totfound;
1479}
1480
9ffeb235 1481static int gpt_probe_label(struct fdisk_context *cxt)
766d5156
DB
1482{
1483 int mbr_type;
9ffeb235 1484 struct fdisk_gpt_label *gpt;
766d5156 1485
9ffeb235
KZ
1486 assert(cxt);
1487 assert(cxt->label);
aa36c2cf 1488 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
1489
1490 gpt = self_label(cxt);
766d5156 1491
d2d9efa1
KZ
1492 /* TODO: it would be nice to support scenario when GPT headers are OK,
1493 * but PMBR is corrupt */
766d5156
DB
1494 mbr_type = valid_pmbr(cxt);
1495 if (!mbr_type)
1496 goto failed;
1497
88141067 1498 DBG(LABEL, ul_debug("found a %s MBR", mbr_type == GPT_MBR_PROTECTIVE ?
766d5156
DB
1499 "protective" : "hybrid"));
1500
d71ef5a4
KZ
1501 /* primary header */
1502 gpt->pheader = gpt_read_header(cxt, GPT_PRIMARY_PARTITION_TABLE_LBA,
1503 &gpt->ents);
45ddb828
KZ
1504
1505 if (gpt->pheader)
1506 /* primary OK, try backup from alternative LBA */
1507 gpt->bheader = gpt_read_header(cxt,
1508 le64_to_cpu(gpt->pheader->alternative_lba),
1509 NULL);
1510 else
1511 /* primary corrupted -- try last LBA */
1512 gpt->bheader = gpt_read_header(cxt, last_lba(cxt), &gpt->ents);
766d5156 1513
d2d9efa1 1514 if (!gpt->pheader && !gpt->bheader)
766d5156
DB
1515 goto failed;
1516
d2d9efa1
KZ
1517 /* primary OK, backup corrupted -- recovery */
1518 if (gpt->pheader && !gpt->bheader) {
1519 fdisk_warnx(cxt, _("The backup GPT table is corrupt, but the "
1520 "primary appears OK, so that will be used."));
45ddb828
KZ
1521 gpt->bheader = gpt_copy_header(cxt, gpt->pheader);
1522 if (!gpt->bheader)
d2d9efa1 1523 goto failed;
d2d9efa1
KZ
1524 gpt_recompute_crc(gpt->bheader, gpt->ents);
1525
1526 /* primary corrupted, backup OK -- recovery */
1527 } else if (!gpt->pheader && gpt->bheader) {
1528 fdisk_warnx(cxt, _("The primary GPT table is corrupt, but the "
1529 "backup appears OK, so that will be used."));
45ddb828
KZ
1530 gpt->pheader = gpt_copy_header(cxt, gpt->bheader);
1531 if (!gpt->pheader)
d2d9efa1 1532 goto failed;
d2d9efa1
KZ
1533 gpt_recompute_crc(gpt->pheader, gpt->ents);
1534 }
d71ef5a4 1535
b683c081 1536 cxt->label->nparts_max = gpt_get_nentries(gpt);
b28df75e 1537 cxt->label->nparts_cur = partitions_in_use(gpt);
766d5156
DB
1538 return 1;
1539failed:
88141067 1540 DBG(LABEL, ul_debug("GPT probe failed"));
9ffeb235 1541 gpt_deinit(cxt->label);
766d5156
DB
1542 return 0;
1543}
1544
1545/*
1546 * Stolen from libblkid - can be removed once partition semantics
1547 * are added to the fdisk API.
1548 */
1549static char *encode_to_utf8(unsigned char *src, size_t count)
1550{
1551 uint16_t c;
d06f321d 1552 char *dest;
766d5156 1553 size_t i, j, len = count;
3f731001 1554
d06f321d
KZ
1555 dest = calloc(1, count);
1556 if (!dest)
1557 return NULL;
766d5156
DB
1558
1559 for (j = i = 0; i + 2 <= count; i += 2) {
1560 /* always little endian */
1561 c = (src[i+1] << 8) | src[i];
1562 if (c == 0) {
1563 dest[j] = '\0';
1564 break;
1565 } else if (c < 0x80) {
1566 if (j+1 >= len)
1567 break;
1568 dest[j++] = (uint8_t) c;
1569 } else if (c < 0x800) {
1570 if (j+2 >= len)
1571 break;
1572 dest[j++] = (uint8_t) (0xc0 | (c >> 6));
1573 dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
1574 } else {
1575 if (j+3 >= len)
1576 break;
1577 dest[j++] = (uint8_t) (0xe0 | (c >> 12));
1578 dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
1579 dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
1580 }
1581 }
1582 dest[j] = '\0';
1583
1584 return dest;
1585}
1586
01086b80 1587static int gpt_entry_attrs_to_string(struct gpt_entry *e, char **res)
c83f772e 1588{
01086b80
KZ
1589 unsigned int n, count = 0;
1590 size_t l;
1591 char *bits, *p;
1592 uint64_t attrs;
1593
1594 assert(e);
1595 assert(res);
1596
1597 *res = NULL;
159652d9 1598 attrs = e->attrs;
01086b80
KZ
1599 if (!attrs)
1600 return 0; /* no attributes at all */
1601
1602 bits = (char *) &attrs;
1603
1604 /* Note that sizeof() is correct here, we need separators between
1605 * the strings so also count \0 is correct */
1606 *res = calloc(1, sizeof(GPT_ATTRSTR_NOBLOCK) +
1607 sizeof(GPT_ATTRSTR_REQ) +
1608 sizeof(GPT_ATTRSTR_LEGACY) +
1609 sizeof("GUID:") + (GPT_ATTRBIT_GUID_COUNT * 3));
c83f772e 1610 if (!*res)
01086b80
KZ
1611 return -errno;
1612
1613 p = *res;
1614 if (isset(bits, GPT_ATTRBIT_REQ)) {
1615 memcpy(p, GPT_ATTRSTR_REQ, (l = sizeof(GPT_ATTRSTR_REQ)));
1616 p += l - 1;
1617 }
1618 if (isset(bits, GPT_ATTRBIT_NOBLOCK)) {
1619 if (p > *res)
1620 *p++ = ' ';
1621 memcpy(p, GPT_ATTRSTR_NOBLOCK, (l = sizeof(GPT_ATTRSTR_NOBLOCK)));
1622 p += l - 1;
1623 }
1624 if (isset(bits, GPT_ATTRBIT_LEGACY)) {
1625 if (p > *res)
1626 *p++ = ' ';
1627 memcpy(p, GPT_ATTRSTR_LEGACY, (l = sizeof(GPT_ATTRSTR_LEGACY)));
1628 p += l - 1;
1629 }
1630
1631 for (n = GPT_ATTRBIT_GUID_FIRST;
1632 n < GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT; n++) {
c83f772e 1633
01086b80 1634 if (!isset(bits, n))
c83f772e 1635 continue;
01086b80
KZ
1636 if (!count) {
1637 if (p > *res)
1638 *p++ = ' ';
1639 p += sprintf(p, "GUID:%u", n);
1640 } else
1641 p += sprintf(p, ",%u", n);
c83f772e 1642 count++;
c83f772e
KZ
1643 }
1644
01086b80 1645 return 0;
c83f772e
KZ
1646}
1647
c77ba531
KZ
1648static int gpt_entry_attrs_from_string(
1649 struct fdisk_context *cxt,
1650 struct gpt_entry *e,
1651 const char *str)
1652{
1653 const char *p = str;
1654 uint64_t attrs = 0;
1655 char *bits;
1656
1657 assert(e);
1658 assert(p);
1659
1660 DBG(LABEL, ul_debug("GPT: parsing string attributes '%s'", p));
1661
1662 bits = (char *) &attrs;
1663
1664 while (p && *p) {
1665 int bit = -1;
1666
1667 while (isblank(*p)) p++;
1668 if (!*p)
1669 break;
1670
1671 DBG(LABEL, ul_debug(" parsing item '%s'", p));
1672
17d0902c 1673 if (strncmp(p, GPT_ATTRSTR_REQ,
c77ba531
KZ
1674 sizeof(GPT_ATTRSTR_REQ) - 1) == 0) {
1675 bit = GPT_ATTRBIT_REQ;
1676 p += sizeof(GPT_ATTRSTR_REQ) - 1;
d1b7bfe5
SR
1677 } else if (strncmp(p, GPT_ATTRSTR_REQ_TYPO,
1678 sizeof(GPT_ATTRSTR_REQ_TYPO) - 1) == 0) {
1679 bit = GPT_ATTRBIT_REQ;
1680 p += sizeof(GPT_ATTRSTR_REQ_TYPO) - 1;
c77ba531
KZ
1681 } else if (strncmp(p, GPT_ATTRSTR_LEGACY,
1682 sizeof(GPT_ATTRSTR_LEGACY) - 1) == 0) {
1683 bit = GPT_ATTRBIT_LEGACY;
1684 p += sizeof(GPT_ATTRSTR_LEGACY) - 1;
1685 } else if (strncmp(p, GPT_ATTRSTR_NOBLOCK,
1686 sizeof(GPT_ATTRSTR_NOBLOCK) - 1) == 0) {
1687 bit = GPT_ATTRBIT_NOBLOCK;
1688 p += sizeof(GPT_ATTRSTR_NOBLOCK) - 1;
17d0902c
KZ
1689
1690 /* GUID:<bit> as well as <bit> */
bae57b5a 1691 } else if (isdigit((unsigned char) *p)
17d0902c 1692 || (strncmp(p, "GUID:", 5) == 0
bae57b5a 1693 && isdigit((unsigned char) *(p + 5)))) {
c77ba531
KZ
1694 char *end = NULL;
1695
17d0902c
KZ
1696 if (*p == 'G')
1697 p += 5;
1698
c77ba531
KZ
1699 errno = 0;
1700 bit = strtol(p, &end, 0);
1701 if (errno || !end || end == str
1702 || bit < GPT_ATTRBIT_GUID_FIRST
1703 || bit >= GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT)
1704 bit = -1;
1705 else
1706 p = end;
1707 }
1708
1709 if (bit < 0) {
54fefa07 1710 fdisk_warnx(cxt, _("unsupported GPT attribute bit '%s'"), p);
c77ba531
KZ
1711 return -EINVAL;
1712 }
1713
17d0902c
KZ
1714 if (*p && *p != ',' && !isblank(*p)) {
1715 fdisk_warnx(cxt, _("failed to parse GPT attribute string '%s'"), str);
1716 return -EINVAL;
1717 }
1718
c77ba531
KZ
1719 setbit(bits, bit);
1720
1721 while (isblank(*p)) p++;
1722 if (*p == ',')
1723 p++;
1724 }
1725
159652d9 1726 e->attrs = attrs;
c77ba531
KZ
1727 return 0;
1728}
1729
8c0a7f91
KZ
1730static int gpt_get_partition(struct fdisk_context *cxt, size_t n,
1731 struct fdisk_partition *pa)
766d5156 1732{
9ffeb235 1733 struct fdisk_gpt_label *gpt;
6941952e 1734 struct gpt_entry *e;
01086b80
KZ
1735 char u_str[37];
1736 int rc = 0;
92e486f8 1737 struct gpt_guid guid;
9ffeb235
KZ
1738
1739 assert(cxt);
1740 assert(cxt->label);
aa36c2cf 1741 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
1742
1743 gpt = self_label(cxt);
766d5156 1744
b683c081 1745 if (n >= gpt_get_nentries(gpt))
6941952e 1746 return -EINVAL;
3c5fb475 1747
6941952e 1748 gpt = self_label(cxt);
b28df75e 1749 e = gpt_get_entry(gpt, n);
b1920e0b 1750
02a376f2 1751 pa->used = gpt_entry_is_used(e) || gpt_partition_start(e);
8c0a7f91
KZ
1752 if (!pa->used)
1753 return 0;
766d5156 1754
8c0a7f91 1755 pa->start = gpt_partition_start(e);
77d6a70a 1756 pa->size = gpt_partition_size(e);
7f539277 1757 pa->type = gpt_partition_parttype(cxt, e);
766d5156 1758
92e486f8
RM
1759 guid = e->partition_guid;
1760 if (guid_to_string(&guid, u_str)) {
8c0a7f91 1761 pa->uuid = strdup(u_str);
01086b80
KZ
1762 if (!pa->uuid) {
1763 rc = -errno;
1764 goto done;
1765 }
8c0a7f91
KZ
1766 } else
1767 pa->uuid = NULL;
1768
01086b80
KZ
1769 rc = gpt_entry_attrs_to_string(e, &pa->attrs);
1770 if (rc)
1771 goto done;
b1920e0b 1772
8c0a7f91 1773 pa->name = encode_to_utf8((unsigned char *)e->name, sizeof(e->name));
8c0a7f91 1774 return 0;
01086b80 1775done:
8c0a7f91 1776 fdisk_reset_partition(pa);
01086b80 1777 return rc;
6941952e 1778}
766d5156 1779
9348ef25 1780
b0a484a8
KZ
1781static int gpt_set_partition(struct fdisk_context *cxt, size_t n,
1782 struct fdisk_partition *pa)
1783{
1784 struct fdisk_gpt_label *gpt;
1785 struct gpt_entry *e;
1786 int rc = 0;
9146a008 1787 uint64_t start, end;
b0a484a8
KZ
1788
1789 assert(cxt);
1790 assert(cxt->label);
1791 assert(fdisk_is_label(cxt, GPT));
1792
1793 gpt = self_label(cxt);
1794
b683c081 1795 if (n >= gpt_get_nentries(gpt))
b0a484a8
KZ
1796 return -EINVAL;
1797
9146a008
KZ
1798 FDISK_INIT_UNDEF(start);
1799 FDISK_INIT_UNDEF(end);
1800
b0a484a8 1801 gpt = self_label(cxt);
b28df75e 1802 e = gpt_get_entry(gpt, n);
b0a484a8
KZ
1803
1804 if (pa->uuid) {
6936c081 1805 char new_u[37], old_u[37];
92e486f8 1806 struct gpt_guid guid;
6936c081 1807
92e486f8
RM
1808 guid = e->partition_guid;
1809 guid_to_string(&guid, old_u);
b0a484a8
KZ
1810 rc = gpt_entry_set_uuid(e, pa->uuid);
1811 if (rc)
1812 return rc;
92e486f8
RM
1813 guid = e->partition_guid;
1814 guid_to_string(&guid, new_u);
0477369a 1815 fdisk_info(cxt, _("Partition UUID changed from %s to %s."),
6936c081 1816 old_u, new_u);
b0a484a8
KZ
1817 }
1818
6936c081
KZ
1819 if (pa->name) {
1820 char *old = encode_to_utf8((unsigned char *)e->name, sizeof(e->name));
b0a484a8
KZ
1821 gpt_entry_set_name(e, pa->name);
1822
0477369a 1823 fdisk_info(cxt, _("Partition name changed from '%s' to '%.*s'."),
6936c081
KZ
1824 old, (int) GPT_PART_NAME_LEN, pa->name);
1825 free(old);
1826 }
1827
b0a484a8
KZ
1828 if (pa->type && pa->type->typestr) {
1829 struct gpt_guid typeid;
1830
a48c0985
KZ
1831 rc = string_to_guid(pa->type->typestr, &typeid);
1832 if (rc)
1833 return rc;
b0a484a8
KZ
1834 gpt_entry_set_type(e, &typeid);
1835 }
c77ba531
KZ
1836 if (pa->attrs) {
1837 rc = gpt_entry_attrs_from_string(cxt, e, pa->attrs);
1838 if (rc)
1839 return rc;
1840 }
b0a484a8 1841
ecf40cda 1842 if (fdisk_partition_has_start(pa))
9146a008 1843 start = pa->start;
76785052
KZ
1844 if (fdisk_partition_has_size(pa) || fdisk_partition_has_start(pa)) {
1845 uint64_t xstart = fdisk_partition_has_start(pa) ? pa->start : gpt_partition_start(e);
1846 uint64_t xsize = fdisk_partition_has_size(pa) ? pa->size : gpt_partition_size(e);
1847 end = xstart + xsize - 1ULL;
1848 }
9146a008 1849
c949fa98
KZ
1850 if (!FDISK_IS_UNDEF(start)) {
1851 if (start < le64_to_cpu(gpt->pheader->first_usable_lba)) {
614ddddf 1852 fdisk_warnx(cxt, _("The start of the partition understeps FirstUsableLBA."));
c949fa98
KZ
1853 return -EINVAL;
1854 }
9146a008 1855 e->lba_start = cpu_to_le64(start);
c949fa98
KZ
1856 }
1857 if (!FDISK_IS_UNDEF(end)) {
1858 if (end > le64_to_cpu(gpt->pheader->last_usable_lba)) {
614ddddf 1859 fdisk_warnx(cxt, _("The end of the partition oversteps LastUsableLBA."));
c949fa98
KZ
1860 return -EINVAL;
1861 }
9146a008 1862 e->lba_end = cpu_to_le64(end);
c949fa98 1863 }
b0a484a8
KZ
1864 gpt_recompute_crc(gpt->pheader, gpt->ents);
1865 gpt_recompute_crc(gpt->bheader, gpt->ents);
1866
1867 fdisk_label_set_changed(cxt->label, 1);
1868 return rc;
1869}
1870
1871
766d5156
DB
1872
1873/*
1874 * Write partitions.
1875 * Returns 0 on success, or corresponding error otherwise.
1876 */
1877static int gpt_write_partitions(struct fdisk_context *cxt,
b28df75e 1878 struct gpt_header *header, unsigned char *ents)
766d5156 1879{
5eaeb585 1880 off_t offset = (off_t) le64_to_cpu(header->partition_entry_lba) * cxt->sector_size;
9e320545
KZ
1881 size_t towrite;
1882 ssize_t ssz;
1883 int rc;
1884
1885 rc = gpt_sizeof_ents(header, &towrite);
1886 if (rc)
1887 return rc;
766d5156
DB
1888
1889 if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
9e320545 1890 return -errno;
d71ef5a4 1891
9e320545
KZ
1892 ssz = write(cxt->dev_fd, ents, towrite);
1893 if (ssz < 0 || (ssize_t) towrite != ssz)
1894 return -errno;
1895
1896 return 0;
766d5156
DB
1897}
1898
1899/*
4bb82a45
KZ
1900 * Write a GPT header to a specified LBA.
1901 *
1902 * We read all sector, so we have to write all sector back
1903 * to the device -- never ever rely on sizeof(struct gpt_header)!
1904 *
766d5156
DB
1905 * Returns 0 on success, or corresponding error otherwise.
1906 */
1907static int gpt_write_header(struct fdisk_context *cxt,
1908 struct gpt_header *header, uint64_t lba)
1909{
1910 off_t offset = lba * cxt->sector_size;
1911
1912 if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
1913 goto fail;
1914 if (cxt->sector_size ==
1915 (size_t) write(cxt->dev_fd, header, cxt->sector_size))
1916 return 0;
1917fail:
1918 return -errno;
1919}
1920
1921/*
1922 * Write the protective MBR.
1923 * Returns 0 on success, or corresponding error otherwise.
1924 */
1925static int gpt_write_pmbr(struct fdisk_context *cxt)
1926{
1927 off_t offset;
1928 struct gpt_legacy_mbr *pmbr = NULL;
1929
9ffeb235
KZ
1930 assert(cxt);
1931 assert(cxt->firstsector);
766d5156
DB
1932
1933 pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
1934
1935 /* zero out the legacy partitions */
1936 memset(pmbr->partition_record, 0, sizeof(pmbr->partition_record));
1937
1938 pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE);
1939 pmbr->partition_record[0].os_type = EFI_PMBR_OSTYPE;
1940 pmbr->partition_record[0].start_sector = 1;
1941 pmbr->partition_record[0].end_head = 0xFE;
1942 pmbr->partition_record[0].end_sector = 0xFF;
1943 pmbr->partition_record[0].end_track = 0xFF;
1944 pmbr->partition_record[0].starting_lba = cpu_to_le32(1);
1945
1946 /*
1947 * Set size_in_lba to the size of the disk minus one. If the size of the disk
1948 * is too large to be represented by a 32bit LBA (2Tb), set it to 0xFFFFFFFF.
1949 */
0a7cdf80 1950 if (cxt->total_sectors - 1ULL > 0xFFFFFFFFULL)
766d5156
DB
1951 pmbr->partition_record[0].size_in_lba = cpu_to_le32(0xFFFFFFFF);
1952 else
1953 pmbr->partition_record[0].size_in_lba =
0a7cdf80 1954 cpu_to_le32((uint32_t) (cxt->total_sectors - 1ULL));
766d5156
DB
1955
1956 offset = GPT_PMBR_LBA * cxt->sector_size;
1957 if (offset != lseek(cxt->dev_fd, offset, SEEK_SET))
1958 goto fail;
1959
19613111
DB
1960 /* pMBR covers the first sector (LBA) of the disk */
1961 if (write_all(cxt->dev_fd, pmbr, cxt->sector_size))
1962 goto fail;
1963 return 0;
766d5156
DB
1964fail:
1965 return -errno;
1966}
1967
1968/*
1969 * Writes in-memory GPT and pMBR data to disk.
1970 * Returns 0 if successful write, otherwise, a corresponding error.
1971 * Any indication of error will abort the operation.
1972 */
9ffeb235 1973static int gpt_write_disklabel(struct fdisk_context *cxt)
766d5156 1974{
9ffeb235 1975 struct fdisk_gpt_label *gpt;
433d05ff 1976 int mbr_type;
d71ef5a4 1977
9ffeb235
KZ
1978 assert(cxt);
1979 assert(cxt->label);
aa36c2cf 1980 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
1981
1982 gpt = self_label(cxt);
433d05ff 1983 mbr_type = valid_pmbr(cxt);
766d5156
DB
1984
1985 /* check that disk is big enough to handle the backup header */
c15aec86 1986 if (le64_to_cpu(gpt->pheader->alternative_lba) > cxt->total_sectors)
766d5156
DB
1987 goto err0;
1988
1989 /* check that the backup header is properly placed */
0a7cdf80 1990 if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1ULL)
766d5156
DB
1991 /* TODO: correct this (with user authorization) and write */
1992 goto err0;
1993
b28df75e 1994 if (check_overlap_partitions(gpt))
766d5156
DB
1995 goto err0;
1996
1997 /* recompute CRCs for both headers */
d71ef5a4
KZ
1998 gpt_recompute_crc(gpt->pheader, gpt->ents);
1999 gpt_recompute_crc(gpt->bheader, gpt->ents);
766d5156
DB
2000
2001 /*
2002 * UEFI requires writing in this specific order:
2003 * 1) backup partition tables
2004 * 2) backup GPT header
2005 * 3) primary partition tables
2006 * 4) primary GPT header
2007 * 5) protective MBR
2008 *
2009 * If any write fails, we abort the rest.
2010 */
d71ef5a4 2011 if (gpt_write_partitions(cxt, gpt->bheader, gpt->ents) != 0)
766d5156 2012 goto err1;
c15aec86
KZ
2013 if (gpt_write_header(cxt, gpt->bheader,
2014 le64_to_cpu(gpt->pheader->alternative_lba)) != 0)
766d5156 2015 goto err1;
d71ef5a4 2016 if (gpt_write_partitions(cxt, gpt->pheader, gpt->ents) != 0)
766d5156 2017 goto err1;
d71ef5a4 2018 if (gpt_write_header(cxt, gpt->pheader, GPT_PRIMARY_PARTITION_TABLE_LBA) != 0)
766d5156 2019 goto err1;
433d05ff
KZ
2020
2021 if (mbr_type == GPT_MBR_HYBRID)
2022 fdisk_warnx(cxt, _("The device contains hybrid MBR -- writing GPT only. "
2023 "You have to sync the MBR manually."));
2024 else if (gpt_write_pmbr(cxt) != 0)
766d5156
DB
2025 goto err1;
2026
88141067 2027 DBG(LABEL, ul_debug("GPT write success"));
766d5156
DB
2028 return 0;
2029err0:
88141067 2030 DBG(LABEL, ul_debug("GPT write failed: incorrect input"));
c15aec86 2031 errno = EINVAL;
766d5156
DB
2032 return -EINVAL;
2033err1:
88141067 2034 DBG(LABEL, ul_debug("GPT write failed: %m"));
766d5156
DB
2035 return -errno;
2036}
2037
2038/*
2039 * Verify data integrity and report any found problems for:
2040 * - primary and backup header validations
9e930041 2041 * - partition validations
766d5156 2042 */
9ffeb235 2043static int gpt_verify_disklabel(struct fdisk_context *cxt)
766d5156 2044{
83df5feb
KZ
2045 int nerror = 0;
2046 unsigned int ptnum;
9ffeb235
KZ
2047 struct fdisk_gpt_label *gpt;
2048
2049 assert(cxt);
2050 assert(cxt->label);
aa36c2cf 2051 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
2052
2053 gpt = self_label(cxt);
e820595b
KZ
2054 if (!gpt)
2055 return -EINVAL;
766d5156 2056
e820595b 2057 if (!gpt->bheader) {
766d5156 2058 nerror++;
83df5feb 2059 fdisk_warnx(cxt, _("Disk does not contain a valid backup header."));
766d5156
DB
2060 }
2061
d71ef5a4 2062 if (!gpt_check_header_crc(gpt->pheader, gpt->ents)) {
766d5156 2063 nerror++;
83df5feb 2064 fdisk_warnx(cxt, _("Invalid primary header CRC checksum."));
766d5156 2065 }
d71ef5a4 2066 if (gpt->bheader && !gpt_check_header_crc(gpt->bheader, gpt->ents)) {
766d5156 2067 nerror++;
83df5feb 2068 fdisk_warnx(cxt, _("Invalid backup header CRC checksum."));
766d5156
DB
2069 }
2070
d71ef5a4 2071 if (!gpt_check_entryarr_crc(gpt->pheader, gpt->ents)) {
766d5156 2072 nerror++;
83df5feb 2073 fdisk_warnx(cxt, _("Invalid partition entry checksum."));
766d5156
DB
2074 }
2075
d71ef5a4 2076 if (!gpt_check_lba_sanity(cxt, gpt->pheader)) {
766d5156 2077 nerror++;
83df5feb 2078 fdisk_warnx(cxt, _("Invalid primary header LBA sanity checks."));
766d5156 2079 }
d71ef5a4 2080 if (gpt->bheader && !gpt_check_lba_sanity(cxt, gpt->bheader)) {
766d5156 2081 nerror++;
83df5feb 2082 fdisk_warnx(cxt, _("Invalid backup header LBA sanity checks."));
766d5156
DB
2083 }
2084
d71ef5a4 2085 if (le64_to_cpu(gpt->pheader->my_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) {
766d5156 2086 nerror++;
83df5feb 2087 fdisk_warnx(cxt, _("MyLBA mismatch with real position at primary header."));
766d5156 2088 }
d71ef5a4 2089 if (gpt->bheader && le64_to_cpu(gpt->bheader->my_lba) != last_lba(cxt)) {
766d5156 2090 nerror++;
83df5feb 2091 fdisk_warnx(cxt, _("MyLBA mismatch with real position at backup header."));
766d5156
DB
2092
2093 }
c15aec86 2094 if (le64_to_cpu(gpt->pheader->alternative_lba) >= cxt->total_sectors) {
766d5156 2095 nerror++;
a1e276ae 2096 fdisk_warnx(cxt, _("Disk is too small to hold all data."));
766d5156
DB
2097 }
2098
2099 /*
2100 * if the GPT is the primary table, check the alternateLBA
2101 * to see if it is a valid GPT
2102 */
c15aec86
KZ
2103 if (gpt->bheader && (le64_to_cpu(gpt->pheader->my_lba) !=
2104 le64_to_cpu(gpt->bheader->alternative_lba))) {
766d5156 2105 nerror++;
83df5feb 2106 fdisk_warnx(cxt, _("Primary and backup header mismatch."));
766d5156
DB
2107 }
2108
b28df75e 2109 ptnum = check_overlap_partitions(gpt);
766d5156
DB
2110 if (ptnum) {
2111 nerror++;
83df5feb
KZ
2112 fdisk_warnx(cxt, _("Partition %u overlaps with partition %u."),
2113 ptnum, ptnum+1);
766d5156
DB
2114 }
2115
b28df75e 2116 ptnum = check_too_big_partitions(gpt, cxt->total_sectors);
766d5156
DB
2117 if (ptnum) {
2118 nerror++;
83df5feb
KZ
2119 fdisk_warnx(cxt, _("Partition %u is too big for the disk."),
2120 ptnum);
766d5156
DB
2121 }
2122
b28df75e 2123 ptnum = check_start_after_end_partitions(gpt);
766d5156
DB
2124 if (ptnum) {
2125 nerror++;
83df5feb
KZ
2126 fdisk_warnx(cxt, _("Partition %u ends before it starts."),
2127 ptnum);
766d5156
DB
2128 }
2129
2130 if (!nerror) { /* yay :-) */
2131 uint32_t nsegments = 0;
2132 uint64_t free_sectors = 0, largest_segment = 0;
6d0ed4cb 2133 char *strsz = NULL;
766d5156 2134
ac1a559a 2135 fdisk_info(cxt, _("No errors detected."));
83df5feb 2136 fdisk_info(cxt, _("Header version: %s"), gpt_get_header_revstr(gpt->pheader));
b683c081 2137 fdisk_info(cxt, _("Using %zu out of %zu partitions."),
b28df75e 2138 partitions_in_use(gpt),
b683c081 2139 gpt_get_nentries(gpt));
766d5156 2140
b28df75e 2141 free_sectors = get_free_sectors(cxt, gpt, &nsegments, &largest_segment);
6d0ed4cb
KZ
2142 if (largest_segment)
2143 strsz = size_to_human_string(SIZE_SUFFIX_SPACE | SIZE_SUFFIX_3LETTER,
2144 largest_segment * cxt->sector_size);
2145
4ae11fe8 2146 fdisk_info(cxt,
829f4206
KZ
2147 P_("A total of %ju free sectors is available in %u segment.",
2148 "A total of %ju free sectors is available in %u segments "
6d0ed4cb
KZ
2149 "(the largest is %s).", nsegments),
2150 free_sectors, nsegments, strsz);
2151 free(strsz);
2152
766d5156 2153 } else
a1e276ae 2154 fdisk_warnx(cxt,
8e7f944d 2155 P_("%d error detected.", "%d errors detected.", nerror),
a1e276ae 2156 nerror);
766d5156
DB
2157
2158 return 0;
2159}
2160
2161/* Delete a single GPT partition, specified by partnum. */
8a95621d 2162static int gpt_delete_partition(struct fdisk_context *cxt,
9ffeb235 2163 size_t partnum)
766d5156 2164{
9ffeb235 2165 struct fdisk_gpt_label *gpt;
d71ef5a4 2166
9ffeb235
KZ
2167 assert(cxt);
2168 assert(cxt->label);
aa36c2cf 2169 assert(fdisk_is_label(cxt, GPT));
d71ef5a4 2170
9ffeb235
KZ
2171 gpt = self_label(cxt);
2172
b28df75e 2173 if (partnum >= cxt->label->nparts_max)
1f5eb51b 2174 return -EINVAL;
766d5156 2175
02a376f2 2176 if (!gpt_entry_is_used(gpt_get_entry(gpt, partnum)))
1f5eb51b 2177 return -EINVAL;
b28df75e
KZ
2178
2179 /* hasta la vista, baby! */
2180 gpt_zeroize_entry(gpt, partnum);
2181
2182 gpt_recompute_crc(gpt->pheader, gpt->ents);
2183 gpt_recompute_crc(gpt->bheader, gpt->ents);
2184 cxt->label->nparts_cur--;
2185 fdisk_label_set_changed(cxt->label, 1);
1f5eb51b
DB
2186
2187 return 0;
766d5156
DB
2188}
2189
080633e4 2190
766d5156 2191/* Performs logical checks to add a new partition entry */
8a95621d
KZ
2192static int gpt_add_partition(
2193 struct fdisk_context *cxt,
c3bc7483
KZ
2194 struct fdisk_partition *pa,
2195 size_t *partno)
766d5156 2196{
512a430f
KZ
2197 uint64_t user_f, user_l; /* user input ranges for first and last sectors */
2198 uint64_t disk_f, disk_l; /* first and last available sector ranges on device*/
2199 uint64_t dflt_f, dflt_l; /* largest segment (default) */
c0d14b09 2200 struct gpt_guid typeid;
9ffeb235 2201 struct fdisk_gpt_label *gpt;
d71ef5a4 2202 struct gpt_header *pheader;
b28df75e 2203 struct gpt_entry *e;
4114da08 2204 struct fdisk_ask *ask = NULL;
77d6a70a 2205 size_t partnum;
4114da08 2206 int rc;
766d5156 2207
9ffeb235
KZ
2208 assert(cxt);
2209 assert(cxt->label);
aa36c2cf 2210 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
2211
2212 gpt = self_label(cxt);
b28df75e
KZ
2213
2214 assert(gpt);
2215 assert(gpt->pheader);
2216 assert(gpt->ents);
2217
d71ef5a4 2218 pheader = gpt->pheader;
d71ef5a4 2219
6c89f750 2220 rc = fdisk_partition_next_partno(pa, cxt, &partnum);
1240f549 2221 if (rc) {
88141067 2222 DBG(LABEL, ul_debug("GPT failed to get next partno"));
77d6a70a 2223 return rc;
1240f549 2224 }
b28df75e 2225
b683c081 2226 assert(partnum < gpt_get_nentries(gpt));
b28df75e 2227
02a376f2 2228 if (gpt_entry_is_used(gpt_get_entry(gpt, partnum))) {
829f4206 2229 fdisk_warnx(cxt, _("Partition %zu is already defined. "
83217641 2230 "Delete it before re-adding it."), partnum +1);
77d6a70a 2231 return -ERANGE;
766d5156 2232 }
b683c081 2233 if (gpt_get_nentries(gpt) == partitions_in_use(gpt)) {
83df5feb 2234 fdisk_warnx(cxt, _("All partitions are already in use."));
77d6a70a 2235 return -ENOSPC;
766d5156 2236 }
b28df75e 2237 if (!get_free_sectors(cxt, gpt, NULL, NULL)) {
83df5feb 2238 fdisk_warnx(cxt, _("No free sectors available."));
8254c3a5 2239 return -ENOSPC;
766d5156
DB
2240 }
2241
4044d244 2242 rc = string_to_guid(pa && pa->type && pa->type->typestr ?
77d6a70a
KZ
2243 pa->type->typestr:
2244 GPT_DEFAULT_ENTRY_TYPE, &typeid);
4044d244
KZ
2245 if (rc)
2246 return rc;
77d6a70a 2247
b28df75e
KZ
2248 disk_f = find_first_available(gpt, le64_to_cpu(pheader->first_usable_lba));
2249 e = gpt_get_entry(gpt, 0);
4a4616b2
KZ
2250
2251 /* if first sector no explicitly defined then ignore small gaps before
2252 * the first partition */
2253 if ((!pa || !fdisk_partition_has_start(pa))
02a376f2 2254 && gpt_entry_is_used(e)
b28df75e 2255 && disk_f < gpt_partition_start(e)) {
4a4616b2
KZ
2256
2257 do {
2258 uint64_t x;
fdbd7bb9 2259 DBG(LABEL, ul_debug("testing first sector %"PRIu64"", disk_f));
b28df75e 2260 disk_f = find_first_available(gpt, disk_f);
4a4616b2
KZ
2261 if (!disk_f)
2262 break;
b28df75e 2263 x = find_last_free(gpt, disk_f);
4a4616b2
KZ
2264 if (x - disk_f >= cxt->grain / cxt->sector_size)
2265 break;
fdbd7bb9 2266 DBG(LABEL, ul_debug("first sector %"PRIu64" addresses to small space, continue...", disk_f));
0a7cdf80 2267 disk_f = x + 1ULL;
4a4616b2
KZ
2268 } while(1);
2269
2270 if (disk_f == 0)
b28df75e 2271 disk_f = find_first_available(gpt, le64_to_cpu(pheader->first_usable_lba));
4a4616b2
KZ
2272 }
2273
b28df75e
KZ
2274 e = NULL;
2275 disk_l = find_last_free_sector(gpt);
512a430f
KZ
2276
2277 /* the default is the largest free space */
b28df75e
KZ
2278 dflt_f = find_first_in_largest(gpt);
2279 dflt_l = find_last_free(gpt, dflt_f);
512a430f
KZ
2280
2281 /* align the default in range <dflt_f,dflt_l>*/
9475cc78 2282 dflt_f = fdisk_align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l);
766d5156 2283
77d6a70a 2284 /* first sector */
ecf40cda
KZ
2285 if (pa && pa->start_follow_default) {
2286 user_f = dflt_f;
2287
2288 } else if (pa && fdisk_partition_has_start(pa)) {
fdbd7bb9 2289 DBG(LABEL, ul_debug("first sector defined: %ju", (uintmax_t)pa->start));
b28df75e 2290 if (pa->start != find_first_available(gpt, pa->start)) {
fdbd7bb9 2291 fdisk_warnx(cxt, _("Sector %ju already used."), (uintmax_t)pa->start);
77d6a70a 2292 return -ERANGE;
e3443e8f 2293 }
77d6a70a 2294 user_f = pa->start;
77d6a70a
KZ
2295 } else {
2296 /* ask by dialog */
2297 for (;;) {
2298 if (!ask)
2299 ask = fdisk_new_ask();
2300 else
2301 fdisk_reset_ask(ask);
2302
2303 /* First sector */
2304 fdisk_ask_set_query(ask, _("First sector"));
2305 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
2306 fdisk_ask_number_set_low(ask, disk_f); /* minimal */
2307 fdisk_ask_number_set_default(ask, dflt_f); /* default */
2308 fdisk_ask_number_set_high(ask, disk_l); /* maximal */
2309
2310 rc = fdisk_do_ask(cxt, ask);
2311 if (rc)
2312 goto done;
2313
2314 user_f = fdisk_ask_number_get_result(ask);
b28df75e 2315 if (user_f != find_first_available(gpt, user_f)) {
77d6a70a
KZ
2316 fdisk_warnx(cxt, _("Sector %ju already used."), user_f);
2317 continue;
2318 }
512a430f 2319 break;
77d6a70a
KZ
2320 }
2321 }
2322
1240f549 2323
77d6a70a 2324 /* Last sector */
b28df75e 2325 dflt_l = find_last_free(gpt, user_f);
77d6a70a 2326
ecf40cda
KZ
2327 if (pa && pa->end_follow_default) {
2328 user_l = dflt_l;
2329
2330 } else if (pa && fdisk_partition_has_size(pa)) {
ee50336c 2331 user_l = user_f + pa->size - 1;
fdbd7bb9
RM
2332 DBG(LABEL, ul_debug("size defined: %ju, end: %"PRIu64" (last possible: %"PRIu64")",
2333 (uintmax_t)pa->size, user_l, dflt_l));
68fe4b28 2334 if (user_l != dflt_l && !pa->size_explicit
d527d2dd 2335 && user_l - user_f > (cxt->grain / fdisk_get_sector_size(cxt))) {
68fe4b28
KZ
2336 user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l);
2337 if (user_l > user_f)
0a7cdf80 2338 user_l -= 1ULL;
68fe4b28 2339 }
77d6a70a
KZ
2340 } else {
2341 for (;;) {
2342 if (!ask)
2343 ask = fdisk_new_ask();
2344 else
2345 fdisk_reset_ask(ask);
7c43fd23
KZ
2346 if (!ask)
2347 return -ENOMEM;
77d6a70a
KZ
2348
2349 fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}"));
2350 fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
2351 fdisk_ask_number_set_low(ask, user_f); /* minimal */
2352 fdisk_ask_number_set_default(ask, dflt_l); /* default */
2353 fdisk_ask_number_set_high(ask, dflt_l); /* maximal */
2354 fdisk_ask_number_set_base(ask, user_f); /* base for relative input */
2355 fdisk_ask_number_set_unit(ask, cxt->sector_size);
2356
2357 rc = fdisk_do_ask(cxt, ask);
2358 if (rc)
2359 goto done;
2360
2361 user_l = fdisk_ask_number_get_result(ask);
1240f549 2362 if (fdisk_ask_number_is_relative(ask)) {
765004f3
KZ
2363 user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l);
2364 if (user_l > user_f)
0a7cdf80 2365 user_l -= 1ULL;
0c344037 2366 }
18b266ce 2367
765004f3 2368 if (user_l >= user_f && user_l <= disk_l)
77d6a70a 2369 break;
8c73e509
KZ
2370
2371 fdisk_warnx(cxt, _("Value out of range."));
77d6a70a 2372 }
766d5156
DB
2373 }
2374
8d95e7e0
KZ
2375
2376 if (user_f > user_l || partnum >= cxt->label->nparts_max) {
27aadd8b 2377 fdisk_warnx(cxt, _("Could not create partition %zu"), partnum + 1);
8d95e7e0 2378 rc = -EINVAL;
1240f549 2379 goto done;
8d95e7e0
KZ
2380 }
2381
3fd1f771 2382 /* Be paranoid and check against on-disk setting rather than against libfdisk cxt */
9d9a1b87
KZ
2383 if (user_l > le64_to_cpu(pheader->last_usable_lba)) {
2384 fdisk_warnx(cxt, _("The last usable GPT sector is %ju, but %ju is requested."),
2385 le64_to_cpu(pheader->last_usable_lba), user_l);
2386 rc = -EINVAL;
2387 goto done;
2388 }
2389
2390 if (user_f < le64_to_cpu(pheader->first_usable_lba)) {
2391 fdisk_warnx(cxt, _("The first usable GPT sector is %ju, but %ju is requested."),
2392 le64_to_cpu(pheader->first_usable_lba), user_f);
2393 rc = -EINVAL;
2394 goto done;
2395 }
2396
ecf40cda
KZ
2397 assert(!FDISK_IS_UNDEF(user_l));
2398 assert(!FDISK_IS_UNDEF(user_f));
b683c081 2399 assert(partnum < gpt_get_nentries(gpt));
ecf40cda 2400
b28df75e 2401 e = gpt_get_entry(gpt, partnum);
8d95e7e0
KZ
2402 e->lba_end = cpu_to_le64(user_l);
2403 e->lba_start = cpu_to_le64(user_f);
2404
2405 gpt_entry_set_type(e, &typeid);
2406
2407 if (pa && pa->uuid) {
2408 /* Sometimes it's necessary to create a copy of the PT and
2409 * reuse already defined UUID
2410 */
2411 rc = gpt_entry_set_uuid(e, pa->uuid);
2412 if (rc)
2413 goto done;
1240f549 2414 } else {
8d95e7e0
KZ
2415 /* Any time a new partition entry is created a new GUID must be
2416 * generated for that partition, and every partition is guaranteed
2417 * to have a unique GUID.
2418 */
92e486f8
RM
2419 struct gpt_guid guid;
2420
8d95e7e0 2421 uuid_generate_random((unsigned char *) &e->partition_guid);
92e486f8
RM
2422 guid = e->partition_guid;
2423 swap_efi_guid(&guid);
8d95e7e0
KZ
2424 }
2425
2426 if (pa && pa->name && *pa->name)
2427 gpt_entry_set_name(e, pa->name);
c77ba531
KZ
2428 if (pa && pa->attrs)
2429 gpt_entry_attrs_from_string(cxt, e, pa->attrs);
8d95e7e0 2430
fdbd7bb9 2431 DBG(LABEL, ul_debug("GPT new partition: partno=%zu, start=%"PRIu64", end=%"PRIu64", size=%"PRIu64"",
ee50336c
KZ
2432 partnum,
2433 gpt_partition_start(e),
2434 gpt_partition_end(e),
2435 gpt_partition_size(e)));
2436
b28df75e
KZ
2437 gpt_recompute_crc(gpt->pheader, gpt->ents);
2438 gpt_recompute_crc(gpt->bheader, gpt->ents);
8d95e7e0
KZ
2439
2440 /* report result */
2441 {
a01b5b70
KZ
2442 struct fdisk_parttype *t;
2443
9ffeb235
KZ
2444 cxt->label->nparts_cur++;
2445 fdisk_label_set_changed(cxt->label, 1);
a01b5b70 2446
b28df75e 2447 t = gpt_partition_parttype(cxt, e);
a01b5b70 2448 fdisk_info_new_partition(cxt, partnum + 1, user_f, user_l, t);
dfc6db2a 2449 fdisk_unref_parttype(t);
9fcd49d5 2450 }
8254c3a5 2451
4114da08 2452 rc = 0;
c3bc7483
KZ
2453 if (partno)
2454 *partno = partnum;
4114da08 2455done:
a3d83488 2456 fdisk_unref_ask(ask);
4114da08 2457 return rc;
766d5156
DB
2458}
2459
3f731001
DB
2460/*
2461 * Create a new GPT disklabel - destroys any previous data.
2462 */
9ffeb235 2463static int gpt_create_disklabel(struct fdisk_context *cxt)
3f731001
DB
2464{
2465 int rc = 0;
5eaeb585 2466 size_t esz = 0;
21fe3dde 2467 char str[37];
9ffeb235 2468 struct fdisk_gpt_label *gpt;
92e486f8 2469 struct gpt_guid guid;
9ffeb235
KZ
2470
2471 assert(cxt);
2472 assert(cxt->label);
aa36c2cf 2473 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
2474
2475 gpt = self_label(cxt);
3f731001 2476
d71ef5a4 2477 /* label private stuff has to be empty, see gpt_deinit() */
d71ef5a4
KZ
2478 assert(gpt->pheader == NULL);
2479 assert(gpt->bheader == NULL);
4e0e8253 2480
3f731001 2481 /*
3f731001
DB
2482 * When no header, entries or pmbr is set, we're probably
2483 * dealing with a new, empty disk - so always allocate memory
2484 * to deal with the data structures whatever the case is.
2485 */
3f731001
DB
2486 rc = gpt_mknew_pmbr(cxt);
2487 if (rc < 0)
2488 goto done;
2489
4bb82a45
KZ
2490 assert(cxt->sector_size >= sizeof(struct gpt_header));
2491
d71ef5a4 2492 /* primary */
4bb82a45 2493 gpt->pheader = calloc(1, cxt->sector_size);
46667ba4
KZ
2494 if (!gpt->pheader) {
2495 rc = -ENOMEM;
2496 goto done;
2497 }
d71ef5a4 2498 rc = gpt_mknew_header(cxt, gpt->pheader, GPT_PRIMARY_PARTITION_TABLE_LBA);
3f731001
DB
2499 if (rc < 0)
2500 goto done;
2501
d71ef5a4 2502 /* backup ("copy" primary) */
4bb82a45 2503 gpt->bheader = calloc(1, cxt->sector_size);
46667ba4
KZ
2504 if (!gpt->bheader) {
2505 rc = -ENOMEM;
2506 goto done;
2507 }
d71ef5a4
KZ
2508 rc = gpt_mknew_header_from_bkp(cxt, gpt->bheader,
2509 last_lba(cxt), gpt->pheader);
3f731001
DB
2510 if (rc < 0)
2511 goto done;
2512
9e320545
KZ
2513 rc = gpt_sizeof_ents(gpt->pheader, &esz);
2514 if (rc)
2515 goto done;
46667ba4
KZ
2516 gpt->ents = calloc(1, esz);
2517 if (!gpt->ents) {
2518 rc = -ENOMEM;
2519 goto done;
2520 }
d71ef5a4
KZ
2521 gpt_recompute_crc(gpt->pheader, gpt->ents);
2522 gpt_recompute_crc(gpt->bheader, gpt->ents);
3f731001 2523
b683c081 2524 cxt->label->nparts_max = gpt_get_nentries(gpt);
9ffeb235 2525 cxt->label->nparts_cur = 0;
9fcd49d5 2526
92e486f8
RM
2527 guid = gpt->pheader->disk_guid;
2528 guid_to_string(&guid, str);
9ffeb235 2529 fdisk_label_set_changed(cxt->label, 1);
0477369a 2530 fdisk_info(cxt, _("Created a new GPT disklabel (GUID: %s)."), str);
3f731001
DB
2531done:
2532 return rc;
2533}
2534
35b1f0a4
KZ
2535static int gpt_set_disklabel_id(struct fdisk_context *cxt)
2536{
2537 struct fdisk_gpt_label *gpt;
2538 struct gpt_guid uuid;
2539 char *str, *old, *new;
2540 int rc;
2541
2542 assert(cxt);
2543 assert(cxt->label);
aa36c2cf 2544 assert(fdisk_is_label(cxt, GPT));
35b1f0a4
KZ
2545
2546 gpt = self_label(cxt);
2547 if (fdisk_ask_string(cxt,
2548 _("Enter new disk UUID (in 8-4-4-4-12 format)"), &str))
2549 return -EINVAL;
2550
2551 rc = string_to_guid(str, &uuid);
2552 free(str);
2553
2554 if (rc) {
2555 fdisk_warnx(cxt, _("Failed to parse your UUID."));
2556 return rc;
2557 }
2558
5989556a 2559 old = gpt_get_header_id(gpt->pheader);
35b1f0a4
KZ
2560
2561 gpt->pheader->disk_guid = uuid;
2562 gpt->bheader->disk_guid = uuid;
2563
2564 gpt_recompute_crc(gpt->pheader, gpt->ents);
2565 gpt_recompute_crc(gpt->bheader, gpt->ents);
2566
5989556a 2567 new = gpt_get_header_id(gpt->pheader);
35b1f0a4 2568
0477369a 2569 fdisk_info(cxt, _("Disk identifier changed from %s to %s."), old, new);
35b1f0a4
KZ
2570
2571 free(old);
2572 free(new);
2573 fdisk_label_set_changed(cxt->label, 1);
2574 return 0;
2575}
2576
a18e726c
SP
2577static int gpt_check_table_overlap(struct fdisk_context *cxt,
2578 uint64_t first_usable,
2579 uint64_t last_usable)
2580{
2581 struct fdisk_gpt_label *gpt = self_label(cxt);
b683c081 2582 size_t i;
a18e726c
SP
2583 int rc = 0;
2584
2585 /* First check if there's enough room for the table. last_lba may have wrapped */
2586 if (first_usable > cxt->total_sectors || /* far too little space */
2587 last_usable > cxt->total_sectors || /* wrapped */
2588 first_usable > last_usable) { /* too little space */
2589 fdisk_warnx(cxt, _("Not enough space for new partition table!"));
2590 return -ENOSPC;
2591 }
2592
2593 /* check that all partitions fit in the remaining space */
b683c081 2594 for (i = 0; i < gpt_get_nentries(gpt); i++) {
b28df75e
KZ
2595 struct gpt_entry *e = gpt_get_entry(gpt, i);
2596
02a376f2 2597 if (!gpt_entry_is_used(e))
a18e726c 2598 continue;
b28df75e 2599 if (gpt_partition_start(e) < first_usable) {
b683c081 2600 fdisk_warnx(cxt, _("Partition #%zu out of range (minimal start is %"PRIu64" sectors)"),
a18e726c
SP
2601 i + 1, first_usable);
2602 rc = -EINVAL;
2603 }
b28df75e 2604 if (gpt_partition_end(e) > last_usable) {
b683c081 2605 fdisk_warnx(cxt, _("Partition #%zu out of range (maximal end is %"PRIu64" sectors)"),
0a7cdf80 2606 i + 1, last_usable - 1ULL);
a18e726c
SP
2607 rc = -EINVAL;
2608 }
2609 }
2610 return rc;
2611}
2612
f88eeb25
KZ
2613/**
2614 * fdisk_gpt_set_npartitions:
2615 * @cxt: context
81b176c4 2616 * @entries: new size
f88eeb25
KZ
2617 *
2618 * Elarge GPT entries array if possible. The function check if an existing
2619 * partition does not overlap the entries array area. If yes, then it report
2620 * warning and returns -EINVAL.
2621 *
2622 * Returns: 0 on success, < 0 on error.
81b176c4 2623 * Since: 2.29
f88eeb25 2624 */
81b176c4 2625int fdisk_gpt_set_npartitions(struct fdisk_context *cxt, uint32_t entries)
a18e726c
SP
2626{
2627 struct fdisk_gpt_label *gpt;
2628 size_t old_size, new_size;
f88eeb25 2629 uint32_t old;
a18e726c
SP
2630 uint64_t first_usable, last_usable;
2631 int rc;
2632
2633 assert(cxt);
2634 assert(cxt->label);
21f1206a
KZ
2635
2636 if (!fdisk_is_label(cxt, GPT))
2637 return -EINVAL;
a18e726c
SP
2638
2639 gpt = self_label(cxt);
2640
2641 old = le32_to_cpu(gpt->pheader->npartition_entries);
81b176c4 2642 if (old == entries)
a67054f9 2643 return 0; /* do nothing, say nothing */
a18e726c
SP
2644
2645 /* calculate the size (bytes) of the entries array */
9e320545
KZ
2646 rc = gpt_calculate_sizeof_ents(gpt->pheader, entries, &new_size);
2647 if (rc) {
0508f347 2648 fdisk_warnx(cxt, _("The number of the partition has to be smaller than %zu."),
f71b96bf 2649 UINT32_MAX / le32_to_cpu(gpt->pheader->sizeof_partition_entry));
9e320545 2650 return rc;
f71b96bf
KZ
2651 }
2652
9e320545
KZ
2653 rc = gpt_calculate_sizeof_ents(gpt->pheader, old, &old_size);
2654 if (rc)
2655 return rc;
a18e726c
SP
2656
2657 /* calculate new range of usable LBAs */
f88eeb25
KZ
2658 first_usable = (uint64_t) (new_size / cxt->sector_size) + 2ULL;
2659 last_usable = cxt->total_sectors - 2ULL - (uint64_t) (new_size / cxt->sector_size);
a18e726c
SP
2660
2661 /* if expanding the table, first check that everything fits,
2662 * then allocate more memory and zero. */
81b176c4 2663 if (entries > old) {
b28df75e
KZ
2664 unsigned char *ents;
2665
a18e726c
SP
2666 rc = gpt_check_table_overlap(cxt, first_usable, last_usable);
2667 if (rc)
2668 return rc;
2669 ents = realloc(gpt->ents, new_size);
2670 if (!ents) {
2671 fdisk_warnx(cxt, _("Cannot allocate memory!"));
2672 return -ENOMEM;
2673 }
52f35f1e 2674 memset(ents + old_size, 0, new_size - old_size);
a18e726c
SP
2675 gpt->ents = ents;
2676 }
2677
2678 /* everything's ok, apply the new size */
81b176c4
KZ
2679 gpt->pheader->npartition_entries = cpu_to_le32(entries);
2680 gpt->bheader->npartition_entries = cpu_to_le32(entries);
a18e726c
SP
2681
2682 /* usable LBA addresses will have changed */
2683 fdisk_set_first_lba(cxt, first_usable);
2684 fdisk_set_last_lba(cxt, last_usable);
2685 gpt->pheader->first_usable_lba = cpu_to_le64(first_usable);
2686 gpt->bheader->first_usable_lba = cpu_to_le64(first_usable);
2687 gpt->pheader->last_usable_lba = cpu_to_le64(last_usable);
2688 gpt->bheader->last_usable_lba = cpu_to_le64(last_usable);
2689
2690
2691 /* The backup header must be recalculated */
2692 gpt_mknew_header_common(cxt, gpt->bheader, le64_to_cpu(gpt->pheader->alternative_lba));
2693
2694 /* CRCs will have changed */
2695 gpt_recompute_crc(gpt->pheader, gpt->ents);
2696 gpt_recompute_crc(gpt->bheader, gpt->ents);
2697
bbb574a2
KZ
2698 /* update library info */
2699 cxt->label->nparts_max = gpt_get_nentries(gpt);
2700
81b176c4 2701 fdisk_info(cxt, _("Partition table length changed from %"PRIu32" to %"PRIu64"."), old, entries);
a18e726c
SP
2702
2703 fdisk_label_set_changed(cxt->label, 1);
2704 return 0;
2705}
2706
8c0a7f91 2707static int gpt_part_is_used(struct fdisk_context *cxt, size_t i)
47b8e7c0 2708{
9ffeb235 2709 struct fdisk_gpt_label *gpt;
47b8e7c0
KZ
2710 struct gpt_entry *e;
2711
9ffeb235
KZ
2712 assert(cxt);
2713 assert(cxt->label);
aa36c2cf 2714 assert(fdisk_is_label(cxt, GPT));
9ffeb235
KZ
2715
2716 gpt = self_label(cxt);
2717
b683c081 2718 if (i >= gpt_get_nentries(gpt))
8c0a7f91 2719 return 0;
b28df75e
KZ
2720
2721 e = gpt_get_entry(gpt, i);
47b8e7c0 2722
02a376f2 2723 return gpt_entry_is_used(e) || gpt_partition_start(e);
47b8e7c0
KZ
2724}
2725
0077e7cd
KZ
2726/**
2727 * fdisk_gpt_is_hybrid:
2728 * @cxt: context
2729 *
2730 * The regular GPT contains PMBR (dummy protective MBR) where the protective
2731 * MBR does not address any partitions.
2732 *
2733 * Hybrid GPT contains regular MBR where this partition table addresses the
2734 * same partitions as GPT. It's recommended to not use hybrid GPT due to MBR
2735 * limits.
2736 *
2737 * The libfdisk does not provide functionality to sync GPT and MBR, you have to
2738 * directly access and modify (P)MBR (see fdisk_new_nested_context()).
2739 *
2740 * Returns: 1 if partition table detected as hybrid otherwise return 0
2741 */
433d05ff
KZ
2742int fdisk_gpt_is_hybrid(struct fdisk_context *cxt)
2743{
2744 assert(cxt);
2745 return valid_pmbr(cxt) == GPT_MBR_HYBRID;
2746}
2747
4a4a0927
MM
2748/**
2749 * fdisk_gpt_get_partition_attrs:
2750 * @cxt: context
2751 * @partnum: partition number
2752 * @attrs: GPT partition attributes
2753 *
2754 * Sets @attrs for the given partition
2755 *
2756 * Returns: 0 on success, <0 on error.
2757 */
2758int fdisk_gpt_get_partition_attrs(
2759 struct fdisk_context *cxt,
2760 size_t partnum,
2761 uint64_t *attrs)
2762{
2763 struct fdisk_gpt_label *gpt;
2764
2765 assert(cxt);
2766 assert(cxt->label);
21f1206a
KZ
2767
2768 if (!fdisk_is_label(cxt, GPT))
2769 return -EINVAL;
4a4a0927
MM
2770
2771 gpt = self_label(cxt);
2772
b683c081 2773 if (partnum >= gpt_get_nentries(gpt))
4a4a0927
MM
2774 return -EINVAL;
2775
b28df75e 2776 *attrs = le64_to_cpu(gpt_get_entry(gpt, partnum)->attrs);
4a4a0927
MM
2777 return 0;
2778}
2779
2780/**
2781 * fdisk_gpt_set_partition_attrs:
2782 * @cxt: context
2783 * @partnum: partition number
2784 * @attrs: GPT partition attributes
2785 *
2786 * Sets the GPT partition attributes field to @attrs.
2787 *
2788 * Returns: 0 on success, <0 on error.
2789 */
2790int fdisk_gpt_set_partition_attrs(
2791 struct fdisk_context *cxt,
2792 size_t partnum,
2793 uint64_t attrs)
2794{
2795 struct fdisk_gpt_label *gpt;
2796
2797 assert(cxt);
2798 assert(cxt->label);
21f1206a
KZ
2799
2800 if (!fdisk_is_label(cxt, GPT))
2801 return -EINVAL;
4a4a0927
MM
2802
2803 DBG(LABEL, ul_debug("GPT entry attributes change requested partno=%zu", partnum));
2804 gpt = self_label(cxt);
2805
b683c081 2806 if (partnum >= gpt_get_nentries(gpt))
4a4a0927
MM
2807 return -EINVAL;
2808
b28df75e 2809 gpt_get_entry(gpt, partnum)->attrs = cpu_to_le64(attrs);
4a4a0927
MM
2810 fdisk_info(cxt, _("The attributes on partition %zu changed to 0x%016" PRIx64 "."),
2811 partnum + 1, attrs);
2812
2813 gpt_recompute_crc(gpt->pheader, gpt->ents);
2814 gpt_recompute_crc(gpt->bheader, gpt->ents);
2815 fdisk_label_set_changed(cxt->label, 1);
2816 return 0;
2817}
2818
c83f772e
KZ
2819static int gpt_toggle_partition_flag(
2820 struct fdisk_context *cxt,
2821 size_t i,
2822 unsigned long flag)
2823{
2824 struct fdisk_gpt_label *gpt;
b28df75e 2825 struct gpt_entry *e;
262c94c2
RM
2826 uint64_t attrs;
2827 uintmax_t tmp;
01086b80
KZ
2828 char *bits;
2829 const char *name = NULL;
2830 int bit = -1, rc;
c83f772e
KZ
2831
2832 assert(cxt);
2833 assert(cxt->label);
aa36c2cf 2834 assert(fdisk_is_label(cxt, GPT));
c83f772e 2835
88141067 2836 DBG(LABEL, ul_debug("GPT entry attribute change requested partno=%zu", i));
c83f772e
KZ
2837 gpt = self_label(cxt);
2838
b683c081 2839 if (i >= gpt_get_nentries(gpt))
c83f772e
KZ
2840 return -EINVAL;
2841
b28df75e
KZ
2842 e = gpt_get_entry(gpt, i);
2843 attrs = e->attrs;
01086b80 2844 bits = (char *) &attrs;
c83f772e
KZ
2845
2846 switch (flag) {
2847 case GPT_FLAG_REQUIRED:
01086b80
KZ
2848 bit = GPT_ATTRBIT_REQ;
2849 name = GPT_ATTRSTR_REQ;
c83f772e
KZ
2850 break;
2851 case GPT_FLAG_NOBLOCK:
01086b80
KZ
2852 bit = GPT_ATTRBIT_NOBLOCK;
2853 name = GPT_ATTRSTR_NOBLOCK;
c83f772e
KZ
2854 break;
2855 case GPT_FLAG_LEGACYBOOT:
01086b80
KZ
2856 bit = GPT_ATTRBIT_LEGACY;
2857 name = GPT_ATTRSTR_LEGACY;
c83f772e
KZ
2858 break;
2859 case GPT_FLAG_GUIDSPECIFIC:
01086b80 2860 rc = fdisk_ask_number(cxt, 48, 48, 63, _("Enter GUID specific bit"), &tmp);
c83f772e
KZ
2861 if (rc)
2862 return rc;
01086b80
KZ
2863 bit = tmp;
2864 break;
773aae5c
KZ
2865 default:
2866 /* already specified PT_FLAG_GUIDSPECIFIC bit */
2867 if (flag >= 48 && flag <= 63) {
2868 bit = flag;
2869 flag = GPT_FLAG_GUIDSPECIFIC;
2870 }
2871 break;
01086b80 2872 }
c83f772e 2873
773aae5c
KZ
2874 if (bit < 0) {
2875 fdisk_warnx(cxt, _("failed to toggle unsupported bit %lu"), flag);
01086b80 2876 return -EINVAL;
773aae5c 2877 }
01086b80
KZ
2878
2879 if (!isset(bits, bit))
2880 setbit(bits, bit);
2881 else
2882 clrbit(bits, bit);
2883
b28df75e 2884 e->attrs = attrs;
01086b80
KZ
2885
2886 if (flag == GPT_FLAG_GUIDSPECIFIC)
0477369a 2887 fdisk_info(cxt, isset(bits, bit) ?
01086b80
KZ
2888 _("The GUID specific bit %d on partition %zu is enabled now.") :
2889 _("The GUID specific bit %d on partition %zu is disabled now."),
c83f772e 2890 bit, i + 1);
01086b80 2891 else
0477369a 2892 fdisk_info(cxt, isset(bits, bit) ?
01086b80
KZ
2893 _("The %s flag on partition %zu is enabled now.") :
2894 _("The %s flag on partition %zu is disabled now."),
2895 name, i + 1);
c83f772e
KZ
2896
2897 gpt_recompute_crc(gpt->pheader, gpt->ents);
2898 gpt_recompute_crc(gpt->bheader, gpt->ents);
01086b80 2899 fdisk_label_set_changed(cxt->label, 1);
c83f772e
KZ
2900 return 0;
2901}
1054699c 2902
9348ef25
KZ
2903static int gpt_entry_cmp_start(const void *a, const void *b)
2904{
2905 struct gpt_entry *ae = (struct gpt_entry *) a,
2906 *be = (struct gpt_entry *) b;
02a376f2
KZ
2907 int au = gpt_entry_is_used(ae),
2908 bu = gpt_entry_is_used(be);
9348ef25 2909
02a376f2 2910 if (!au && !bu)
9348ef25 2911 return 0;
02a376f2 2912 if (!au)
9348ef25 2913 return 1;
02a376f2 2914 if (!bu)
9348ef25
KZ
2915 return -1;
2916
19ff8ff7 2917 return cmp_numbers(gpt_partition_start(ae), gpt_partition_start(be));
9348ef25
KZ
2918}
2919
2920/* sort partition by start sector */
2921static int gpt_reorder(struct fdisk_context *cxt)
2922{
2923 struct fdisk_gpt_label *gpt;
dd49c7d6 2924 size_t i, nparts, mess;
9348ef25
KZ
2925
2926 assert(cxt);
2927 assert(cxt->label);
aa36c2cf 2928 assert(fdisk_is_label(cxt, GPT));
9348ef25
KZ
2929
2930 gpt = self_label(cxt);
b683c081 2931 nparts = gpt_get_nentries(gpt);
9348ef25 2932
dd49c7d6
KZ
2933 for (i = 0, mess = 0; mess == 0 && i + 1 < nparts; i++)
2934 mess = gpt_entry_cmp_start(
b28df75e
KZ
2935 (const void *) gpt_get_entry(gpt, i),
2936 (const void *) gpt_get_entry(gpt, i + 1)) > 0;
dd49c7d6
KZ
2937
2938 if (!mess) {
2939 fdisk_info(cxt, _("Nothing to do. Ordering is correct already."));
2940 return 1;
2941 }
2942
9348ef25
KZ
2943 qsort(gpt->ents, nparts, sizeof(struct gpt_entry),
2944 gpt_entry_cmp_start);
2945
2946 gpt_recompute_crc(gpt->pheader, gpt->ents);
2947 gpt_recompute_crc(gpt->bheader, gpt->ents);
2948 fdisk_label_set_changed(cxt->label, 1);
2949
9348ef25
KZ
2950 return 0;
2951}
2952
1240f549
KZ
2953static int gpt_reset_alignment(struct fdisk_context *cxt)
2954{
2955 struct fdisk_gpt_label *gpt;
2956 struct gpt_header *h;
2957
2958 assert(cxt);
2959 assert(cxt->label);
aa36c2cf 2960 assert(fdisk_is_label(cxt, GPT));
1240f549
KZ
2961
2962 gpt = self_label(cxt);
2963 h = gpt ? gpt->pheader : NULL;
2964
2965 if (h) {
2966 /* always follow existing table */
43a2b094
KZ
2967 cxt->first_lba = le64_to_cpu(h->first_usable_lba);
2968 cxt->last_lba = le64_to_cpu(h->last_usable_lba);
1240f549
KZ
2969 } else {
2970 /* estimate ranges for GPT */
2971 uint64_t first, last;
2972
2973 count_first_last_lba(cxt, &first, &last);
2974
2975 if (cxt->first_lba < first)
2976 cxt->first_lba = first;
2977 if (cxt->last_lba > last)
2978 cxt->last_lba = last;
2979 }
2980
2981 return 0;
2982}
4e0e8253
KZ
2983/*
2984 * Deinitialize fdisk-specific variables
2985 */
d71ef5a4 2986static void gpt_deinit(struct fdisk_label *lb)
4e0e8253 2987{
d71ef5a4
KZ
2988 struct fdisk_gpt_label *gpt = (struct fdisk_gpt_label *) lb;
2989
2990 if (!gpt)
2991 return;
2992
2993 free(gpt->ents);
2994 free(gpt->pheader);
2995 free(gpt->bheader);
2996
2997 gpt->ents = NULL;
2998 gpt->pheader = NULL;
2999 gpt->bheader = NULL;
4e0e8253
KZ
3000}
3001
0c5d095e 3002static const struct fdisk_label_operations gpt_operations =
766d5156 3003{
0c5d095e
KZ
3004 .probe = gpt_probe_label,
3005 .write = gpt_write_disklabel,
3006 .verify = gpt_verify_disklabel,
3007 .create = gpt_create_disklabel,
775001ad 3008 .locate = gpt_locate_disklabel,
5989556a 3009 .get_item = gpt_get_disklabel_item,
35b1f0a4 3010 .set_id = gpt_set_disklabel_id,
21fe3dde 3011
8c0a7f91 3012 .get_part = gpt_get_partition,
b0a484a8 3013 .set_part = gpt_set_partition,
77d6a70a 3014 .add_part = gpt_add_partition,
e11c6684 3015 .del_part = gpt_delete_partition,
5989556a 3016 .reorder = gpt_reorder,
8c0a7f91
KZ
3017
3018 .part_is_used = gpt_part_is_used,
c83f772e 3019 .part_toggle_flag = gpt_toggle_partition_flag,
4e0e8253 3020
1240f549
KZ
3021 .deinit = gpt_deinit,
3022
3023 .reset_alignment = gpt_reset_alignment
766d5156 3024};
0c5d095e 3025
bd85d11f 3026static const struct fdisk_field gpt_fields[] =
6941952e
KZ
3027{
3028 /* basic */
bd85d11f
KZ
3029 { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 },
3030 { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER },
3031 { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER },
3032 { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER },
bd85d11f
KZ
3033 { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY },
3034 { FDISK_FIELD_TYPE, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY },
6941952e 3035 /* expert */
bd85d11f
KZ
3036 { FDISK_FIELD_TYPEID, N_("Type-UUID"), 36, FDISK_FIELDFL_DETAIL },
3037 { FDISK_FIELD_UUID, N_("UUID"), 36, FDISK_FIELDFL_DETAIL },
3038 { FDISK_FIELD_NAME, N_("Name"), 0.2, FDISK_FIELDFL_DETAIL },
3039 { FDISK_FIELD_ATTR, N_("Attrs"), 0, FDISK_FIELDFL_DETAIL }
6941952e
KZ
3040};
3041
0c5d095e
KZ
3042/*
3043 * allocates GPT in-memory stuff
3044 */
3045struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt)
3046{
3047 struct fdisk_label *lb;
3048 struct fdisk_gpt_label *gpt;
3049
3050 assert(cxt);
3051
3052 gpt = calloc(1, sizeof(*gpt));
3053 if (!gpt)
3054 return NULL;
3055
3056 /* initialize generic part of the driver */
3057 lb = (struct fdisk_label *) gpt;
3058 lb->name = "gpt";
53b422ab 3059 lb->id = FDISK_DISKLABEL_GPT;
0c5d095e
KZ
3060 lb->op = &gpt_operations;
3061 lb->parttypes = gpt_parttypes;
3062 lb->nparttypes = ARRAY_SIZE(gpt_parttypes);
3063
bd85d11f
KZ
3064 lb->fields = gpt_fields;
3065 lb->nfields = ARRAY_SIZE(gpt_fields);
6941952e 3066
0c5d095e
KZ
3067 return lb;
3068}
4a4a0927
MM
3069
3070#ifdef TEST_PROGRAM
5fde1d9f 3071static int test_getattr(struct fdisk_test *ts, int argc, char *argv[])
4a4a0927
MM
3072{
3073 const char *disk = argv[1];
3074 size_t part = strtoul(argv[2], NULL, 0) - 1;
3075 struct fdisk_context *cxt;
3076 uint64_t atters = 0;
3077
3078 cxt = fdisk_new_context();
3079 fdisk_assign_device(cxt, disk, 1);
3080
3081 if (!fdisk_is_label(cxt, GPT))
3082 return EXIT_FAILURE;
3083
3084 if (fdisk_gpt_get_partition_attrs(cxt, part, &atters))
3085 return EXIT_FAILURE;
3086
3087 printf("%s: 0x%016" PRIx64 "\n", argv[2], atters);
3088
3089 fdisk_unref_context(cxt);
3090 return 0;
3091}
3092
5fde1d9f 3093static int test_setattr(struct fdisk_test *ts, int argc, char *argv[])
4a4a0927
MM
3094{
3095 const char *disk = argv[1];
3096 size_t part = strtoul(argv[2], NULL, 0) - 1;
3097 uint64_t atters = strtoull(argv[3], NULL, 0);
3098 struct fdisk_context *cxt;
3099
3100 cxt = fdisk_new_context();
3101 fdisk_assign_device(cxt, disk, 0);
3102
3103 if (!fdisk_is_label(cxt, GPT))
3104 return EXIT_FAILURE;
3105
3106 if (fdisk_gpt_set_partition_attrs(cxt, part, atters))
3107 return EXIT_FAILURE;
3108
3109 if (fdisk_write_disklabel(cxt))
3110 return EXIT_FAILURE;
3111
3112 fdisk_unref_context(cxt);
3113 return 0;
3114}
3115
3116int main(int argc, char *argv[])
3117{
3118 struct fdisk_test tss[] = {
3119 { "--getattr", test_getattr, "<disk> <partition> print attributes" },
3120 { "--setattr", test_setattr, "<disk> <partition> <value> set attributes" },
3121 { NULL }
3122 };
3123
3124 return fdisk_run_test(tss, argc, argv);
3125}
3126
3127#endif