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