xref: /openbsd/sbin/fdisk/part.c (revision 404b540a)
1 /*	$OpenBSD: part.c,v 1.50 2009/04/29 22:58:24 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Tobias Weingartner
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <err.h>
29 #include <util.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/disklabel.h>
37 #include <machine/param.h>
38 #include "disk.h"
39 #include "misc.h"
40 #include "mbr.h"
41 
42 int	PRT_check_chs(prt_t *partn);
43 
44 static const struct part_type {
45 	int	type;
46 	char	sname[14];
47 } part_types[] = {
48 	{ 0x00, "unused      "},   /* unused */
49 	{ 0x01, "DOS FAT-12  "},   /* Primary DOS with 12 bit FAT */
50 	{ 0x02, "XENIX /     "},   /* XENIX / filesystem */
51 	{ 0x03, "XENIX /usr  "},   /* XENIX /usr filesystem */
52 	{ 0x04, "DOS FAT-16  "},   /* Primary DOS with 16 bit FAT */
53 	{ 0x05, "Extended DOS"},   /* Extended DOS */
54 	{ 0x06, "DOS > 32MB  "},   /* Primary 'big' DOS (> 32MB) */
55 	{ 0x07, "NTFS        "},   /* NTFS */
56 	{ 0x08, "AIX fs      "},   /* AIX filesystem */
57 	{ 0x09, "AIX/Coherent"},   /* AIX boot partition or Coherent */
58 	{ 0x0A, "OS/2 Bootmgr"},   /* OS/2 Boot Manager or OPUS */
59 	{ 0x0B, "Win95 FAT-32"},   /* Primary Win95 w/ 32-bit FAT */
60 	{ 0x0C, "Win95 FAT32L"},   /* Primary Win95 w/ 32-bit FAT LBA-mapped */
61 	{ 0x0E, "DOS FAT-16  "},   /* Primary DOS w/ 16-bit FAT, CHS-mapped */
62 	{ 0x0F, "Extended LBA"},   /* Extended DOS LBA-mapped */
63 	{ 0x10, "OPUS        "},   /* OPUS */
64 	{ 0x11, "OS/2 hidden "},   /* OS/2 BM: hidden DOS 12-bit FAT */
65 	{ 0x12, "Compaq Diag."},   /* Compaq Diagnostics */
66 	{ 0x14, "OS/2 hidden "},   /* OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug */
67 	{ 0x16, "OS/2 hidden "},   /* OS/2 BM: hidden DOS 16-bit FAT >=32M */
68 	{ 0x17, "OS/2 hidden "},   /* OS/2 BM: hidden IFS */
69 	{ 0x18, "AST swap    "},   /* AST Windows swapfile */
70 	{ 0x19, "Willowtech  "},   /* Willowtech Photon coS */
71 	{ 0x1C, "ThinkPad Rec"},   /* IBM ThinkPad recovery partition */
72 	{ 0x20, "Willowsoft  "},   /* Willowsoft OFS1 */
73 	{ 0x24, "NEC DOS     "},   /* NEC DOS */
74 	{ 0x27, "Win Recovery"},   /* Windows hidden Recovery Partition */
75 	{ 0x38, "Theos       "},   /* Theos */
76 	{ 0x39, "Plan 9      "},   /* Plan 9 */
77 	{ 0x40, "VENIX 286   "},   /* VENIX 286 or LynxOS */
78 	{ 0x41, "Lin/Minux DR"},   /* Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot */
79 	{ 0x42, "LinuxSwap DR"},   /* SFS or Linux swap (sharing disk with DRDOS) */
80 	{ 0x43, "Linux DR    "},   /* Linux native (sharing disk with DRDOS) */
81 	{ 0x4D, "QNX 4.2 Pri "},   /* QNX 4.2 Primary */
82 	{ 0x4E, "QNX 4.2 Sec "},   /* QNX 4.2 Secondary */
83 	{ 0x4F, "QNX 4.2 Ter "},   /* QNX 4.2 Tertiary */
84 	{ 0x50, "DM          "},   /* DM (disk manager) */
85 	{ 0x51, "DM          "},   /* DM6 Aux1 (or Novell) */
86 	{ 0x52, "CP/M or SysV"},   /* CP/M or Microport SysV/AT */
87 	{ 0x53, "DM          "},   /* DM6 Aux3 */
88 	{ 0x54, "Ontrack     "},   /* Ontrack */
89 	{ 0x55, "EZ-Drive    "},   /* EZ-Drive (disk manager) */
90 	{ 0x56, "Golden Bow  "},   /* Golden Bow (disk manager) */
91 	{ 0x5C, "Priam       "},   /* Priam Edisk (disk manager) */
92 	{ 0x61, "SpeedStor   "},   /* SpeedStor */
93 	{ 0x63, "ISC, HURD, *"},   /* ISC, System V/386, GNU HURD or Mach */
94 	{ 0x64, "NetWare 2.xx"},   /* Novell NetWare 2.xx */
95 	{ 0x65, "NetWare 3.xx"},   /* Novell NetWare 3.xx */
96 	{ 0x66, "NetWare 386 "},   /* Novell 386 NetWare */
97 	{ 0x67, "Novell      "},   /* Novell */
98 	{ 0x68, "Novell      "},   /* Novell */
99 	{ 0x69, "Novell      "},   /* Novell */
100 	{ 0x70, "DiskSecure  "},   /* DiskSecure Multi-Boot */
101 	{ 0x75, "PCIX        "},   /* PCIX */
102 	{ 0x80, "Minix (old) "},   /* Minix 1.1 ... 1.4a */
103 	{ 0x81, "Minix (new) "},   /* Minix 1.4b ... 1.5.10 */
104 	{ 0x82, "Linux swap  "},   /* Linux swap */
105 	{ 0x83, "Linux files*"},   /* Linux filesystem */
106 	{ 0x84, "OS/2 hidden "},   /* OS/2 hidden C: drive */
107 	{ 0x85, "Linux ext.  "},   /* Linux extended */
108 	{ 0x86, "NT FAT VS   "},   /* NT FAT volume set */
109 	{ 0x87, "NTFS VS     "},   /* NTFS volume set or HPFS mirrored */
110 	{ 0x8E, "Linux LVM   "},   /* Linux LVM */
111 	{ 0x93, "Amoeba FS   "},   /* Amoeba filesystem */
112 	{ 0x94, "Amoeba BBT  "},   /* Amoeba bad block table */
113 	{ 0x99, "Mylex       "},   /* Mylex EISA SCSI */
114 	{ 0x9F, "BSDI        "},   /* BSDI BSD/OS */
115 	{ 0xA0, "NotebookSave"},   /* Phoenix NoteBIOS save-to-disk */
116 	{ 0xA5, "FreeBSD     "},   /* FreeBSD */
117 	{ 0xA6, "OpenBSD     "},   /* OpenBSD */
118 	{ 0xA7, "NEXTSTEP    "},   /* NEXTSTEP */
119 	{ 0xA8, "MacOS X     "},   /* MacOS X main partition */
120 	{ 0xA9, "NetBSD      "},   /* NetBSD */
121 	{ 0xAB, "MacOS X boot"},   /* MacOS X boot partition */
122 	{ 0xAF, "MacOS X HFS+"},   /* MacOS X HFS+ partition */
123 	{ 0xB7, "BSDI filesy*"},   /* BSDI BSD/386 filesystem */
124 	{ 0xB8, "BSDI swap   "},   /* BSDI BSD/386 swap */
125 	{ 0xBF, "Solaris     "},   /* Solaris */
126 	{ 0xC0, "CTOS        "},   /* CTOS */
127 	{ 0xC1, "DRDOSs FAT12"},   /* DRDOS/sec (FAT-12) */
128 	{ 0xC4, "DRDOSs < 32M"},   /* DRDOS/sec (FAT-16, < 32M) */
129 	{ 0xC6, "DRDOSs >=32M"},   /* DRDOS/sec (FAT-16, >= 32M) */
130 	{ 0xC7, "HPFS Disbled"},   /* Syrinx (Cyrnix?) or HPFS disabled */
131 	{ 0xDB, "CPM/C.DOS/C*"},   /* Concurrent CPM or C.DOS or CTOS */
132 	{ 0xDE, "Dell Maint  "},   /* Dell maintenance partition */
133 	{ 0xE1, "SpeedStor   "},   /* DOS access or SpeedStor 12-bit FAT extended partition */
134 	{ 0xE3, "SpeedStor   "},   /* DOS R/O or SpeedStor or Storage Dimensions */
135 	{ 0xE4, "SpeedStor   "},   /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
136 	{ 0xEB, "BeOS/i386   "},   /* BeOS for Intel */
137 	{ 0xEE, "EFI GPT     "},   /* EFI Protective Partition */
138 	{ 0xEF, "EFI Sys     "},   /* EFI System Partition */
139 	{ 0xF1, "SpeedStor   "},   /* SpeedStor or Storage Dimensions */
140 	{ 0xF2, "DOS 3.3+ Sec"},   /* DOS 3.3+ Secondary */
141 	{ 0xF4, "SpeedStor   "},   /* SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML */
142 	{ 0xFF, "Xenix BBT   "},   /* Xenix Bad Block Table */
143 };
144 
145 void
146 PRT_printall(void)
147 {
148 	int i, idrows;
149 
150 	idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4;
151 
152 	printf("Choose from the following Partition id values:\n");
153 	for (i = 0; i < idrows; i++) {
154 		printf("%02X %s   %02X %s   %02X %s",
155 		    part_types[i].type, part_types[i].sname,
156 		    part_types[i+idrows].type, part_types[i+idrows].sname,
157 		    part_types[i+idrows*2].type, part_types[i+idrows*2].sname);
158 		if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) {
159 			printf("   %02X %s\n",
160 			    part_types[i+idrows*3].type,
161 			    part_types[i+idrows*3].sname);
162 		} else
163 			printf( "\n" );
164 	}
165 }
166 
167 const char *
168 PRT_ascii_id(int id)
169 {
170 	static char unknown[] = "<Unknown ID>";
171 	int i;
172 
173 	for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) {
174 		if (part_types[i].type == id)
175 			return (part_types[i].sname);
176 	}
177 
178 	return (unknown);
179 }
180 
181 void
182 PRT_parse(disk_t *disk, void *prt, off_t offset, off_t reloff,
183     prt_t *partn)
184 {
185 	unsigned char *p = prt;
186 	off_t off;
187 
188 	partn->flag = *p++;
189 	partn->shead = *p++;
190 
191 	partn->ssect = (*p) & 0x3F;
192 	partn->scyl = ((*p << 2) & 0xFF00) | (*(p+1));
193 	p += 2;
194 
195 	partn->id = *p++;
196 	partn->ehead = *p++;
197 	partn->esect = (*p) & 0x3F;
198 	partn->ecyl = ((*p << 2) & 0xFF00) | (*(p+1));
199 	p += 2;
200 
201 	if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL))
202 		off = reloff;
203 	else
204 		off = offset;
205 
206 	partn->bs = getlong(p) + off;
207 	partn->ns = getlong(p+4);
208 
209 	PRT_fix_CHS(disk, partn);
210 }
211 
212 int
213 PRT_check_chs(prt_t *partn)
214 {
215 	if ( (partn->shead > 255) ||
216 		(partn->ssect >63) ||
217 		(partn->scyl > 1023) ||
218 		(partn->ehead >255) ||
219 		(partn->esect >63) ||
220 		(partn->ecyl > 1023) )
221 	{
222 		return 0;
223 	}
224 	return 1;
225 }
226 void
227 PRT_make(prt_t *partn, off_t offset, off_t reloff, void *prt)
228 {
229 	unsigned char *p = prt;
230 	int ecsave, scsave;
231 	int modified = 0;
232 	off_t off;
233 
234 	if ((partn->scyl > 1023) || (partn->ecyl > 1023)) {
235 		scsave = partn->scyl;
236 		ecsave = partn->ecyl;
237 		partn->scyl = (partn->scyl > 1023)? 1023: partn->scyl;
238 		partn->ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl;
239 		modified = 1;
240 	}
241 	if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL))
242 		off = reloff;
243 	else
244 		off = offset;
245 
246 	if (PRT_check_chs(partn)) {
247 		*p++ = partn->flag & 0xFF;
248 
249 		*p++ = partn->shead & 0xFF;
250 		*p++ = (partn->ssect & 0x3F) | ((partn->scyl & 0x300) >> 2);
251 		*p++ = partn->scyl & 0xFF;
252 
253 		*p++ = partn->id & 0xFF;
254 
255 		*p++ = partn->ehead & 0xFF;
256 		*p++ = (partn->esect & 0x3F) | ((partn->ecyl & 0x300) >> 2);
257 		*p++ = partn->ecyl & 0xFF;
258 	} else {
259 		/* should this really keep flag, id and set others to 0xff? */
260 		*p++ = partn->flag & 0xFF;
261 		*p++ = 0xFF;
262 		*p++ = 0xFF;
263 		*p++ = 0xFF;
264 		*p++ = partn->id & 0xFF;
265 		*p++ = 0xFF;
266 		*p++ = 0xFF;
267 		*p++ = 0xFF;
268 		printf("Warning CHS values out of bounds only saving LBA values\n");
269 	}
270 
271 	putlong(p, partn->bs - off);
272 	putlong(p+4, partn->ns);
273 	if (modified) {
274 		partn->scyl = scsave;
275 		partn->ecyl = ecsave;
276 	}
277 }
278 
279 void
280 PRT_print(int num, prt_t *partn, char *units)
281 {
282 	double size;
283 	int i;
284 	i = unit_lookup(units);
285 
286 	if (partn == NULL) {
287 		printf("            Starting         Ending         LBA Info:\n");
288 		printf(" #: id      C   H   S -      C   H   S [       start:        size ]\n");
289 		printf("-------------------------------------------------------------------------------\n");
290 	} else {
291 		size = ((double)partn->ns * unit_types[SECTORS].conversion) /
292 		    unit_types[i].conversion;
293 		printf("%c%1d: %.2X %6u %3u %3u - %6u %3u %3u [%12u:%12.0f%s] %s\n",
294 		    (partn->flag == 0x80)?'*':' ',
295 		    num, partn->id,
296 		    partn->scyl, partn->shead, partn->ssect,
297 		    partn->ecyl, partn->ehead, partn->esect,
298 		    partn->bs, size,
299 		    unit_types[i].abbr,
300 		    PRT_ascii_id(partn->id));
301 	}
302 }
303 
304 void
305 PRT_fix_BN(disk_t *disk, prt_t *part, int pn)
306 {
307 	u_int32_t spt, tpc, spc;
308 	u_int32_t start = 0;
309 	u_int32_t end = 0;
310 
311 	/* Zero out entry if not used */
312 	if (part->id == DOSPTYP_UNUSED ) {
313 		memset(part, 0, sizeof(*part));
314 		return;
315 	}
316 
317 	/* Disk metrics */
318 	spt = disk->real->sectors;
319 	tpc = disk->real->heads;
320 	spc = spt * tpc;
321 
322 	start += part->scyl * spc;
323 	start += part->shead * spt;
324 	start += part->ssect - 1;
325 
326 	end += part->ecyl * spc;
327 	end += part->ehead * spt;
328 	end += part->esect - 1;
329 
330 	/* XXX - Should handle this... */
331 	if (start > end)
332 		warn("Start of partition #%d after end!", pn);
333 
334 	part->bs = start;
335 	part->ns = (end - start) + 1;
336 }
337 
338 void
339 PRT_fix_CHS(disk_t *disk, prt_t *part)
340 {
341 	u_int32_t spt, tpc, spc;
342 	u_int32_t start, end, size;
343 	u_int32_t cyl, head, sect;
344 
345 	/* Zero out entry if not used */
346 	if (part->id == DOSPTYP_UNUSED ) {
347 		memset(part, 0, sizeof(*part));
348 		return;
349 	}
350 
351 	/* Disk metrics */
352 	spt = disk->real->sectors;
353 	tpc = disk->real->heads;
354 	spc = spt * tpc;
355 
356 	start = part->bs;
357 	size = part->ns;
358 	end = (start + size) - 1;
359 
360 	/* Figure out starting CHS values */
361 	cyl = (start / spc); start -= (cyl * spc);
362 	head = (start / spt); start -= (head * spt);
363 	sect = (start + 1);
364 
365 	part->scyl = cyl;
366 	part->shead = head;
367 	part->ssect = sect;
368 
369 	/* Figure out ending CHS values */
370 	cyl = (end / spc); end -= (cyl * spc);
371 	head = (end / spt); end -= (head * spt);
372 	sect = (end + 1);
373 
374 	part->ecyl = cyl;
375 	part->ehead = head;
376 	part->esect = sect;
377 }
378 
379