xref: /openbsd-src/sbin/fdisk/part.c (revision f1dd7b858388b4a23f4f67a4957ec5ff656ebbe8)
1 /*	$OpenBSD: part.c,v 1.80 2021/05/15 19:44:15 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 "disk.h"
30 #include "misc.h"
31 #include "part.h"
32 
33 int	PRT_check_chs(struct prt *partn);
34 
35 static const struct part_type {
36 	int	type;
37 	char	sname[14];
38 	char	guid[37];
39 } part_types[] = {
40 	{ 0x00, "unused      ", "00000000-0000-0000-0000-000000000000" },
41 	{ 0x01, "FAT12       ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
42 	{ 0x02, "XENIX /     "},   /* XENIX / filesystem */
43 	{ 0x03, "XENIX /usr  "},   /* XENIX /usr filesystem */
44 	{ 0x04, "FAT16S      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
45 	{ 0x05, "Extended DOS"},   /* Extended DOS */
46 	{ 0x06, "FAT16B      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
47 	{ 0x07, "NTFS        ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
48 	{ 0x08, "AIX fs      "},   /* AIX filesystem */
49 	{ 0x09, "AIX/Coherent"},   /* AIX boot partition or Coherent */
50 	{ 0x0A, "OS/2 Bootmgr"},   /* OS/2 Boot Manager or OPUS */
51 	{ 0x0B, "FAT32       ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
52 	{ 0x0C, "FAT32L      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
53 	{ 0x0D, "BIOS Boot   ", "21686148-6449-6e6f-744e-656564454649" },
54 	{ 0x0E, "FAT16L      ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
55 	{ 0x0F, "Extended LBA"},   /* Extended DOS LBA-mapped */
56 	{ 0x10, "OPUS        "},   /* OPUS */
57 	{ 0x11, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
58 	{ 0x12, "Compaq Diag."},   /* Compaq Diagnostics */
59 	{ 0x14, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
60 	{ 0x16, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
61 	{ 0x17, "OS/2 hidden ", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
62 	{ 0x18, "AST swap    "},   /* AST Windows swapfile */
63 	{ 0x19, "Willowtech  "},   /* Willowtech Photon coS */
64 	{ 0x1C, "ThinkPad Rec", "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" },
65 	{ 0x24, "NEC DOS     "},   /* NEC DOS */
66 	{ 0x27, "Win Recovery", "de94bba4-06d1-4d40-a16a-bfd50179d6ac" },
67 	{ 0x20, "Willowsoft  "},   /* Willowsoft OFS1 */
68 	{ 0x38, "Theos       "},   /* Theos */
69 	{ 0x39, "Plan 9      "},   /* Plan 9 */
70 	{ 0x40, "VENIX 286   "},   /* VENIX 286 or LynxOS */
71 	{ 0x41, "Lin/Minux DR"},   /* Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot */
72 	{ 0x42, "LinuxSwap DR", "af9b60a0-1431-4f62-bc68-3311714a69ad" },
73 	{ 0x43, "Linux DR    "},   /* Linux native (sharing disk with DRDOS) */
74 	{ 0x4D, "QNX 4.2 Pri "},   /* QNX 4.2 Primary */
75 	{ 0x4E, "QNX 4.2 Sec "},   /* QNX 4.2 Secondary */
76 	{ 0x4F, "QNX 4.2 Ter "},   /* QNX 4.2 Tertiary */
77 	{ 0x50, "DM          "},   /* DM (disk manager) */
78 	{ 0x51, "DM          "},   /* DM6 Aux1 (or Novell) */
79 	{ 0x52, "CP/M or SysV"},   /* CP/M or Microport SysV/AT */
80 	{ 0x53, "DM          "},   /* DM6 Aux3 */
81 	{ 0x54, "Ontrack     "},   /* Ontrack */
82 	{ 0x55, "EZ-Drive    "},   /* EZ-Drive (disk manager) */
83 	{ 0x56, "Golden Bow  "},   /* Golden Bow (disk manager) */
84 	{ 0x5C, "Priam       "},   /* Priam Edisk (disk manager) */
85 	{ 0x61, "SpeedStor   "},   /* SpeedStor */
86 	{ 0x63, "ISC, HURD, *"},   /* ISC, System V/386, GNU HURD or Mach */
87 	{ 0x64, "NetWare 2.xx"},   /* Novell NetWare 2.xx */
88 	{ 0x65, "NetWare 3.xx"},   /* Novell NetWare 3.xx */
89 	{ 0x66, "NetWare 386 "},   /* Novell 386 NetWare */
90 	{ 0x67, "Novell      "},   /* Novell */
91 	{ 0x68, "Novell      "},   /* Novell */
92 	{ 0x69, "Novell      "},   /* Novell */
93 	{ 0x70, "DiskSecure  "},   /* DiskSecure Multi-Boot */
94 	{ 0x75, "PCIX        "},   /* PCIX */
95 	{ 0x7f, "ChromeKernel", "fe3a2a5d-4f32-41a7-b725-accc3285a309" },
96 	{ 0x80, "Minix (old) "},   /* Minix 1.1 ... 1.4a */
97 	{ 0x81, "Minix (new) "},   /* Minix 1.4b ... 1.5.10 */
98 	{ 0x82, "Linux swap  ", "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" },
99 	{ 0x83, "Linux files*", "0fc63daf-8483-4772-8e79-3d69d8477de4" },
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   ", "e6d6d379-f507-44c2-a23c-238f2a3df928" },
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     ", "516e7cb4-6ecf-11d6-8ff8-00022d09712b" },
111 	{ 0xA6, "OpenBSD     ", "824cc7a0-36a8-11e3-890a-952519ad3f61" },
112 	{ 0xA7, "NEXTSTEP    "},   /* NEXTSTEP */
113 	{ 0xA8, "MacOS X     ", "55465300-0000-11aa-aa11-00306543ecac" },
114 	{ 0xA9, "NetBSD      ", "516e7cb4-6ecf-11d6-8ff8-00022d09712b" },
115 	{ 0xAB, "MacOS X boot", "426f6f74-0000-11aa-aa11-00306543ecac" },
116 	{ 0xAF, "MacOS X HFS+", "48465300-0000-11aa-aa11-00306543ecac" },
117 	{ 0xB7, "BSDI filesy*"},   /* BSDI BSD/386 filesystem */
118 	{ 0xB8, "BSDI swap   "},   /* BSDI BSD/386 swap */
119 	{ 0xBF, "Solaris     ", "6a85cf4d-1dd2-11b2-99a6-080020736631" },
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   ", "42465331-3ba3-10f1-802a-4861696b7521" },
131 	{ 0xEE, "EFI GPT     "},   /* EFI Protective Partition */
132 	{ 0xEF, "EFI Sys     ", "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" },
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 void
140 PRT_printall(void)
141 {
142 	int i, idrows;
143 
144 	idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4;
145 
146 	printf("Choose from the following Partition id values:\n");
147 	for (i = 0; i < idrows; i++) {
148 		printf("%02X %s   %02X %s   %02X %s",
149 		    part_types[i].type, part_types[i].sname,
150 		    part_types[i+idrows].type, part_types[i+idrows].sname,
151 		    part_types[i+idrows*2].type, part_types[i+idrows*2].sname);
152 		if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) {
153 			printf("   %02X %s\n",
154 			    part_types[i+idrows*3].type,
155 			    part_types[i+idrows*3].sname);
156 		} else
157 			printf( "\n" );
158 	}
159 }
160 
161 const char *
162 PRT_ascii_id(int id)
163 {
164 	static char unknown[] = "<Unknown ID>";
165 	int i;
166 
167 	for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) {
168 		if (part_types[i].type == id)
169 			return (part_types[i].sname);
170 	}
171 
172 	return (unknown);
173 }
174 
175 void
176 PRT_parse(struct dos_partition *prt, off_t offset, off_t reloff,
177     struct prt *partn)
178 {
179 	off_t off;
180 	uint32_t t;
181 
182 	partn->flag = prt->dp_flag;
183 	partn->shead = prt->dp_shd;
184 
185 	partn->ssect = (prt->dp_ssect) & 0x3F;
186 	partn->scyl = ((prt->dp_ssect << 2) & 0xFF00) | prt->dp_scyl;
187 
188 	partn->id = prt->dp_typ;
189 	partn->ehead = prt->dp_ehd;
190 	partn->esect = (prt->dp_esect) & 0x3F;
191 	partn->ecyl = ((prt->dp_esect << 2) & 0xFF00) | prt->dp_ecyl;
192 
193 	if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL))
194 		off = reloff;
195 	else
196 		off = offset;
197 
198 #if 0 /* XXX */
199 	partn->bs = letoh32(prt->dp_start) + off;
200 	partn->ns = letoh32(prt->dp_size);
201 	if (partn->id == DOSPTYP_EFI && partn == UINT32_MAX)
202 		partn->ns = DL_GETDSIZE(&dl) - partn->bs;
203 #else
204 	memcpy(&t, &prt->dp_start, sizeof(uint32_t));
205 	partn->bs = letoh32(t) + off;
206 	memcpy(&t, &prt->dp_size, sizeof(uint32_t));
207 	partn->ns = letoh32(t);
208 	if (partn->id == DOSPTYP_EFI && partn->ns == UINT32_MAX)
209 		partn->ns = DL_GETDSIZE(&dl) - partn->bs;
210 #endif
211 
212 	PRT_fix_CHS(partn);
213 }
214 
215 int
216 PRT_check_chs(struct prt *partn)
217 {
218 	if ( (partn->shead > 255) ||
219 		(partn->ssect >63) ||
220 		(partn->scyl > 1023) ||
221 		(partn->ehead >255) ||
222 		(partn->esect >63) ||
223 		(partn->ecyl > 1023) )
224 	{
225 		return (0);
226 	}
227 	return (1);
228 }
229 
230 void
231 PRT_make(struct prt *partn, off_t offset, off_t reloff,
232     struct dos_partition *prt)
233 {
234 	off_t off;
235 	uint32_t ecsave, scsave;
236 	uint64_t t;
237 
238 	/* Save (and restore below) cylinder info we may fiddle with. */
239 	scsave = partn->scyl;
240 	ecsave = partn->ecyl;
241 
242 	if ((partn->scyl > 1023) || (partn->ecyl > 1023)) {
243 		partn->scyl = (partn->scyl > 1023)? 1023: partn->scyl;
244 		partn->ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl;
245 	}
246 	if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL))
247 		off = reloff;
248 	else
249 		off = offset;
250 
251 	if (PRT_check_chs(partn)) {
252 		prt->dp_shd = partn->shead & 0xFF;
253 		prt->dp_ssect = (partn->ssect & 0x3F) |
254 		    ((partn->scyl & 0x300) >> 2);
255 		prt->dp_scyl = partn->scyl & 0xFF;
256 		prt->dp_ehd = partn->ehead & 0xFF;
257 		prt->dp_esect = (partn->esect & 0x3F) |
258 		    ((partn->ecyl & 0x300) >> 2);
259 		prt->dp_ecyl = partn->ecyl & 0xFF;
260 	} else {
261 		memset(prt, 0xFF, sizeof(*prt));
262 	}
263 
264 	prt->dp_flag = partn->flag & 0xFF;
265 	prt->dp_typ = partn->id & 0xFF;
266 
267 	t = htole64(partn->bs - off);
268 	memcpy(&prt->dp_start, &t, sizeof(uint32_t));
269 	if (partn->id == DOSPTYP_EFI && (partn->bs + partn->ns) >
270 	    DL_GETDSIZE(&dl))
271 		t = htole64(UINT32_MAX);
272 	else
273 		t = htole64(partn->ns);
274 	memcpy(&prt->dp_size, &t, sizeof(uint32_t));
275 
276 	partn->scyl = scsave;
277 	partn->ecyl = ecsave;
278 }
279 
280 void
281 PRT_print(int num, struct prt *partn, char *units)
282 {
283 	const int secsize = unit_types[SECTORS].conversion;
284 	double size;
285 	int i;
286 
287 	i = unit_lookup(units);
288 
289 	if (partn == NULL) {
290 		printf("            Starting         Ending    "
291 		    "     LBA Info:\n");
292 		printf(" #: id      C   H   S -      C   H   S "
293 		    "[       start:        size ]\n");
294 		printf("---------------------------------------"
295 		    "----------------------------------------\n");
296 	} else {
297 		size = ((double)partn->ns * secsize) / unit_types[i].conversion;
298 		printf("%c%1d: %.2X %6u %3u %3u - %6u %3u %3u "
299 		    "[%12llu:%12.0f%s] %s\n",
300 		    (partn->flag == DOSACTIVE)?'*':' ',
301 		    num, partn->id,
302 		    partn->scyl, partn->shead, partn->ssect,
303 		    partn->ecyl, partn->ehead, partn->esect,
304 		    partn->bs, size,
305 		    unit_types[i].abbr,
306 		    PRT_ascii_id(partn->id));
307 	}
308 }
309 
310 void
311 PRT_fix_BN(struct prt *part, int pn)
312 {
313 	uint32_t spt, tpc, spc;
314 	uint32_t start = 0;
315 	uint32_t end = 0;
316 
317 	/* Zero out entry if not used */
318 	if (part->id == DOSPTYP_UNUSED) {
319 		memset(part, 0, sizeof(*part));
320 		return;
321 	}
322 
323 	/* Disk geometry. */
324 	spt = disk.sectors;
325 	tpc = disk.heads;
326 	spc = spt * tpc;
327 
328 	start += part->scyl * spc;
329 	start += part->shead * spt;
330 	start += part->ssect - 1;
331 
332 	end += part->ecyl * spc;
333 	end += part->ehead * spt;
334 	end += part->esect - 1;
335 
336 	/* XXX - Should handle this... */
337 	if (start > end)
338 		warnx("Start of partition #%d after end!", pn);
339 
340 	part->bs = start;
341 	part->ns = (end - start) + 1;
342 }
343 
344 void
345 PRT_fix_CHS(struct prt *part)
346 {
347 	uint32_t spt, tpc, spc;
348 	uint32_t start, end, size;
349 	uint32_t cyl, head, sect;
350 
351 	/* Zero out entry if not used */
352 	if (part->id == DOSPTYP_UNUSED || part->ns == 0) {
353 		memset(part, 0, sizeof(*part));
354 		return;
355 	}
356 
357 	/* Disk geometry. */
358 	spt = disk.sectors;
359 	tpc = disk.heads;
360 	spc = spt * tpc;
361 
362 	start = part->bs;
363 	size = part->ns;
364 	end = (start + size) - 1;
365 
366 	/* Figure out starting CHS values */
367 	cyl = (start / spc); start -= (cyl * spc);
368 	head = (start / spt); start -= (head * spt);
369 	sect = (start + 1);
370 
371 	part->scyl = cyl;
372 	part->shead = head;
373 	part->ssect = sect;
374 
375 	/* Figure out ending CHS values */
376 	cyl = (end / spc); end -= (cyl * spc);
377 	head = (end / spt); end -= (head * spt);
378 	sect = (end + 1);
379 
380 	part->ecyl = cyl;
381 	part->ehead = head;
382 	part->esect = sect;
383 }
384 
385 char *
386 PRT_uuid_to_typename(struct uuid *uuid)
387 {
388 	static char partition_type[37];	/* Room for a GUID if needed. */
389 	char *uuidstr = NULL;
390 	int i, entries, status;
391 
392 	memset(partition_type, 0, sizeof(partition_type));
393 
394 	uuid_to_string(uuid, &uuidstr, &status);
395 	if (status != uuid_s_ok)
396 		goto done;
397 
398 	entries = sizeof(part_types) / sizeof(struct part_type);
399 
400 	for (i = 0; i < entries; i++) {
401 		if (memcmp(part_types[i].guid, uuidstr,
402 		    sizeof(part_types[i].guid)) == 0)
403 			break;
404 	}
405 
406 	if (i < entries)
407 		strlcpy(partition_type, part_types[i].sname,
408 		    sizeof(partition_type));
409 	else
410 		strlcpy(partition_type, uuidstr, sizeof(partition_type));
411 
412 done:
413 	free(uuidstr);
414 
415 	return (partition_type);
416 }
417 
418 int
419 PRT_uuid_to_type(struct uuid *uuid)
420 {
421 	char *uuidstr;
422 	int entries, i, status, type;
423 
424 	type = 0;
425 
426 	uuid_to_string(uuid, &uuidstr, &status);
427 	if (status != uuid_s_ok)
428 		goto done;
429 
430 	entries = sizeof(part_types) / sizeof(struct part_type);
431 	for (i = 0; i < entries; i++) {
432 		if (memcmp(part_types[i].guid, uuidstr,
433 		    sizeof(part_types[i].guid)) == 0) {
434 			type = part_types[i].type;
435 			break;
436 		}
437 	}
438 
439 done:
440 	free(uuidstr);
441 	return (type);
442 }
443 
444 struct uuid *
445 PRT_type_to_uuid(int type)
446 {
447 	static struct uuid guid;
448 	int i, entries, status = uuid_s_ok;
449 
450 	memset(&guid, 0, sizeof(guid));
451 
452 	entries = sizeof(part_types) / sizeof(struct part_type);
453 
454 	for (i = 0; i < entries; i++) {
455 		if (part_types[i].type == type)
456 			break;
457 	}
458 	if (i < entries)
459 		uuid_from_string(part_types[i].guid, &guid, &status);
460 	if (i == entries || status != uuid_s_ok)
461 		uuid_from_string(part_types[0].guid, &guid, &status);
462 
463 	return (&guid);
464 }
465