1 /** $MirOS: src/sbin/fdisk/part.c,v 1.8 2014/02/27 21:52:11 tg Exp $ */
2 /* $OpenBSD: part.c,v 1.42 2006/06/09 17:01:47 deraadt Exp $ */
3
4 /*
5 * Copyright (c) 1997 Tobias Weingartner
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/types.h>
30 #include <sys/fcntl.h>
31 #include <sys/stat.h>
32 #include <sys/disklabel.h>
33 #include <machine/param.h>
34 #include <err.h>
35 #include <util.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include "disk.h"
40 #include "misc.h"
41 #include "mbr.h"
42
43 __RCSID("$MirOS: src/sbin/fdisk/part.c,v 1.8 2014/02/27 21:52:11 tg Exp $");
44
45 int PRT_check_chs(prt_t *partn);
46
47 static const struct part_type {
48 int type;
49 char sname[14];
50 } part_types[] = {
51 { 0x00, "unused "}, /* unused */
52 { 0x01, "DOS FAT12 "}, /* Primary DOS with 12 bit FAT */
53 { 0x02, "XENIX / "}, /* XENIX / filesystem */
54 { 0x03, "XENIX /usr "}, /* XENIX /usr filesystem */
55 { 0x04, "DOS FAT16 "}, /* Primary DOS with 16 bit FAT */
56 { 0x05, "Extended DOS"}, /* Extended DOS */
57 { 0x06, "DOS > 32MB "}, /* Primary 'big' DOS (> 32MB) */
58 { 0x07, "HPFS/QNX/AUX"}, /* OS/2 HPFS, QNX-2 or Advanced UNIX */
59 { 0x08, "AIX fs "}, /* AIX filesystem */
60 { 0x09, "AIX/Coherent"}, /* AIX boot partition or Coherent */
61 { 0x0A, "OS/2 Bootmgr"}, /* OS/2 Boot Manager or OPUS */
62 { 0x0B, "DOS FAT32 "}, /* Primary DOS w/ 32-bit FAT */
63 { 0x0C, "DOS FAT32 L "}, /* Primary DOS w/ 32-bit FAT LBA-mapped */
64 { 0x0E, "DOS FAT16 L "}, /* Primary DOS w/ 16-bit FAT LBA-mapped */
65 { 0x0F, "Extended LBA"}, /* Extended DOS LBA-mapped */
66 { 0x10, "OPUS "}, /* OPUS */
67 { 0x11, "OS/2 hidden "}, /* OS/2 BM: hidden DOS 12-bit FAT */
68 { 0x12, "Compaq Diag."}, /* Compaq Diagnostics */
69 { 0x14, "OS/2 hidden "}, /* OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug */
70 { 0x16, "OS/2 hidden "}, /* OS/2 BM: hidden DOS 16-bit FAT >=32M */
71 { 0x17, "OS/2 hidden "}, /* OS/2 BM: hidden IFS */
72 { 0x18, "AST swap "}, /* AST Windows swapfile */
73 { 0x19, "Willowtech "}, /* Willowtech Photon coS */
74 { 0x1C, "Thinkpad Rec"}, /* IBM Thinkpad recovery partition */
75 { 0x20, "Willowsoft "}, /* Willowsoft OFS1 */
76 { 0x24, "NEC DOS "}, /* NEC DOS */
77 { 0x27, "MirBSD "}, /* MirOS BSD disklabel */
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 { 0x84, "OS/2 hidden "}, /* OS/2 hidden C: drive */
110 { 0x85, "Linux ext. "}, /* Linux extended */
111 { 0x86, "NT FAT VS "}, /* NT FAT volume set */
112 { 0x87, "NTFS VS "}, /* NTFS volume set or HPFS mirrored */
113 { 0x88, "O.ADK cfgfs "}, /* OpenADK cfgfs or fwcf */
114 { 0x93, "Amoeba FS "}, /* Amoeba filesystem */
115 { 0x94, "Amoeba BBT "}, /* Amoeba bad block table */
116 { 0x96, "ISO 9660 "}, /* ISO 9660 (CHRP, manifold-boot) */
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 { 0xA8, "MacOS X "}, /* MacOS X main partition */
124 { 0xA9, "NetBSD "}, /* NetBSD */
125 { 0xAB, "MacOS X boot"}, /* MacOS X boot partition */
126 { 0xB7, "BSDI filesy*"}, /* BSDI BSD/386 filesystem */
127 { 0xB8, "BSDI swap "}, /* BSDI BSD/386 swap */
128 { 0xBF, "Solaris "}, /* Solaris */
129 { 0xC0, "CTOS "}, /* CTOS */
130 { 0xC1, "DRDOSs FAT12"}, /* DRDOS/sec (FAT-12) */
131 { 0xC4, "DRDOSs < 32M"}, /* DRDOS/sec (FAT-16, < 32M) */
132 { 0xC6, "DRDOSs >=32M"}, /* DRDOS/sec (FAT-16, >= 32M) */
133 { 0xC7, "HPFS Disbled"}, /* Syrinx (Cyrnix?) or HPFS disabled */
134 { 0xDA, "non-FS data "}, /* raw / non-filesystem data */
135 { 0xDB, "CPM/C.DOS/C*"}, /* Concurrent CPM or C.DOS or CTOS */
136 { 0xDE, "Dell Maint "}, /* Dell maintenance partition */
137 { 0xE1, "SpeedStor "}, /* DOS access or SpeedStor 12-bit FAT extended partition */
138 { 0xE3, "SpeedStor "}, /* DOS R/O or SpeedStor or Storage Dimensions */
139 { 0xE4, "SpeedStor "}, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
140 { 0xEB, "BeOS/i386 "}, /* BeOS for Intel */
141 { 0xEE, "EFI GPT "}, /* EFI Protective Partition */
142 { 0xEF, "EFI Sys "}, /* EFI System Partition */
143 { 0xF1, "SpeedStor "}, /* SpeedStor or Storage Dimensions */
144 { 0xF2, "DOS 3.3+ Sec"}, /* DOS 3.3+ Secondary */
145 { 0xF4, "SpeedStor "}, /* SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML */
146 { 0xFF, "Xenix BBT "}, /* Xenix Bad Block Table */
147 };
148
149 void
PRT_printall(void)150 PRT_printall(void)
151 {
152 size_t i, idrows;
153
154 idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4;
155
156 printf("Choose from the following Partition id values:\n");
157 for (i = 0; i < idrows; i++) {
158 printf("%02X %s %02X %s %02X %s",
159 part_types[i].type, part_types[i].sname,
160 part_types[i+idrows].type, part_types[i+idrows].sname,
161 part_types[i+idrows*2].type, part_types[i+idrows*2].sname);
162 if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) {
163 printf(" %02X %s\n",
164 part_types[i+idrows*3].type,
165 part_types[i+idrows*3].sname);
166 } else
167 printf( "\n" );
168 }
169 }
170
171 const char *
PRT_ascii_id(int id)172 PRT_ascii_id(int id)
173 {
174 static const char unknown[] = "<Unknown ID>";
175 size_t i;
176
177 for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) {
178 if (part_types[i].type == id)
179 return (part_types[i].sname);
180 }
181
182 return (unknown);
183 }
184
185 void
PRT_parse(disk_t * disk,void * prt,off_t offset,off_t reloff,prt_t * partn)186 PRT_parse(disk_t *disk, void *prt, off_t offset, off_t reloff,
187 prt_t *partn)
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) \
206 || (partn->id == DOSPTYP_EXTENDL) \
207 || (partn->id == DOSPTYP_EXTENDLX))
208 off = reloff;
209 else
210 off = offset;
211
212 partn->bs = getlong(p) + off;
213 partn->ns = getlong(p+4);
214
215 PRT_fix_CHS(disk, partn);
216 }
217
218 int
PRT_check_chs(prt_t * partn)219 PRT_check_chs(prt_t *partn)
220 {
221 if ( (partn->shead > 255) ||
222 (partn->ssect >63) ||
223 (partn->scyl > 1023) ||
224 (partn->ehead >255) ||
225 (partn->esect >63) ||
226 (partn->ecyl > 1023) )
227 {
228 return 0;
229 }
230 return 1;
231 }
232 void
PRT_make(prt_t * partn,off_t offset,off_t reloff,void * prt)233 PRT_make(prt_t *partn, off_t offset, off_t reloff, void *prt)
234 {
235 unsigned char *p = prt;
236 int ecsave = 0, scsave = 0;
237 int modified = 0;
238 off_t off;
239
240 if ((partn->scyl > 1023) || (partn->ecyl > 1023)) {
241 scsave = partn->scyl;
242 ecsave = partn->ecyl;
243 partn->scyl = (partn->scyl > 1023)? 1023: partn->scyl;
244 partn->ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl;
245 modified = 1;
246 }
247 if ((partn->id == DOSPTYP_EXTEND) \
248 || (partn->id == DOSPTYP_EXTENDL) \
249 || (partn->id == DOSPTYP_EXTENDLX))
250 off = reloff;
251 else
252 off = offset;
253
254 if (PRT_check_chs(partn)) {
255 *p++ = partn->flag & 0xFF;
256
257 *p++ = partn->shead & 0xFF;
258 *p++ = (partn->ssect & 0x3F) | ((partn->scyl & 0x300) >> 2);
259 *p++ = partn->scyl & 0xFF;
260
261 *p++ = partn->id & 0xFF;
262
263 *p++ = partn->ehead & 0xFF;
264 *p++ = (partn->esect & 0x3F) | ((partn->ecyl & 0x300) >> 2);
265 *p++ = partn->ecyl & 0xFF;
266 } else {
267 /* should this really keep flag, id and set others to 0xff? */
268 *p++ = partn->flag & 0xFF;
269 *p++ = 0xFF;
270 *p++ = 0xFF;
271 *p++ = 0xFF;
272 *p++ = partn->id & 0xFF;
273 *p++ = 0xFF;
274 *p++ = 0xFF;
275 *p++ = 0xFF;
276 printf("Warning CHS values out of bounds only saving LBA values\n");
277 }
278
279 putlong(p, partn->bs - off);
280 putlong(p+4, partn->ns);
281 if (modified) {
282 partn->scyl = scsave;
283 partn->ecyl = ecsave;
284 }
285 }
286
287 void
PRT_print(int num,prt_t * partn,char * units,int apart)288 PRT_print(int num, prt_t *partn, char *units, int apart)
289 {
290 double size;
291 int i;
292 i = unit_lookup(units);
293
294 if (partn == NULL) {
295 printf(" Starting Ending LBA Info:\n");
296 printf(" #: id C H S - C H S [ start: size ]\n");
297 printf("--------------------------------------------------------------------------\n");
298 } else {
299 size = ((double)partn->ns * unit_types[SECTORS].conversion) /
300 unit_types[i].conversion;
301 printf("%c%1d: %.2X %4u %3u %2u - %4u %3u %2u [%12u:%12.0f%s] %s\n",
302 (partn->flag == 0x80)?'*':(apart == num)?'!':' ',
303 num, partn->id,
304 partn->scyl, partn->shead, partn->ssect,
305 partn->ecyl, partn->ehead, partn->esect,
306 partn->bs, size,
307 unit_types[i].disp,
308 PRT_ascii_id(partn->id));
309 }
310 }
311
312 void
PRT_fix_BN(disk_t * disk,prt_t * part,int pn)313 PRT_fix_BN(disk_t *disk, prt_t *part, int pn)
314 {
315 u_int32_t spt, tpc, spc;
316 u_int32_t start = 0;
317 u_int32_t end = 0;
318
319 /* Zero out entry if not used */
320 if (part->id == DOSPTYP_UNUSED ) {
321 memset(part, 0, sizeof(*part));
322 return;
323 }
324
325 /* Disk metrics */
326 spt = disk->real->sectors;
327 tpc = disk->real->heads;
328 spc = spt * tpc;
329
330 start += part->scyl * spc;
331 start += part->shead * spt;
332 start += part->ssect - 1;
333
334 end += part->ecyl * spc;
335 end += part->ehead * spt;
336 end += part->esect - 1;
337
338 /* XXX - Should handle this... */
339 if (start > end)
340 warn("Start of partition #%d after end!", pn);
341
342 part->bs = start;
343 part->ns = (end - start) + 1;
344 }
345
346 void
PRT_fix_CHS(disk_t * disk,prt_t * part)347 PRT_fix_CHS(disk_t *disk, prt_t *part)
348 {
349 u_int32_t spt, tpc, spc;
350 u_int32_t start, end, size;
351 u_int32_t cyl, head, sect;
352
353 /* Zero out entry if not used */
354 if (part->id == DOSPTYP_UNUSED ) {
355 memset(part, 0, sizeof(*part));
356 return;
357 }
358
359 /* Disk metrics */
360 spt = disk->real->sectors;
361 tpc = disk->real->heads;
362 spc = spt * tpc;
363
364 start = part->bs;
365 size = part->ns;
366 end = (start + size) - 1;
367
368 /* Figure out starting CHS values */
369 cyl = (start / spc); start -= (cyl * spc);
370 head = (start / spt); start -= (head * spt);
371 sect = (start + 1);
372
373 part->scyl = cyl;
374 part->shead = head;
375 part->ssect = sect;
376
377 /* Figure out ending CHS values */
378 cyl = (end / spc); end -= (cyl * spc);
379 head = (end / spt); end -= (head * spt);
380 sect = (end + 1);
381
382 part->ecyl = cyl;
383 part->ehead = head;
384 part->esect = sect;
385 }
386