xref: /openbsd/sbin/fdisk/part.c (revision 6ba1b8a5)
1*6ba1b8a5Skrw /*	$OpenBSD: part.c,v 1.144 2023/03/30 22:53:39 krw Exp $	*/
2a1705421Sweingart 
3a1705421Sweingart /*
4a1705421Sweingart  * Copyright (c) 1997 Tobias Weingartner
5a1705421Sweingart  *
610a68084Skrw  * Permission to use, copy, modify, and distribute this software for any
710a68084Skrw  * purpose with or without fee is hereby granted, provided that the above
810a68084Skrw  * copyright notice and this permission notice appear in all copies.
9a1705421Sweingart  *
1010a68084Skrw  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1110a68084Skrw  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1210a68084Skrw  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1310a68084Skrw  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1410a68084Skrw  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1510a68084Skrw  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1610a68084Skrw  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1705421Sweingart  */
18a1705421Sweingart 
19a7568474Sderaadt #include <sys/types.h>
20a7568474Sderaadt #include <sys/disklabel.h>
21729290c0Skrw 
22e8252b55Skrw #include <err.h>
2398952941Skrw #include <stdint.h>
24a1705421Sweingart #include <stdio.h>
25fba7235cSkrw #include <stdlib.h>
26184a329bSmillert #include <string.h>
27fba7235cSkrw #include <uuid.h>
28abc6f793Skrw 
29199eafeaSkrw #include "part.h"
30a5472107Skrw #include "disk.h"
31a1705421Sweingart #include "misc.h"
3265deb39bSkrw #include "gpt.h"
33a1705421Sweingart 
345308a554Skrw struct mbr_type {
355308a554Skrw 	int	 mt_type;
3624a7e0ddSkrw 	char	*mt_name;
375308a554Skrw };
385308a554Skrw 
39290491cbSkrw /*
40290491cbSkrw * MBR type sources:
41290491cbSkrw *	OpenBSD Historical usage
42290491cbSkrw * 	https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
43290491cbSkrw *	https://www.win.tue.nl/~aeb/partitions/partition_types-1.html
44290491cbSkrw */
455308a554Skrw const struct mbr_type		mbr_types[] = {
465308a554Skrw 	{ 0x00, "unused"	},   /* unused */
475308a554Skrw 	{ 0x01, "DOS FAT-12"	},   /* Primary DOS with 12 bit FAT */
48764d6d49Stom 	{ 0x02, "XENIX /"	},   /* XENIX / filesystem */
49764d6d49Stom 	{ 0x03, "XENIX /usr"	},   /* XENIX /usr filesystem */
505308a554Skrw 	{ 0x04, "DOS FAT-16"	},   /* Primary DOS with 16 bit FAT */
51764d6d49Stom 	{ 0x05, "Extended DOS"	},   /* Extended DOS */
525308a554Skrw 	{ 0x06, "DOS > 32MB"	},   /* Primary 'big' DOS (> 32MB) */
535308a554Skrw 	{ 0x07, "NTFS"		},   /* NTFS */
54764d6d49Stom 	{ 0x08, "AIX fs"	},   /* AIX filesystem */
55764d6d49Stom 	{ 0x09, "AIX/Coherent"	},   /* AIX boot partition or Coherent */
56764d6d49Stom 	{ 0x0A, "OS/2 Bootmgr"	},   /* OS/2 Boot Manager or OPUS */
575308a554Skrw 	{ 0x0B, "Win95 FAT-32"	},   /* Primary Win95 w/ 32-bit FAT */
585308a554Skrw 	{ 0x0C, "Win95 FAT32L"	},   /* Primary Win95 w/ 32-bit FAT LBA-mapped */
595308a554Skrw 	{ 0x0E, "DOS FAT-16"	},   /* Primary DOS w/ 16-bit FAT, CHS-mapped */
60764d6d49Stom 	{ 0x0F, "Extended LBA"	},   /* Extended DOS LBA-mapped */
61764d6d49Stom 	{ 0x10, "OPUS"		},   /* OPUS */
625308a554Skrw 	{ 0x11, "OS/2 hidden"	},   /* OS/2 BM: hidden DOS 12-bit FAT */
6372c8f31dSkrw 	{ 0x12, "Compaq Diag"	},   /* Compaq Diagnostics */
645308a554Skrw 	{ 0x14, "OS/2 hidden"	},   /* OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug */
655308a554Skrw 	{ 0x16, "OS/2 hidden"	},   /* OS/2 BM: hidden DOS 16-bit FAT >=32M */
665308a554Skrw 	{ 0x17, "OS/2 hidden"	},   /* OS/2 BM: hidden IFS */
67764d6d49Stom 	{ 0x18, "AST swap"	},   /* AST Windows swapfile */
68764d6d49Stom 	{ 0x19, "Willowtech"	},   /* Willowtech Photon coS */
695308a554Skrw 	{ 0x1C, "ThinkPad Rec"	},   /* IBM ThinkPad recovery partition */
70fba7235cSkrw 	{ 0x20, "Willowsoft"	},   /* Willowsoft OFS1 */
715308a554Skrw 	{ 0x24, "NEC DOS"	},   /* NEC DOS */
725308a554Skrw 	{ 0x27, "Win Recovery"	},   /* Windows hidden Recovery Partition */
73764d6d49Stom 	{ 0x38, "Theos"		},   /* Theos */
74764d6d49Stom 	{ 0x39, "Plan 9"	},   /* Plan 9 */
75764d6d49Stom 	{ 0x40, "VENIX 286"	},   /* VENIX 286 or LynxOS */
76764d6d49Stom 	{ 0x41, "Lin/Minux DR" 	},   /* Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot */
775308a554Skrw 	{ 0x42, "LinuxSwap DR" 	},   /* SFS or Linux swap (sharing disk with DRDOS) */
78764d6d49Stom 	{ 0x43, "Linux DR" 	},   /* Linux native (sharing disk with DRDOS) */
79764d6d49Stom 	{ 0x4D, "QNX 4.2 Pri"	},   /* QNX 4.2 Primary */
80764d6d49Stom 	{ 0x4E, "QNX 4.2 Sec"	},   /* QNX 4.2 Secondary */
81764d6d49Stom 	{ 0x4F, "QNX 4.2 Ter"	},   /* QNX 4.2 Tertiary */
82764d6d49Stom 	{ 0x50, "DM"		},   /* DM (disk manager) */
83764d6d49Stom 	{ 0x51, "DM"		},   /* DM6 Aux1 (or Novell) */
84764d6d49Stom 	{ 0x52, "CP/M or SysV"	},   /* CP/M or Microport SysV/AT */
85764d6d49Stom 	{ 0x53, "DM"		},   /* DM6 Aux3 */
86764d6d49Stom 	{ 0x54, "Ontrack"	},   /* Ontrack */
87764d6d49Stom 	{ 0x55, "EZ-Drive"	},   /* EZ-Drive (disk manager) */
88764d6d49Stom 	{ 0x56, "Golden Bow"	},   /* Golden Bow (disk manager) */
89764d6d49Stom 	{ 0x5C, "Priam"		},   /* Priam Edisk (disk manager) */
90764d6d49Stom 	{ 0x61, "SpeedStor"	},   /* SpeedStor */
91764d6d49Stom 	{ 0x63, "ISC, HURD, *"	},   /* ISC, System V/386, GNU HURD or Mach */
92764d6d49Stom 	{ 0x64, "NetWare 2.xx"	},   /* Novell NetWare 2.xx */
93764d6d49Stom 	{ 0x65, "NetWare 3.xx"	},   /* Novell NetWare 3.xx */
94764d6d49Stom 	{ 0x66, "NetWare 386"	},   /* Novell 386 NetWare */
95764d6d49Stom 	{ 0x67, "Novell"	},   /* Novell */
96764d6d49Stom 	{ 0x68, "Novell"	},   /* Novell */
97764d6d49Stom 	{ 0x69, "Novell"	},   /* Novell */
98764d6d49Stom 	{ 0x70, "DiskSecure"	},   /* DiskSecure Multi-Boot */
99764d6d49Stom 	{ 0x75, "PCIX"		},   /* PCIX */
100764d6d49Stom 	{ 0x80, "Minix (old)"	},   /* Minix 1.1 ... 1.4a */
101764d6d49Stom 	{ 0x81, "Minix (new)"	},   /* Minix 1.4b ... 1.5.10 */
1025308a554Skrw 	{ 0x82, "Linux swap"	},   /* Linux swap */
1035308a554Skrw 	{ 0x83, "Linux files*"	},   /* Linux filesystem */
104764d6d49Stom 	{ 0x84, "OS/2 hidden"	},   /* OS/2 hidden C: drive */
105764d6d49Stom 	{ 0x85, "Linux ext."	},   /* Linux extended */
106764d6d49Stom 	{ 0x86, "NT FAT VS"	},   /* NT FAT volume set */
107764d6d49Stom 	{ 0x87, "NTFS VS"	},   /* NTFS volume set or HPFS mirrored */
1085308a554Skrw 	{ 0x8E, "Linux LVM"	},   /* Linux LVM */
109764d6d49Stom 	{ 0x93, "Amoeba FS"	},   /* Amoeba filesystem */
110764d6d49Stom 	{ 0x94, "Amoeba BBT"	},   /* Amoeba bad block table */
111764d6d49Stom 	{ 0x99, "Mylex"		},   /* Mylex EISA SCSI */
112764d6d49Stom 	{ 0x9F, "BSDI"		},   /* BSDI BSD/OS */
113764d6d49Stom 	{ 0xA0, "NotebookSave"	},   /* Phoenix NoteBIOS save-to-disk */
1145308a554Skrw 	{ 0xA5, "FreeBSD"	},   /* FreeBSD */
1155308a554Skrw 	{ 0xA6, "OpenBSD"	},   /* OpenBSD */
116764d6d49Stom 	{ 0xA7, "NEXTSTEP"	},   /* NEXTSTEP */
1175308a554Skrw 	{ 0xA8, "MacOS X"	},   /* MacOS X main partition */
1185308a554Skrw 	{ 0xA9, "NetBSD"	},   /* NetBSD */
1195308a554Skrw 	{ 0xAB, "MacOS X boot"	},   /* MacOS X boot partition */
1205308a554Skrw 	{ 0xAF, "MacOS X HFS+"	},   /* MacOS X HFS+ partition */
121764d6d49Stom 	{ 0xB7, "BSDI filesy*"	},   /* BSDI BSD/386 filesystem */
122764d6d49Stom 	{ 0xB8, "BSDI swap"	},   /* BSDI BSD/386 swap */
1235308a554Skrw 	{ 0xBF, "Solaris"	},   /* Solaris */
124764d6d49Stom 	{ 0xC0, "CTOS"		},   /* CTOS */
125764d6d49Stom 	{ 0xC1, "DRDOSs FAT12"	},   /* DRDOS/sec (FAT-12) */
126764d6d49Stom 	{ 0xC4, "DRDOSs < 32M"	},   /* DRDOS/sec (FAT-16, < 32M) */
127764d6d49Stom 	{ 0xC6, "DRDOSs >=32M"	},   /* DRDOS/sec (FAT-16, >= 32M) */
128764d6d49Stom 	{ 0xC7, "HPFS Disbled"	},   /* Syrinx (Cyrnix?) or HPFS disabled */
129764d6d49Stom 	{ 0xDB, "CPM/C.DOS/C*"	},   /* Concurrent CPM or C.DOS or CTOS */
130764d6d49Stom 	{ 0xDE, "Dell Maint"	},   /* Dell maintenance partition */
131764d6d49Stom 	{ 0xE1, "SpeedStor"	},   /* DOS access or SpeedStor 12-bit FAT extended partition */
132764d6d49Stom 	{ 0xE3, "SpeedStor"	},   /* DOS R/O or SpeedStor or Storage Dimensions */
133764d6d49Stom 	{ 0xE4, "SpeedStor"	},   /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
1345308a554Skrw 	{ 0xEB, "BeOS/i386"	},   /* BeOS for Intel */
1352d874a94Sderaadt 	{ 0xEE, "EFI GPT"	},   /* EFI Protective Partition */
1365308a554Skrw 	{ 0xEF, "EFI Sys"	},   /* EFI System Partition */
137764d6d49Stom 	{ 0xF1, "SpeedStor"	},   /* SpeedStor or Storage Dimensions */
138764d6d49Stom 	{ 0xF2, "DOS 3.3+ Sec"	},   /* DOS 3.3+ Secondary */
139764d6d49Stom 	{ 0xF4, "SpeedStor"	},   /* SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML */
140764d6d49Stom 	{ 0xFF, "Xenix BBT"	},   /* Xenix Bad Block Table */
141a1705421Sweingart };
142a1705421Sweingart 
1435308a554Skrw struct gpt_type {
144e3f6ba90Skrw 	int	 gt_menuid;
145f458660aSkrw 	int	 gt_attr;
146f458660aSkrw #define	GTATTR_PROTECT		(1 << 0)
147f458660aSkrw #define	GTATTR_PROTECT_EFISYS	(1 << 1)
14824a7e0ddSkrw 	char	*gt_name;
149*6ba1b8a5Skrw 	char	*gt_guid;
1505308a554Skrw };
1515308a554Skrw 
152290491cbSkrw /*
153290491cbSkrw  * GPT GUID sources:
154290491cbSkrw  *
155290491cbSkrw  * UEFI: UEFI Specification 2.9, March 2021, Section 5.3.3, Table 5.7
156290491cbSkrw  * Wikipedia: https://en.wikipedia.org/wiki/GUID_Partition_Table
157290491cbSkrw  * NetBSD: /usr/src/sys/sys/disklabel_gpt.h
158290491cbSkrw  * FreeBSD: /usr/src/sys/sys/disk/gpt.h.
159290491cbSkrw  * DragonFlyBSD: /usr/src/sys/sys/disk/gpt.h.
160290491cbSkrw  * Systemd:https://uapi-group.org/specifications/specs/discoverable_partitions_specification/
161290491cbSkrw  *         https://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html
162290491cbSkrw  */
163d6ffd808Skrw 
164*6ba1b8a5Skrw char * const EFI_SYSTEM_PARTITION_GUID = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b";
165*6ba1b8a5Skrw char * const MICROSOFT_BASIC_DATA_GUID = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7";
166d6ffd808Skrw 
1675308a554Skrw const struct gpt_type		gpt_types[] = {
168c96c378cSkrw 	{ 0x00, 0, "unused",
169c96c378cSkrw 	  "00000000-0000-0000-0000-000000000000" },
170c96c378cSkrw 	{ 0x01, 0, "FAT12",
171d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
172c96c378cSkrw 	{ 0x04, 0, "FAT16S",
173d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
174c96c378cSkrw 	{ 0x06, 0, "FAT16B",
175d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
176c96c378cSkrw 	{ 0x07, 0, "NTFS",
177d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
178c96c378cSkrw 	{ 0x0B, 0, "FAT32",
179d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
180c96c378cSkrw 	{ 0x0C, 0, "FAT32L",
181d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
182f458660aSkrw 	{ 0x0D, GTATTR_PROTECT, "BIOS Boot",
183c96c378cSkrw 	  "21686148-6449-6e6f-744e-656564454649" },
184c96c378cSkrw 	{ 0x0E, 0, "FAT16L",
185d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
186c96c378cSkrw 	{ 0x11, 0, "OS/2 hidden",
187d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
188c96c378cSkrw 	{ 0x14, 0, "OS/2 hidden",
189d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
190c96c378cSkrw 	{ 0x16, 0, "OS/2 hidden",
191d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
192c96c378cSkrw 	{ 0x17, 0, "OS/2 hidden",
193d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
194c96c378cSkrw 	{ 0x1C, 0, "ThinkPad Rec",
195d6ffd808Skrw 	  MICROSOFT_BASIC_DATA_GUID },
196c96c378cSkrw 	{ 0x27, 0, "Win Recovery",
197c96c378cSkrw 	  "de94bba4-06d1-4d40-a16a-bfd50179d6ac" },
198c96c378cSkrw 	{ 0x42, 0, "LinuxSwap DR",
199c96c378cSkrw 	  "af9b60a0-1431-4f62-bc68-3311714a69ad" },
200c96c378cSkrw 	{ 0x7f, 0, "ChromeKernel",
201c96c378cSkrw 	  "fe3a2a5d-4f32-41a7-b725-accc3285a309" },
202c96c378cSkrw 	{ 0x82, 0, "Linux swap",
203c96c378cSkrw 	  "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" },
204c96c378cSkrw 	{ 0x83, 0, "Linux files*",
205c96c378cSkrw 	  "0fc63daf-8483-4772-8e79-3d69d8477de4" },
206c96c378cSkrw 	{ 0x8E, 0, "Linux LVM",
207c96c378cSkrw 	  "e6d6d379-f507-44c2-a23c-238f2a3df928" },
208c96c378cSkrw 	{ 0xA5, 0, "FreeBSD",
209c96c378cSkrw 	  "516e7cb4-6ecf-11d6-8ff8-00022d09712b" },
210c96c378cSkrw 	{ 0xA6, 0, "OpenBSD",
211c96c378cSkrw 	  "824cc7a0-36a8-11e3-890a-952519ad3f61" },
212c96c378cSkrw 	{ 0xA8, 0, "MacOS X",
213c96c378cSkrw 	  "55465300-0000-11aa-aa11-00306543ecac" },
214c96c378cSkrw 	{ 0xA9, 0, "NetBSD",
21565c111ddSkrw 	  "49f48d5a-b10e-11dc-b99b-0019d1879648" },
216c96c378cSkrw 	{ 0xAB, 0, "MacOS X boot",
217c96c378cSkrw 	  "426f6f74-0000-11aa-aa11-00306543ecac" },
218c96c378cSkrw 	{ 0xAF, 0, "MacOS X HFS+",
219c96c378cSkrw 	  "48465300-0000-11aa-aa11-00306543ecac" },
220f458660aSkrw 	{ 0xB0, GTATTR_PROTECT | GTATTR_PROTECT_EFISYS, "APFS",
221c96c378cSkrw 	  "7c3457ef-0000-11aa-aa11-00306543ecac" },
222f458660aSkrw 	{ 0xB1, GTATTR_PROTECT | GTATTR_PROTECT_EFISYS, "APFS ISC",
223c96c378cSkrw 	  "69646961-6700-11aa-aa11-00306543ecac" },
224f458660aSkrw 	{ 0xB2, GTATTR_PROTECT | GTATTR_PROTECT_EFISYS, "APFS Recovery",
225c96c378cSkrw 	  "52637672-7900-11aa-aa11-00306543ecac" },
226f458660aSkrw 	{ 0xB3, GTATTR_PROTECT, "HiFive FSBL",
227c96c378cSkrw 	  "5b193300-fc78-40cd-8002-e86c45580b47" },
228f458660aSkrw 	{ 0xB4, GTATTR_PROTECT, "HiFive BBL",
229c96c378cSkrw 	  "2e54b353-1271-4842-806f-e436d6af6985" },
230c96c378cSkrw 	{ 0xBF, 0, "Solaris",
231c96c378cSkrw 	  "6a85cf4d-1dd2-11b2-99a6-080020736631" },
232c96c378cSkrw 	{ 0xEB, 0, "BeOS/i386",
233c96c378cSkrw 	  "42465331-3ba3-10f1-802a-4861696b7521" },
23465c111ddSkrw 	{ 0xEC, 0, "Legacy MBR",
23565c111ddSkrw 	  "024dee41-33e7-11d3-9d69-0008c781f39f" },
236c96c378cSkrw 	{ 0xEF, 0, "EFI Sys",
237e92bde66Skrw 	  EFI_SYSTEM_PARTITION_GUID },
23895e8765cSkrw };
23995e8765cSkrw 
240f2ec1a13Skrw const struct gpt_type	*find_gpt_type(const struct uuid *);
241867d4347Skrw const struct mbr_type	*find_mbr_type(const int);
242f458660aSkrw int			 uuid_attr(const struct uuid *);
243c96c378cSkrw 
244c96c378cSkrw const struct gpt_type *
245c96c378cSkrw find_gpt_type(const struct uuid *uuid)
246c96c378cSkrw {
247c96c378cSkrw 	char			*uuidstr = NULL;
248c96c378cSkrw 	unsigned int		 i;
249c96c378cSkrw 	uint32_t		 status;
250c96c378cSkrw 
251c96c378cSkrw 	uuid_to_string(uuid, &uuidstr, &status);
252c96c378cSkrw 	if (status == uuid_s_ok) {
253c96c378cSkrw 		for (i = 0; i < nitems(gpt_types); i++) {
254*6ba1b8a5Skrw 			if (strcasecmp(gpt_types[i].gt_guid, uuidstr) == 0)
255c96c378cSkrw 				break;
256c96c378cSkrw 		}
257c96c378cSkrw 	} else
258c96c378cSkrw 		i = nitems(gpt_types);
259c96c378cSkrw 	free(uuidstr);
260c96c378cSkrw 
261c96c378cSkrw 	if (i < nitems(gpt_types))
262c96c378cSkrw 		return &gpt_types[i];
263c96c378cSkrw 	else
264c96c378cSkrw 		return NULL;
265c96c378cSkrw }
266c96c378cSkrw 
267867d4347Skrw const struct mbr_type *
268867d4347Skrw find_mbr_type(const int id)
269c96c378cSkrw {
270867d4347Skrw 	unsigned int			i;
271c96c378cSkrw 
272c96c378cSkrw 	for (i = 0; i < nitems(mbr_types); i++) {
273c96c378cSkrw 		if (mbr_types[i].mt_type == id)
274867d4347Skrw 			return &mbr_types[i];
275c96c378cSkrw 	}
276c96c378cSkrw 
277867d4347Skrw 	return NULL;
278c96c378cSkrw }
279c96c378cSkrw 
280f458660aSkrw int
281f458660aSkrw uuid_attr(const struct uuid *uuid)
282f458660aSkrw {
283f458660aSkrw 	const struct gpt_type	*gt;
284f458660aSkrw 
285f458660aSkrw 	gt = find_gpt_type(uuid);
286f458660aSkrw 	if (gt == NULL)
287f458660aSkrw 		return 0;
288f458660aSkrw 	else
289f458660aSkrw 		return gt->gt_attr;
290f458660aSkrw }
291f2ec1a13Skrw 
29295e8765cSkrw int
2932ea83235Skrw PRT_protected_guid(const struct uuid *uuid)
29495e8765cSkrw {
295f458660aSkrw 	const struct gpt_type	*gt;
2968e294713Skrw 	unsigned int		 pn;
2978e294713Skrw 
298f458660aSkrw 	gt = find_gpt_type(uuid);
299f458660aSkrw 	if (gt && gt->gt_attr & GTATTR_PROTECT)
300f458660aSkrw 		return 1;
30195e8765cSkrw 
302e92bde66Skrw 	if (gt && strcasecmp(gt->gt_guid, EFI_SYSTEM_PARTITION_GUID) == 0) {
3032de77560Skrw 		for (pn = 0; pn < gh.gh_part_num; pn++) {
304f458660aSkrw 			if (uuid_attr(&gp[pn].gp_type) & GTATTR_PROTECT_EFISYS)
305f458660aSkrw 				return 1;
30695e8765cSkrw 		}
30765deb39bSkrw 	}
30895e8765cSkrw 
3098e294713Skrw 	return 0;
31095e8765cSkrw }
31195e8765cSkrw 
3124b464610Sderaadt void
313a0193349Skrw PRT_print_mbrmenu(char *lbuf, size_t lbuflen)
3144b464610Sderaadt {
31572c8f31dSkrw 	unsigned int		cidx, i, idrows;
316d20bdfc6Skrw 
3175308a554Skrw 	idrows = (nitems(mbr_types) + 3) / 4;
3184b464610Sderaadt 
319c2ad5584Sderaadt 	printf("Choose from the following Partition id values:\n");
320d20bdfc6Skrw 	for (i = 0; i < idrows; i++) {
32172c8f31dSkrw 		for (cidx = i; cidx < i + idrows * 3; cidx += idrows) {
32224a7e0ddSkrw 			printf("%02X %-15s", mbr_types[cidx].mt_type,
323934b6408Skrw 			    mbr_types[cidx].mt_name);
32472c8f31dSkrw 		}
32572c8f31dSkrw 		if (cidx < nitems(mbr_types))
32672c8f31dSkrw 			printf("%02X %s", mbr_types[cidx].mt_type,
327934b6408Skrw 			    mbr_types[cidx].mt_name);
3285308a554Skrw 		printf("\n");
3295308a554Skrw 	}
330a0193349Skrw 
331a0193349Skrw 	memset(lbuf, 0, lbuflen);	/* Just continue. */
3325308a554Skrw }
3335308a554Skrw 
3345308a554Skrw void
335a0193349Skrw PRT_print_gptmenu(char *lbuf, size_t lbuflen)
3365308a554Skrw {
33772c8f31dSkrw 	unsigned int		cidx, i, idrows;
3385308a554Skrw 
3395308a554Skrw 	idrows = (nitems(gpt_types) + 3) / 4;
3405308a554Skrw 
3415308a554Skrw 	printf("Choose from the following Partition id values:\n");
3425308a554Skrw 	for (i = 0; i < idrows; i++) {
34372c8f31dSkrw 		for (cidx = i; cidx < i + idrows * 3; cidx += idrows) {
344e3f6ba90Skrw 			printf("%02X %-15s", gpt_types[cidx].gt_menuid,
345934b6408Skrw 			    gpt_types[cidx].gt_name);
34672c8f31dSkrw 		}
34772c8f31dSkrw 		if (cidx < nitems(gpt_types))
348e3f6ba90Skrw 			printf("%02X %s", gpt_types[cidx].gt_menuid,
349934b6408Skrw 			    gpt_types[cidx].gt_name);
3504b464610Sderaadt 		printf("\n");
3514b464610Sderaadt 	}
352a0193349Skrw 
353a0193349Skrw 	memset(lbuf, 0, lbuflen);	/* Just continue. */
354d20bdfc6Skrw }
355a1705421Sweingart 
356a1705421Sweingart void
3570cd9e2afSkrw PRT_parse(const struct dos_partition *dp, const uint64_t lba_self,
3580cd9e2afSkrw     const uint64_t lba_firstembr, struct prt *prt)
359a1705421Sweingart {
360ca2e86e1Sprovos 	off_t			off;
361b87d3542Skrw 	uint32_t		t;
362a1705421Sweingart 
363ee38fe33Skrw 	prt->prt_flag = dp->dp_flag;
364ee38fe33Skrw 	prt->prt_id = dp->dp_typ;
365a1705421Sweingart 
366ee38fe33Skrw 	if ((prt->prt_id == DOSPTYP_EXTEND) || (prt->prt_id == DOSPTYP_EXTENDL))
367061e6e0aSkrw 		off = lba_firstembr;
368c3e3230dSderaadt 	else
369061e6e0aSkrw 		off = lba_self;
370ca2e86e1Sprovos 
371ee38fe33Skrw 	memcpy(&t, &dp->dp_start, sizeof(uint32_t));
372ee38fe33Skrw 	prt->prt_bs = letoh32(t) + off;
373ee38fe33Skrw 	memcpy(&t, &dp->dp_size, sizeof(uint32_t));
374ee38fe33Skrw 	prt->prt_ns = letoh32(t);
375ee38fe33Skrw 	if (prt->prt_id == DOSPTYP_EFI && prt->prt_ns == UINT32_MAX)
376ee38fe33Skrw 		prt->prt_ns = DL_GETDSIZE(&dl) - prt->prt_bs;
3774ed7cd7eSrahnds }
37849241bdaSkrw 
379a1705421Sweingart void
38099e0469cSkrw PRT_make(const struct prt *prt, const uint64_t lba_self,
38199e0469cSkrw     const uint64_t lba_firstembr, struct dos_partition *dp)
382a1705421Sweingart {
38377392607Skrw 	struct chs		start, end;
3840cd9e2afSkrw 	uint64_t		off, t;
385c3e3230dSderaadt 
3866aca8866Skrw 	if (prt->prt_ns == 0 || prt->prt_id == DOSPTYP_UNUSED) {
3876aca8866Skrw 		memset(dp, 0, sizeof(*dp));
3886aca8866Skrw 		return;
3896aca8866Skrw 	}
3906aca8866Skrw 
391ee38fe33Skrw 	if ((prt->prt_id == DOSPTYP_EXTEND) || (prt->prt_id == DOSPTYP_EXTENDL))
392ee38fe33Skrw 		off = lba_firstembr;
393c3e3230dSderaadt 	else
394ee38fe33Skrw 		off = lba_self;
395a1705421Sweingart 
39677392607Skrw 	if (PRT_lba_to_chs(prt, &start, &end) == 0) {
39777392607Skrw 		dp->dp_shd = start.chs_head & 0xFF;
39877392607Skrw 		dp->dp_ssect = (start.chs_sect & 0x3F) | ((start.chs_cyl & 0x300) >> 2);
39977392607Skrw 		dp->dp_scyl = start.chs_cyl & 0xFF;
40077392607Skrw 		dp->dp_ehd = end.chs_head & 0xFF;
40177392607Skrw 		dp->dp_esect = (end.chs_sect & 0x3F) | ((end.chs_cyl & 0x300) >> 2);
40277392607Skrw 		dp->dp_ecyl = end.chs_cyl & 0xFF;
4034ed7cd7eSrahnds 	} else {
404ee38fe33Skrw 		memset(dp, 0xFF, sizeof(*dp));
4054ed7cd7eSrahnds 	}
406a1705421Sweingart 
407ee38fe33Skrw 	dp->dp_flag = prt->prt_flag & 0xFF;
408ee38fe33Skrw 	dp->dp_typ = prt->prt_id & 0xFF;
40940b0f5f3Skrw 
410ee38fe33Skrw 	t = htole64(prt->prt_bs - off);
411ee38fe33Skrw 	memcpy(&dp->dp_start, &t, sizeof(uint32_t));
412ee38fe33Skrw 	if (prt->prt_id == DOSPTYP_EFI && (prt->prt_bs + prt->prt_ns) >
41398952941Skrw 	    DL_GETDSIZE(&dl))
41498952941Skrw 		t = htole64(UINT32_MAX);
41598952941Skrw 	else
416ee38fe33Skrw 		t = htole64(prt->prt_ns);
417ee38fe33Skrw 	memcpy(&dp->dp_size, &t, sizeof(uint32_t));
4186d5e103bSkjell }
419a1705421Sweingart 
420a1705421Sweingart void
4217b70791fSkrw PRT_print_parthdr(void)
422a1705421Sweingart {
423ba49db25Skrw 	printf("            Starting         Ending    "
424ba49db25Skrw 	    "     LBA Info:\n");
425ba49db25Skrw 	printf(" #: id      C   H   S -      C   H   S "
426ba49db25Skrw 	    "[       start:        size ]\n");
427ba49db25Skrw 	printf("---------------------------------------"
428ba49db25Skrw 	    "----------------------------------------\n");
4297b70791fSkrw }
4307b70791fSkrw 
4317b70791fSkrw void
4327b70791fSkrw PRT_print_part(const int num, const struct prt *prt, const char *units)
4337b70791fSkrw {
4347b70791fSkrw 	const struct unit_type	*ut;
435867d4347Skrw 	const struct mbr_type	*mt;
43677392607Skrw 	struct chs		 start, end;
4377b70791fSkrw 	double			 size;
4387b70791fSkrw 
4393e9b7d6bSkrw 	size = units_size(units, prt->prt_ns, &ut);
44077392607Skrw 	PRT_lba_to_chs(prt, &start, &end);
441867d4347Skrw 	mt = find_mbr_type(prt->prt_id);
44277392607Skrw 
44377392607Skrw 	printf("%c%1d: %.2X %6llu %3u %3u - %6llu %3u %3u "
444ba49db25Skrw 	    "[%12llu:%12.0f%s] %s\n",
445ee38fe33Skrw 	    (prt->prt_flag == DOSACTIVE)?'*':' ',
446ee38fe33Skrw 	    num, prt->prt_id,
44777392607Skrw 	    start.chs_cyl, start.chs_head, start.chs_sect,
44877392607Skrw 	    end.chs_cyl, end.chs_head, end.chs_sect,
449867d4347Skrw 	    prt->prt_bs, size, ut->ut_abbr, mt ? mt->mt_name : "<Unknown ID>");
45062718823Skrw 
45162718823Skrw 	if (prt->prt_bs >= DL_GETDSIZE(&dl))
45262718823Skrw 		printf("partition %d starts beyond the end of %s\n", num,
45362718823Skrw 		    disk.dk_name);
45462718823Skrw 	else if (prt->prt_bs + prt->prt_ns > DL_GETDSIZE(&dl))
45562718823Skrw 		printf("partition %d extends beyond the end of %s\n", num,
45662718823Skrw 		    disk.dk_name);
457a1705421Sweingart }
458a1705421Sweingart 
45977392607Skrw int
46077392607Skrw PRT_lba_to_chs(const struct prt *prt, struct chs *start, struct chs *end)
461a1705421Sweingart {
46277392607Skrw 	uint64_t		lba;
463a1705421Sweingart 
46477392607Skrw 	if (prt->prt_ns == 0 || prt->prt_id == DOSPTYP_UNUSED) {
46577392607Skrw 		memset(start, 0, sizeof(*start));
46677392607Skrw 		memset(end, 0, sizeof(*end));
46777392607Skrw 		return -1;
468eb4cb19dSkjell 	}
469eb4cb19dSkjell 
47077392607Skrw 	/*
47177392607Skrw 	 * C = LBA ÷ (HPC × SPT)
47277392607Skrw 	 * H = (LBA ÷ SPT) mod HPC
47377392607Skrw 	 * S = (LBA mod SPT) + 1
47477392607Skrw 	 */
475a1705421Sweingart 
47677392607Skrw 	lba = prt->prt_bs;
47777392607Skrw 	start->chs_cyl = lba / (disk.dk_sectors * disk.dk_heads);
47877392607Skrw 	start->chs_head = (lba / disk.dk_sectors) % disk.dk_heads;
47977392607Skrw 	start->chs_sect = (lba % disk.dk_sectors) + 1;
480a1705421Sweingart 
48177392607Skrw 	lba = prt->prt_bs + prt->prt_ns - 1;
48277392607Skrw 	end->chs_cyl = lba / (disk.dk_sectors * disk.dk_heads);
48377392607Skrw 	end->chs_head = (lba / disk.dk_sectors) % disk.dk_heads;
48477392607Skrw 	end->chs_sect = (lba % disk.dk_sectors) + 1;
485a1705421Sweingart 
48677392607Skrw 	if (start->chs_head > 255 || end->chs_head > 255 ||
48777392607Skrw 	    start->chs_sect > 63  || end->chs_sect > 63 ||
48877392607Skrw 	    start->chs_cyl > 1023 || end->chs_cyl > 1023)
48977392607Skrw 		return -1;
490a1705421Sweingart 
49177392607Skrw 	return 0;
492a1705421Sweingart }
493fba7235cSkrw 
494f2ec1a13Skrw const char *
495934b6408Skrw PRT_uuid_to_name(const struct uuid *uuid)
496f2ec1a13Skrw {
497f2ec1a13Skrw 	static char		 typename[UUID_STR_LEN + 1];
4985c01edd6Skrw 	const uint8_t		 gpt_uuid_msdos[] = GPT_UUID_MSDOS;
4995c01edd6Skrw 	struct uuid		 uuid_msdos;
500f2ec1a13Skrw 	const struct gpt_type	*gt;
501f2ec1a13Skrw 	char			*uuidstr;
502351f0068Skrw 	uint32_t		 status;
503f2ec1a13Skrw 
5045c01edd6Skrw 	uuid_dec_be(gpt_uuid_msdos, &uuid_msdos);
5055c01edd6Skrw 	if (uuid_compare(&uuid_msdos, uuid, NULL) == 0)
5065c01edd6Skrw 		return "Microsoft basic data";
507f2ec1a13Skrw 
508f2ec1a13Skrw 	gt = find_gpt_type(uuid);
5095c01edd6Skrw 	if (gt != NULL)
510934b6408Skrw 		return gt->gt_name;
5115c01edd6Skrw 
512f2ec1a13Skrw 	uuid_to_string(uuid, &uuidstr, &status);
513f2ec1a13Skrw 	if (status == uuid_s_ok)
514f2ec1a13Skrw 		strlcpy(typename, uuidstr, sizeof(typename));
5155c01edd6Skrw 	else
5165c01edd6Skrw 		typename[0] = '\0';
517f2ec1a13Skrw 	free(uuidstr);
518f2ec1a13Skrw 
519f2ec1a13Skrw 	return typename;
520fba7235cSkrw }
521fba7235cSkrw 
522145e5a87Stim int
523e3f6ba90Skrw PRT_uuid_to_menuid(const struct uuid *uuid)
524145e5a87Stim {
525f2ec1a13Skrw 	const struct gpt_type	*gt;
526145e5a87Stim 
527f2ec1a13Skrw 	gt = find_gpt_type(uuid);
528f2ec1a13Skrw 	if (gt == NULL)
52943277e5dSkrw 		return -1;
530f2ec1a13Skrw 	else
531e3f6ba90Skrw 		return gt->gt_menuid;
532145e5a87Stim }
533145e5a87Stim 
534e48f25a4Skrw const struct uuid *
535e3f6ba90Skrw PRT_menuid_to_guid(const int menuid)
536fba7235cSkrw {
537fba7235cSkrw 	static struct uuid	guid;
5387403d590Skrw 	int			i;
539351f0068Skrw 	uint32_t		status = uuid_s_ok;
540fba7235cSkrw 
5417403d590Skrw 	for (i = 0; i < nitems(gpt_types); i++) {
5427403d590Skrw 		if (gpt_types[i].gt_menuid == menuid) {
5437403d590Skrw 			uuid_from_string(gpt_types[i].gt_guid, &guid, &status);
544fba7235cSkrw 			break;
545fba7235cSkrw 		}
5467403d590Skrw 	}
5477403d590Skrw 	if (i == nitems(gpt_types) || status != uuid_s_ok)
548482578bcSkrw 		uuid_create_nil(&guid, NULL);
549fba7235cSkrw 
5502a536aa2Skrw 	return &guid;
551fba7235cSkrw }
552