]> git.cameronkatri.com Git - apple_cmds.git/blob - diskdev_cmds/fdisk.tproj/mbr.c
Merge branch 'apple'
[apple_cmds.git] / diskdev_cmds / fdisk.tproj / mbr.c
1 /*
2 * Copyright (c) 2002, 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Copyright (c) 1997 Tobias Weingartner
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by Tobias Weingartner.
39 * 4. The name of the author may not be used to endorse or promote products
40 * derived from this software without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */
53
54 #include <err.h>
55 #include <util.h>
56 #include <stdio.h>
57 #include <unistd.h>
58 #include <stdlib.h>
59 #include <ctype.h>
60 #include <memory.h>
61 #include <sys/fcntl.h>
62 #include <sys/ioctl.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #if 0
66 #include <sys/dkio.h>
67 #endif
68 #include <machine/param.h>
69 #include "disk.h"
70 #include "misc.h"
71 #include "mbr.h"
72 #include "part.h"
73
74
75 void
76 MBR_init(disk, mbr)
77 disk_t *disk;
78 mbr_t *mbr;
79 {
80 /* Fix up given mbr for this disk */
81 mbr->part[0].flag = 0;
82 mbr->part[1].flag = 0;
83 mbr->part[2].flag = 0;
84 #if !defined(DOSPTYP_OPENBSD)
85 mbr->part[3].flag = 0;
86 mbr->signature = MBR_SIGNATURE;
87 #else
88
89 mbr->part[3].flag = DOSACTIVE;
90 mbr->signature = DOSMBR_SIGNATURE;
91
92 /* Use whole disk, save for first head, on first cyl. */
93 mbr->part[3].id = DOSPTYP_OPENBSD;
94 mbr->part[3].scyl = 0;
95 mbr->part[3].shead = 1;
96 mbr->part[3].ssect = 1;
97
98 /* Go right to the end */
99 mbr->part[3].ecyl = disk->real->cylinders - 1;
100 mbr->part[3].ehead = disk->real->heads - 1;
101 mbr->part[3].esect = disk->real->sectors;
102
103 /* Fix up start/length fields */
104 PRT_fix_BN(disk, &mbr->part[3], 3);
105
106 #if defined(__powerpc__) || defined(__mips__)
107 /* Now fix up for the MS-DOS boot partition on PowerPC. */
108 mbr->part[0].flag = DOSACTIVE; /* Boot from dos part */
109 mbr->part[3].flag = 0;
110 mbr->part[3].ns += mbr->part[3].bs;
111 mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
112 mbr->part[3].ns -= mbr->part[3].bs;
113 PRT_fix_CHS(disk, &mbr->part[3], 3);
114 if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
115 /* align the partition on a cylinder boundary */
116 mbr->part[3].shead = 0;
117 mbr->part[3].ssect = 1;
118 mbr->part[3].scyl += 1;
119 }
120 /* Fix up start/length fields */
121 PRT_fix_BN(disk, &mbr->part[3], 3);
122 #endif
123 #endif
124 }
125
126 void
127 MBR_parse(disk, offset, reloff, mbr)
128 disk_t *disk;
129 off_t offset;
130 off_t reloff;
131 mbr_t *mbr;
132 {
133 int i;
134 unsigned char *mbr_buf = mbr->buf;
135
136 memcpy(mbr->code, mbr_buf, MBR_CODE_SIZE);
137 mbr->offset = offset;
138 mbr->reloffset = reloff;
139 mbr->signature = getshort(&mbr_buf[MBR_SIG_OFF]);
140
141 for (i = 0; i < NDOSPART; i++)
142 PRT_parse(disk, &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i],
143 offset, reloff, &mbr->part[i], i);
144 }
145
146 void
147 MBR_make(mbr)
148 mbr_t *mbr;
149 {
150 int i;
151 unsigned char *mbr_buf = mbr->buf;
152
153 memcpy(mbr_buf, mbr->code, MBR_CODE_SIZE);
154 putshort(&mbr_buf[MBR_SIG_OFF], mbr->signature);
155
156 for (i = 0; i < NDOSPART; i++)
157 PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
158 &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i]);
159 }
160
161 void
162 MBR_print(mbr)
163 mbr_t *mbr;
164 {
165 int i;
166
167 /* Header */
168 printf("Signature: 0x%X\n",
169 (int)mbr->signature);
170 PRT_print(0, NULL);
171
172 /* Entries */
173 for (i = 0; i < NDOSPART; i++)
174 PRT_print(i, &mbr->part[i]);
175 }
176
177 int
178 MBR_read(disk, fd, where, mbr)
179 disk_t *disk;
180 int fd;
181 off_t where;
182 mbr_t *mbr;
183 {
184 off_t off;
185 int len;
186 int size;
187 unsigned char *buf = mbr->buf;
188
189 size = disk->real->sector_size;
190 where *= size;
191 off = lseek(fd, where, SEEK_SET);
192 if (off != where)
193 return (off);
194 len = read(fd, buf, size);
195 if (len != size)
196 return (len);
197 return (0);
198 }
199
200 int
201 MBR_write(disk, fd, mbr)
202 disk_t *disk;
203 int fd;
204 mbr_t *mbr;
205 {
206 off_t off;
207 int len;
208 int size;
209 unsigned char *buf = mbr->buf;
210 off_t where;
211
212 size = disk->real->sector_size;
213 where = mbr->offset * size;
214 off = lseek(fd, where, SEEK_SET);
215 if (off != where)
216 return (off);
217 len = write(fd, buf, size);
218 if (len != size)
219 return (len);
220 #if defined(DIOCRLDINFO)
221 (void) ioctl(fd, DIOCRLDINFO, 0);
222 #endif
223 return (0);
224 }
225
226 void
227 MBR_pcopy(disk, mbr)
228 disk_t *disk;
229 mbr_t *mbr;
230 {
231 /*
232 * Copy partition table from the disk indicated
233 * to the supplied mbr structure
234 */
235
236 int i, fd, offset = 0, reloff = 0;
237 mbr_t *mbrd;
238
239 mbrd = MBR_alloc(NULL);
240 fd = DISK_open(disk->name, O_RDONLY);
241 MBR_read(disk, fd, offset, mbrd);
242 DISK_close(fd);
243 MBR_parse(disk, offset, reloff, mbrd);
244 for (i = 0; i < NDOSPART; i++) {
245 PRT_parse(disk, &mbrd->buf[MBR_PART_OFF +
246 MBR_PART_SIZE * i],
247 offset, reloff, &mbr->part[i], i);
248 PRT_print(i, &mbr->part[i]);
249 }
250 MBR_free(mbrd);
251 }
252
253
254 static int
255 parse_number(char *str, int default_val, int base) {
256 if (str != NULL && *str != '\0') {
257 default_val = strtol(str, NULL, base);
258 }
259 return default_val;
260 }
261
262 static inline int
263 null_arg(char *arg) {
264 if (arg == NULL || *arg == 0)
265 return 1;
266 else
267 return 0;
268 }
269
270 /* Parse a partition spec into a partition structure.
271 * Spec is of the form:
272 * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>]
273 * We require passing in the disk and mbr so we can
274 * set reasonable defaults for values, e.g. "the whole disk"
275 * or "starting after the last partition."
276 */
277 #define N_ARGS 10
278 static int
279 MBR_parse_one_spec(char *line, disk_t *disk, mbr_t *mbr, int pn)
280 {
281 int i;
282 char *args[N_ARGS];
283 prt_t *part = &mbr->part[pn];
284 int next_start, next_size;
285
286 /* There are up to 10 arguments. */
287 for (i=0; i<N_ARGS; i++) {
288 char *arg;
289 while (isspace(*line))
290 line++;
291 arg = strsep(&line, ",\n");
292 if (arg == NULL || line == NULL) {
293 break;
294 }
295 args[i] = arg;
296 }
297 for (; i<N_ARGS; i++) {
298 args[i] = NULL;
299 }
300 /* Set reasonable defaults. */
301 if (pn == 0) {
302 next_start = 0;
303 } else {
304 next_start = mbr->part[pn-1].bs + mbr->part[pn-1].ns;
305 }
306 next_size = disk->real->size;
307 for(i=0; i<pn; i++) {
308 next_size -= mbr->part[i].ns;
309 }
310
311 part->id = parse_number(args[2], 0xA8, 16);
312 if (!null_arg(args[3]) && *args[3] == '*') {
313 part->flag = 0x80;
314 } else {
315 part->flag = 0;
316 }
317 /* If you specify the start or end sector,
318 you have to give both. */
319 if ((null_arg(args[0]) && !null_arg(args[1])) ||
320 (!null_arg(args[0]) && null_arg(args[1]))) {
321 errx(1, "You must specify both start and size, or neither");
322 return -1;
323 }
324
325 /* If you specify one of the CHS args,
326 you have to give them all. */
327 if (!null_arg(args[4])) {
328 for (i=5; i<10; i++) {
329 if (null_arg(args[i])) {
330 errx(1, "Either all CHS arguments must be specified, or none");
331 return -1;
332 }
333 }
334
335 part->scyl = parse_number(args[4], 0, 10);
336 part->shead = parse_number(args[5], 0, 10);
337 part->ssect = parse_number(args[6], 0, 10);
338 part->scyl = parse_number(args[7], 0, 10);
339 part->shead = parse_number(args[8], 0, 10);
340 part->ssect = parse_number(args[9], 0, 10);
341 if (null_arg(args[0])) {
342 PRT_fix_BN(disk, part, pn);
343 }
344 } else {
345 /* See if they gave no CHS and no start/end */
346 if (null_arg(args[0])) {
347 errx(1, "You must specify either start sector and size or CHS");
348 return -1;
349 }
350 }
351 if (!null_arg(args[0])) {
352 part->bs = parse_number(args[0], next_start, 10);
353 part->ns = parse_number(args[1], next_size, 10);
354 PRT_fix_CHS(disk, part, pn);
355 }
356 return 0;
357 }
358
359
360 typedef struct _mbr_chain {
361 mbr_t mbr;
362 struct _mbr_chain *next;
363 } mbr_chain_t;
364
365 /* Parse some number of MBR spec lines.
366 * Spec is of the form:
367 * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>]
368 *
369 */
370 mbr_t *
371 MBR_parse_spec(FILE *f, disk_t *disk)
372 {
373 int lineno;
374 int offset, firstoffset;
375 mbr_t *mbr, *head, *prev_mbr;
376
377 head = mbr = prev_mbr = NULL;
378 firstoffset = 0;
379 do {
380
381 offset = 0;
382 for (lineno = 0; lineno < NDOSPART && !feof(f); lineno++) {
383 char line[256];
384 char *str;
385 prt_t *part;
386
387 do {
388 str = fgets(line, 256, f);
389 } while ((str != NULL) && (*str == '\0'));
390 if (str == NULL) {
391 break;
392 }
393
394 if (mbr == NULL) {
395 mbr = MBR_alloc(prev_mbr);
396 if (head == NULL)
397 head = mbr;
398 }
399
400 if (MBR_parse_one_spec(line, disk, mbr, lineno)) {
401 /* MBR_parse_one_spec printed the error message. */
402 return NULL;
403 }
404 part = &mbr->part[lineno];
405 if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) {
406 offset = part->bs;
407 if (firstoffset == 0) firstoffset = offset;
408 }
409 }
410 /* If fewer lines than partitions, zero out the rest of the partitions */
411 if (mbr != NULL) {
412 for (; lineno < NDOSPART; lineno++) {
413 bzero(&mbr->part[lineno], sizeof(prt_t));
414 }
415 }
416 prev_mbr = mbr;
417 mbr = NULL;
418 } while (offset >= 0 && !feof(f));
419
420 return head;
421 }
422
423 void
424 MBR_dump(mbr_t *mbr)
425 {
426 int i;
427 prt_t *part;
428
429 for (i=0; i<NDOSPART; i++) {
430 part = &mbr->part[i];
431 printf("%d,%d,0x%02X,%c,%u,%u,%u,%u,%u,%u\n",
432 part->bs,
433 part->ns,
434 part->id,
435 (part->flag == 0x80) ? '*' : '-',
436 part->scyl,
437 part->shead,
438 part->ssect,
439 part->ecyl,
440 part->ehead,
441 part->esect);
442 }
443 }
444
445 mbr_t *
446 MBR_alloc(mbr_t *parent)
447 {
448 mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
449 bzero(mbr, sizeof(mbr_t));
450 if (parent) {
451 parent->next = mbr;
452 }
453 mbr->signature = MBR_SIGNATURE;
454 return mbr;
455 }
456
457 void
458 MBR_free(mbr_t *mbr)
459 {
460 mbr_t *tmp;
461 while (mbr) {
462 tmp = mbr->next;
463 free(mbr);
464 mbr = tmp;
465 }
466 }
467
468 /* Read and parse all the partition tables on the disk,
469 * including extended partitions.
470 */
471 mbr_t *
472 MBR_read_all(disk_t *disk)
473 {
474 mbr_t *mbr = NULL, *head = NULL;
475 int i, fd, offset, firstoff;
476
477 fd = DISK_open(disk->name, O_RDONLY);
478 firstoff = offset = 0;
479 do {
480 mbr = MBR_alloc(mbr);
481 if (head == NULL) {
482 head = mbr;
483 }
484 MBR_read(disk, fd, offset, mbr);
485 MBR_parse(disk, offset, firstoff, mbr);
486 if (mbr->signature != MBR_SIGNATURE) {
487 /* The MBR signature is invalid. */
488 break;
489 }
490 offset = 0;
491 for (i=0; i<NDOSPART; i++) {
492 prt_t *part = &mbr->part[i];
493 if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) {
494 offset = part->bs;
495 if (firstoff == 0) {
496 firstoff = offset;
497 }
498 }
499 }
500 } while (offset > 0);
501 DISK_close(fd);
502
503 return head;
504 }
505
506
507 int
508 MBR_write_all(disk_t *disk, mbr_t *mbr)
509 {
510 int result = 0;
511 int fd;
512
513 fd = DISK_open(disk->name, O_RDWR);
514 while (mbr) {
515 MBR_make(mbr);
516 result = MBR_write(disk, fd, mbr);
517 if (result)
518 break;
519 mbr = mbr->next;
520 }
521 DISK_close(fd);
522 return result;
523 }
524
525 void
526 MBR_print_all(mbr_t *mbr) {
527 while (mbr) {
528 MBR_print(mbr);
529 mbr = mbr->next;
530 }
531 }
532
533 void
534 MBR_dump_all(mbr_t *mbr) {
535 while (mbr) {
536 MBR_dump(mbr);
537 mbr = mbr->next;
538 }
539 }
540
541 void
542 MBR_clear(mbr_t *mbr) {
543 int i;
544 if (mbr->next) {
545 MBR_free(mbr->next);
546 mbr->next = NULL;
547 }
548 for (i=0; i<4; i++) {
549 bzero(&mbr->part[i], sizeof(mbr->part[i]));
550 }
551 bzero(&mbr->buf, sizeof(mbr->buf));
552 }
553