xref: /openbsd/sbin/fdisk/part.c (revision 73471bf0)
1 /*	$OpenBSD: part.c,v 1.110 2021/10/18 20:27:32 krw Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Tobias Weingartner
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/disklabel.h>
21 
22 #include <err.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <uuid.h>
28 
29 #include "part.h"
30 #include "disk.h"
31 #include "misc.h"
32 
33 int			 check_chs(const struct prt *);
34 const char		*ascii_id(const int);
35 
36 struct mbr_type {
37 	int	mt_type;
38 	char	mt_sname[14];
39 };
40 
41 const struct mbr_type		mbr_types[] = {
42 	{ 0x00, "unused      " },   /* unused */
43 	{ 0x01, "DOS FAT-12  " },   /* Primary DOS with 12 bit FAT */
44 	{ 0x02, "XENIX /     " },   /* XENIX / filesystem */
45 	{ 0x03, "XENIX /usr  " },   /* XENIX /usr filesystem */
46 	{ 0x04, "DOS FAT-16  " },   /* Primary DOS with 16 bit FAT */
47 	{ 0x05, "Extended DOS" },   /* Extended DOS */
48 	{ 0x06, "DOS > 32MB  " },   /* Primary 'big' DOS (> 32MB) */
49 	{ 0x07, "NTFS        " },   /* NTFS */
50 	{ 0x08, "AIX fs      " },   /* AIX filesystem */
51 	{ 0x09, "AIX/Coherent" },   /* AIX boot partition or Coherent */
52 	{ 0x0A, "OS/2 Bootmgr" },   /* OS/2 Boot Manager or OPUS */
53 	{ 0x0B, "Win95 FAT-32" },   /* Primary Win95 w/ 32-bit FAT */
54 	{ 0x0C, "Win95 FAT32L" },   /* Primary Win95 w/ 32-bit FAT LBA-mapped */
55 	{ 0x0E, "DOS FAT-16  " },   /* Primary DOS w/ 16-bit FAT, CHS-mapped */
56 	{ 0x0F, "Extended LBA" },   /* Extended DOS LBA-mapped */
57 	{ 0x10, "OPUS        " },   /* OPUS */
58 	{ 0x11, "OS/2 hidden " },   /* OS/2 BM: hidden DOS 12-bit FAT */
59 	{ 0x12, "Compaq Diag." },   /* Compaq Diagnostics */
60 	{ 0x14, "OS/2 hidden " },   /* OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug */
61 	{ 0x16, "OS/2 hidden " },   /* OS/2 BM: hidden DOS 16-bit FAT >=32M */
62 	{ 0x17, "OS/2 hidden " },   /* OS/2 BM: hidden IFS */
63 	{ 0x18, "AST swap    " },   /* AST Windows swapfile */
64 	{ 0x19, "Willowtech  " },   /* Willowtech Photon coS */
65 	{ 0x1C, "ThinkPad Rec" },   /* IBM ThinkPad recovery partition */
66 	{ 0x20, "Willowsoft  " },   /* Willowsoft OFS1 */
67 	{ 0x24, "NEC DOS     " },   /* NEC DOS */
68 	{ 0x27, "Win Recovery" },   /* Windows hidden Recovery Partition */
69 	{ 0x38, "Theos       " },   /* Theos */
70 	{ 0x39, "Plan 9      " },   /* Plan 9 */
71 	{ 0x40, "VENIX 286   " },   /* VENIX 286 or LynxOS */
72 	{ 0x41, "Lin/Minux DR" },   /* Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot */
73 	{ 0x42, "LinuxSwap DR" },   /* SFS or Linux swap (sharing disk with DRDOS) */
74 	{ 0x43, "Linux DR    " },   /* Linux native (sharing disk with DRDOS) */
75 	{ 0x4D, "QNX 4.2 Pri " },   /* QNX 4.2 Primary */
76 	{ 0x4E, "QNX 4.2 Sec " },   /* QNX 4.2 Secondary */
77 	{ 0x4F, "QNX 4.2 Ter " },   /* QNX 4.2 Tertiary */
78 	{ 0x50, "DM          " },   /* DM (disk manager) */
79 	{ 0x51, "DM          " },   /* DM6 Aux1 (or Novell) */
80 	{ 0x52, "CP/M or SysV" },   /* CP/M or Microport SysV/AT */
81 	{ 0x53, "DM          " },   /* DM6 Aux3 */
82 	{ 0x54, "Ontrack     " },   /* Ontrack */
83 	{ 0x55, "EZ-Drive    " },   /* EZ-Drive (disk manager) */
84 	{ 0x56, "Golden Bow  " },   /* Golden Bow (disk manager) */
85 	{ 0x5C, "Priam       " },   /* Priam Edisk (disk manager) */
86 	{ 0x61, "SpeedStor   " },   /* SpeedStor */
87 	{ 0x63, "ISC, HURD, *" },   /* ISC, System V/386, GNU HURD or Mach */
88 	{ 0x64, "NetWare 2.xx" },   /* Novell NetWare 2.xx */
89 	{ 0x65, "NetWare 3.xx" },   /* Novell NetWare 3.xx */
90 	{ 0x66, "NetWare 386 " },   /* Novell 386 NetWare */
91 	{ 0x67, "Novell      " },   /* Novell */
92 	{ 0x68, "Novell      " },   /* Novell */
93 	{ 0x69, "Novell      " },   /* Novell */
94 	{ 0x70, "DiskSecure  " },   /* DiskSecure Multi-Boot */
95 	{ 0x75, "PCIX        " },   /* PCIX */
96 	{ 0x80, "Minix (old) " },   /* Minix 1.1 ... 1.4a */
97 	{ 0x81, "Minix (new) " },   /* Minix 1.4b ... 1.5.10 */
98 	{ 0x82, "Linux swap  " },   /* Linux swap */
99 	{ 0x83, "Linux files*" },   /* Linux filesystem */
100 	{ 0x84, "OS/2 hidden " },   /* OS/2 hidden C: drive */
101 	{ 0x85, "Linux ext.  " },   /* Linux extended */
102 	{ 0x86, "NT FAT VS   " },   /* NT FAT volume set */
103 	{ 0x87, "NTFS VS     " },   /* NTFS volume set or HPFS mirrored */
104 	{ 0x8E, "Linux LVM   " },   /* Linux LVM */
105 	{ 0x93, "Amoeba FS   " },   /* Amoeba filesystem */
106 	{ 0x94, "Amoeba BBT  " },   /* Amoeba bad block table */
107 	{ 0x99, "Mylex       " },   /* Mylex EISA SCSI */
108 	{ 0x9F, "BSDI        " },   /* BSDI BSD/OS */
109 	{ 0xA0, "NotebookSave" },   /* Phoenix NoteBIOS save-to-disk */
110 	{ 0xA5, "FreeBSD     " },   /* FreeBSD */
111 	{ 0xA6, "OpenBSD     " },   /* OpenBSD */
112 	{ 0xA7, "NEXTSTEP    " },   /* NEXTSTEP */
113 	{ 0xA8, "MacOS X     " },   /* MacOS X main partition */
114 	{ 0xA9, "NetBSD      " },   /* NetBSD */
115 	{ 0xAB, "MacOS X boot" },   /* MacOS X boot partition */
116 	{ 0xAF, "MacOS X HFS+" },   /* MacOS X HFS+ partition */
117 	{ 0xB7, "BSDI filesy*" },   /* BSDI BSD/386 filesystem */
118 	{ 0xB8, "BSDI swap   " },   /* BSDI BSD/386 swap */
119 	{ 0xBF, "Solaris     " },   /* Solaris */
120 	{ 0xC0, "CTOS        " },   /* CTOS */
121 	{ 0xC1, "DRDOSs FAT12" },   /* DRDOS/sec (FAT-12) */
122 	{ 0xC4, "DRDOSs < 32M" },   /* DRDOS/sec (FAT-16, < 32M) */
123 	{ 0xC6, "DRDOSs >=32M" },   /* DRDOS/sec (FAT-16, >= 32M) */
124 	{ 0xC7, "HPFS Disbled" },   /* Syrinx (Cyrnix?) or HPFS disabled */
125 	{ 0xDB, "CPM/C.DOS/C*" },   /* Concurrent CPM or C.DOS or CTOS */
126 	{ 0xDE, "Dell Maint  " },   /* Dell maintenance partition */
127 	{ 0xE1, "SpeedStor   " },   /* DOS access or SpeedStor 12-bit FAT extended partition */
128 	{ 0xE3, "SpeedStor   " },   /* DOS R/O or SpeedStor or Storage Dimensions */
129 	{ 0xE4, "SpeedStor   " },   /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
130 	{ 0xEB, "BeOS/i386   " },   /* BeOS for Intel */
131 	{ 0xEE, "EFI GPT     " },   /* EFI Protective Partition */
132 	{ 0xEF, "EFI Sys     " },   /* EFI System Partition */
133 	{ 0xF1, "SpeedStor   " },   /* SpeedStor or Storage Dimensions */
134 	{ 0xF2, "DOS 3.3+ Sec" },   /* DOS 3.3+ Secondary */
135 	{ 0xF4, "SpeedStor   " },   /* SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML */
136 	{ 0xFF, "Xenix BBT   " },   /* Xenix Bad Block Table */
137 };
138 
139 struct gpt_type {
140 	int	gt_type;
141 	int	gt_protected;
142 	char	gt_sname[14];
143 	char	gt_guid[UUID_STR_LEN + 1];
144 
145 };
146 
147 const struct gpt_type		gpt_types[] = {
148 	{ 0x00, 0, "unused      ", "00000000-0000-0000-0000-000000000000" },
149 	{ 0x01, 0, "FAT12       ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
150 	{ 0x04, 0, "FAT16S      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
151 	{ 0x06, 0, "FAT16B      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
152 	{ 0x07, 0, "NTFS        ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
153 	{ 0x0B, 0, "FAT32       ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
154 	{ 0x0C, 0, "FAT32L      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
155 	{ 0x0D, 0, "BIOS Boot   ", "21686148-6449-6e6f-744e-656564454649" },
156 	{ 0x0E, 0, "FAT16L      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
157 	{ 0x11, 0, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
158 	{ 0x14, 0, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
159 	{ 0x16, 0, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
160 	{ 0x17, 0, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
161 	{ 0x1C, 0, "ThinkPad Rec", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
162 	{ 0x27, 0, "Win Recovery", "de94bba4-06d1-4d40-a16a-bfd50179d6ac" },
163 	{ 0x42, 0, "LinuxSwap DR", "af9b60a0-1431-4f62-bc68-3311714a69ad" },
164 	{ 0x7f, 0, "ChromeKernel", "fe3a2a5d-4f32-41a7-b725-accc3285a309" },
165 	{ 0x82, 0, "Linux swap  ", "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" },
166 	{ 0x83, 0, "Linux files*", "0fc63daf-8483-4772-8e79-3d69d8477de4" },
167 	{ 0x8E, 0, "Linux LVM   ", "e6d6d379-f507-44c2-a23c-238f2a3df928" },
168 	{ 0xA5, 0, "FreeBSD     ", "516e7cb4-6ecf-11d6-8ff8-00022d09712b" },
169 	{ 0xA6, 0, "OpenBSD     ", "824cc7a0-36a8-11e3-890a-952519ad3f61" },
170 	{ 0xA8, 0, "MacOS X     ", "55465300-0000-11aa-aa11-00306543ecac" },
171 	{ 0xA9, 0, "NetBSD      ", "516e7cb4-6ecf-11d6-8ff8-00022d09712b" },
172 	{ 0xAB, 0, "MacOS X boot", "426f6f74-0000-11aa-aa11-00306543ecac" },
173 	{ 0xAF, 0, "MacOS X HFS+", "48465300-0000-11aa-aa11-00306543ecac" },
174 	{ 0xB0, 1, "APFS        ", "7c3457ef-0000-11aa-aa11-00306543ecac" },
175 	{ 0xB1, 1, "APFS ISC    ", "69646961-6700-11aa-aa11-00306543ecac" },
176 	{ 0xB2, 1, "APFS Recovry", "52637672-7900-11aa-aa11-00306543ecac" },
177 	{ 0xB3, 1, "HiFive FSBL ", "5b193300-fc78-40cd-8002-e86c45580b47" },
178 	{ 0xB4, 1, "HiFive BBL  ", "2e54b353-1271-4842-806f-e436d6af6985" },
179 	{ 0xBF, 0, "Solaris     ", "6a85cf4d-1dd2-11b2-99a6-080020736631" },
180 	{ 0xEB, 0, "BeOS/i386   ", "42465331-3ba3-10f1-802a-4861696b7521" },
181 	{ 0xEF, 0, "EFI Sys     ", "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" },
182 };
183 
184 int
185 PRT_protected_guid(const struct uuid *uuid)
186 {
187 	char			*str = NULL;
188 	int			 rslt = 0;
189 	unsigned int		 i;
190 	uint32_t		 status;
191 
192 	uuid_to_string(uuid, &str, &status);
193 	if (status != uuid_s_ok) {
194 		rslt = -1;
195 		goto done;
196 	}
197 
198 	for(i = 0; i < nitems(gpt_types); i++) {
199 		if (strncmp(str, gpt_types[i].gt_guid, UUID_STR_LEN) == 0) {
200 			if (gpt_types[i].gt_protected)
201 				rslt = -1;
202 			break;
203 		}
204 	}
205 
206  done:
207 	free(str);
208 	return rslt;
209 }
210 
211 void
212 PRT_print_mbrtypes(void)
213 {
214 	unsigned int			i, idrows;
215 
216 	idrows = (nitems(mbr_types) + 3) / 4;
217 
218 	printf("Choose from the following Partition id values:\n");
219 	for (i = 0; i < idrows; i++) {
220 		printf("%02X %s   %02X %s   %02X %s",
221 		    mbr_types[i].mt_type, mbr_types[i].mt_sname,
222 		    mbr_types[i+idrows].mt_type, mbr_types[i+idrows].mt_sname,
223 		    mbr_types[i+idrows*2].mt_type, mbr_types[i+idrows*2].mt_sname);
224 		if ((i+idrows*3) < nitems(mbr_types)) {
225 			printf("   %02X %s\n",
226 			    mbr_types[i+idrows*3].mt_type,
227 			    mbr_types[i+idrows*3].mt_sname);
228 		} else
229 			printf( "\n" );
230 	}
231 }
232 
233 void
234 PRT_print_gpttypes(void)
235 {
236 	unsigned int			i, idrows;
237 
238 	idrows = (nitems(gpt_types) + 3) / 4;
239 
240 	printf("Choose from the following Partition id values:\n");
241 	for (i = 0; i < idrows; i++) {
242 		printf("%02X %s   %02X %s   %02X %s",
243 		    gpt_types[i].gt_type, gpt_types[i].gt_sname,
244 		    gpt_types[i+idrows].gt_type, gpt_types[i+idrows].gt_sname,
245 		    gpt_types[i+idrows*2].gt_type, gpt_types[i+idrows*2].gt_sname);
246 		if ((i+idrows*3) < nitems(gpt_types)) {
247 			printf("   %02X %s\n",
248 			    gpt_types[i+idrows*3].gt_type,
249 			    gpt_types[i+idrows*3].gt_sname);
250 		} else
251 			printf( "\n" );
252 	}
253 }
254 
255 const char *
256 ascii_id(const int id)
257 {
258 	static char		unknown[] = "<Unknown ID>";
259 	int			i;
260 
261 	for (i = 0; i < nitems(mbr_types); i++) {
262 		if (mbr_types[i].mt_type == id)
263 			return mbr_types[i].mt_sname;
264 	}
265 
266 	return unknown;
267 }
268 
269 void
270 PRT_parse(const struct dos_partition *dp, const uint64_t lba_self,
271     const uint64_t lba_firstembr, struct prt *prt)
272 {
273 	off_t			off;
274 	uint32_t		t;
275 
276 	prt->prt_flag = dp->dp_flag;
277 	prt->prt_id = dp->dp_typ;
278 
279 	if ((prt->prt_id == DOSPTYP_EXTEND) || (prt->prt_id == DOSPTYP_EXTENDL))
280 		off = lba_firstembr;
281 	else
282 		off = lba_self;
283 
284 	memcpy(&t, &dp->dp_start, sizeof(uint32_t));
285 	prt->prt_bs = letoh32(t) + off;
286 	memcpy(&t, &dp->dp_size, sizeof(uint32_t));
287 	prt->prt_ns = letoh32(t);
288 	if (prt->prt_id == DOSPTYP_EFI && prt->prt_ns == UINT32_MAX)
289 		prt->prt_ns = DL_GETDSIZE(&dl) - prt->prt_bs;
290 
291 	PRT_fix_CHS(prt);
292 }
293 
294 int
295 check_chs(const struct prt *prt)
296 {
297 	if ( (prt->prt_shead > 255) ||
298 		(prt->prt_ssect >63) ||
299 		(prt->prt_scyl > 1023) ||
300 		(prt->prt_ehead >255) ||
301 		(prt->prt_esect >63) ||
302 		(prt->prt_ecyl > 1023) )
303 	{
304 		return -1;
305 	}
306 	return 0;
307 }
308 
309 void
310 PRT_make(const struct prt *prt, const uint64_t lba_self, const uint64_t lba_firstembr,
311     struct dos_partition *dp)
312 {
313 	uint64_t		off, t;
314 	uint32_t		ecyl, scyl;
315 
316 	scyl = (prt->prt_scyl > 1023) ? 1023 : prt->prt_scyl;
317 	ecyl = (prt->prt_ecyl > 1023) ? 1023 : prt->prt_ecyl;
318 
319 	if ((prt->prt_id == DOSPTYP_EXTEND) || (prt->prt_id == DOSPTYP_EXTENDL))
320 		off = lba_firstembr;
321 	else
322 		off = lba_self;
323 
324 	if (check_chs(prt) == 0) {
325 		dp->dp_shd = prt->prt_shead & 0xFF;
326 		dp->dp_ssect = (prt->prt_ssect & 0x3F) | ((scyl & 0x300) >> 2);
327 		dp->dp_scyl = scyl & 0xFF;
328 		dp->dp_ehd = prt->prt_ehead & 0xFF;
329 		dp->dp_esect = (prt->prt_esect & 0x3F) | ((ecyl & 0x300) >> 2);
330 		dp->dp_ecyl = ecyl & 0xFF;
331 	} else {
332 		memset(dp, 0xFF, sizeof(*dp));
333 	}
334 
335 	dp->dp_flag = prt->prt_flag & 0xFF;
336 	dp->dp_typ = prt->prt_id & 0xFF;
337 
338 	t = htole64(prt->prt_bs - off);
339 	memcpy(&dp->dp_start, &t, sizeof(uint32_t));
340 	if (prt->prt_id == DOSPTYP_EFI && (prt->prt_bs + prt->prt_ns) >
341 	    DL_GETDSIZE(&dl))
342 		t = htole64(UINT32_MAX);
343 	else
344 		t = htole64(prt->prt_ns);
345 	memcpy(&dp->dp_size, &t, sizeof(uint32_t));
346 }
347 
348 void
349 PRT_print(const int num, const struct prt *prt, const char *units)
350 {
351 	const struct unit_type	*ut;
352 	double			 size;
353 
354 	if (prt == NULL) {
355 		printf("            Starting         Ending    "
356 		    "     LBA Info:\n");
357 		printf(" #: id      C   H   S -      C   H   S "
358 		    "[       start:        size ]\n");
359 		printf("---------------------------------------"
360 		    "----------------------------------------\n");
361 	} else {
362 		size = units_size(units, prt->prt_ns, &ut);
363 		printf("%c%1d: %.2X %6u %3u %3u - %6u %3u %3u "
364 		    "[%12llu:%12.0f%s] %s\n",
365 		    (prt->prt_flag == DOSACTIVE)?'*':' ',
366 		    num, prt->prt_id,
367 		    prt->prt_scyl, prt->prt_shead, prt->prt_ssect,
368 		    prt->prt_ecyl, prt->prt_ehead, prt->prt_esect,
369 		    prt->prt_bs, size, ut->ut_abbr, ascii_id(prt->prt_id));
370 	}
371 }
372 
373 void
374 PRT_fix_BN(struct prt *prt, const int pn)
375 {
376 	uint32_t		spt, tpc, spc;
377 	uint32_t		start = 0;
378 	uint32_t		end = 0;
379 
380 	if (prt->prt_id == DOSPTYP_UNUSED) {
381 		memset(prt, 0, sizeof(*prt));
382 		return;
383 	}
384 
385 	spt = disk.dk_sectors;
386 	tpc = disk.dk_heads;
387 	spc = spt * tpc;
388 
389 	start += prt->prt_scyl * spc;
390 	start += prt->prt_shead * spt;
391 	start += prt->prt_ssect - 1;
392 
393 	end += prt->prt_ecyl * spc;
394 	end += prt->prt_ehead * spt;
395 	end += prt->prt_esect - 1;
396 
397 	/* XXX - Should handle this... */
398 	if (start > end)
399 		warnx("Start of partition #%d after end!", pn);
400 
401 	prt->prt_bs = start;
402 	prt->prt_ns = (end - start) + 1;
403 }
404 
405 void
406 PRT_fix_CHS(struct prt *prt)
407 {
408 	uint32_t		spt, tpc, spc;
409 	uint32_t		start, end, size;
410 	uint32_t		cyl, head, sect;
411 
412 	if (prt->prt_id == DOSPTYP_UNUSED || prt->prt_ns == 0) {
413 		memset(prt, 0, sizeof(*prt));
414 		return;
415 	}
416 
417 	spt = disk.dk_sectors;
418 	tpc = disk.dk_heads;
419 	spc = spt * tpc;
420 
421 	start = prt->prt_bs;
422 	size = prt->prt_ns;
423 	end = (start + size) - 1;
424 
425 	cyl = (start / spc);
426 	start -= (cyl * spc);
427 	head = (start / spt);
428 	start -= (head * spt);
429 	sect = (start + 1);
430 
431 	prt->prt_scyl = cyl;
432 	prt->prt_shead = head;
433 	prt->prt_ssect = sect;
434 
435 	cyl = (end / spc);
436 	end -= (cyl * spc);
437 	head = (end / spt);
438 	end -= (head * spt);
439 	sect = (end + 1);
440 
441 	prt->prt_ecyl = cyl;
442 	prt->prt_ehead = head;
443 	prt->prt_esect = sect;
444 }
445 
446 char *
447 PRT_uuid_to_typename(const struct uuid *uuid)
448 {
449 	static char		 partition_type[UUID_STR_LEN + 1];
450 	char			*uuidstr = NULL;
451 	int			 i, entries, status;
452 
453 	memset(partition_type, 0, sizeof(partition_type));
454 
455 	uuid_to_string(uuid, &uuidstr, &status);
456 	if (status != uuid_s_ok)
457 		goto done;
458 
459 	entries = nitems(gpt_types);
460 
461 	for (i = 0; i < entries; i++) {
462 		if (memcmp(gpt_types[i].gt_guid, uuidstr,
463 		    sizeof(gpt_types[i].gt_guid)) == 0)
464 			break;
465 	}
466 
467 	if (i < entries)
468 		strlcpy(partition_type, gpt_types[i].gt_sname,
469 		    sizeof(partition_type));
470 	else
471 		strlcpy(partition_type, uuidstr, sizeof(partition_type));
472 
473 done:
474 	free(uuidstr);
475 
476 	return partition_type;
477 }
478 
479 int
480 PRT_uuid_to_type(const struct uuid *uuid)
481 {
482 	char			*uuidstr;
483 	int			 i, status, type;
484 
485 	type = 0;
486 
487 	uuid_to_string(uuid, &uuidstr, &status);
488 	if (status != uuid_s_ok)
489 		goto done;
490 
491 	for (i = 0; i < nitems(gpt_types); i++) {
492 		if (memcmp(gpt_types[i].gt_guid, uuidstr,
493 		    sizeof(gpt_types[i].gt_guid)) == 0) {
494 			type = gpt_types[i].gt_type;
495 			break;
496 		}
497 	}
498 
499 done:
500 	free(uuidstr);
501 	return type;
502 }
503 
504 struct uuid *
505 PRT_type_to_uuid(const int type)
506 {
507 	static struct uuid	guid;
508 	int			i, entries, status = uuid_s_ok;
509 
510 	memset(&guid, 0, sizeof(guid));
511 
512 	entries = nitems(gpt_types);
513 
514 	for (i = 0; i < entries; i++) {
515 		if (gpt_types[i].gt_type == type)
516 			break;
517 	}
518 	if (i < entries)
519 		uuid_from_string(gpt_types[i].gt_guid, &guid, &status);
520 	if (i == entries || status != uuid_s_ok)
521 		uuid_from_string(gpt_types[0].gt_guid, &guid, &status);
522 
523 	return &guid;
524 }
525