Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/util/fdisk/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
75void
76MBR_init(disk, mbr)
77disk_t *disk;
78mbr_t *mbr;
79{
80/* Fix up given mbr for this disk */
81mbr->part[0].flag = 0;
82mbr->part[1].flag = 0;
83mbr->part[2].flag = 0;
84#if !defined(DOSPTYP_OPENBSD)
85mbr->part[3].flag = 0;
86mbr->signature = MBR_SIGNATURE;
87#else
88
89mbr->part[3].flag = DOSACTIVE;
90mbr->signature = DOSMBR_SIGNATURE;
91
92/* Use whole disk, save for first head, on first cyl. */
93mbr->part[3].id = DOSPTYP_OPENBSD;
94mbr->part[3].scyl = 0;
95mbr->part[3].shead = 1;
96mbr->part[3].ssect = 1;
97
98/* Go right to the end */
99mbr->part[3].ecyl = disk->real->cylinders - 1;
100mbr->part[3].ehead = disk->real->heads - 1;
101mbr->part[3].esect = disk->real->sectors;
102
103/* Fix up start/length fields */
104PRT_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. */
108mbr->part[0].flag = DOSACTIVE;/* Boot from dos part */
109mbr->part[3].flag = 0;
110mbr->part[3].ns += mbr->part[3].bs;
111mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
112mbr->part[3].ns -= mbr->part[3].bs;
113PRT_fix_CHS(disk, &mbr->part[3], 3);
114if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
115/* align the partition on a cylinder boundary */
116mbr->part[3].shead = 0;
117mbr->part[3].ssect = 1;
118mbr->part[3].scyl += 1;
119}
120/* Fix up start/length fields */
121PRT_fix_BN(disk, &mbr->part[3], 3);
122#endif
123#endif
124}
125
126void
127MBR_parse(disk, offset, reloff, mbr)
128disk_t *disk;
129off_t offset;
130off_t reloff;
131mbr_t *mbr;
132{
133int i;
134unsigned char *mbr_buf = mbr->buf;
135
136memcpy(mbr->code, mbr_buf, MBR_CODE_SIZE);
137mbr->offset = offset;
138mbr->reloffset = reloff;
139mbr->signature = getshort(&mbr_buf[MBR_SIG_OFF]);
140
141for (i = 0; i < NDOSPART; i++)
142PRT_parse(disk, &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i],
143 offset, reloff, &mbr->part[i], i);
144}
145
146void
147MBR_make(mbr)
148mbr_t *mbr;
149{
150int i;
151unsigned char *mbr_buf = mbr->buf;
152
153memcpy(mbr_buf, mbr->code, MBR_CODE_SIZE);
154putshort(&mbr_buf[MBR_SIG_OFF], mbr->signature);
155
156for (i = 0; i < NDOSPART; i++)
157PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
158 &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i]);
159}
160
161void
162MBR_print(mbr)
163mbr_t *mbr;
164{
165int i;
166
167/* Header */
168printf("Signature: 0x%X\n",
169 (int)mbr->signature);
170PRT_print(0, NULL);
171
172/* Entries */
173for (i = 0; i < NDOSPART; i++)
174PRT_print(i, &mbr->part[i]);
175}
176
177int
178MBR_read(disk, fd, where, mbr)
179disk_t *disk;
180int fd;
181off_t where;
182mbr_t *mbr;
183{
184off_t off;
185int len;
186int size;
187unsigned char *buf = mbr->buf;
188
189size = disk->real->sector_size;
190where *= size;
191off = lseek(fd, where, SEEK_SET);
192if (off != where)
193return (off);
194len = read(fd, buf, size);
195if (len != size)
196return (len);
197return (0);
198}
199
200int
201MBR_write(disk, fd, mbr)
202disk_t *disk;
203int fd;
204mbr_t *mbr;
205{
206off_t off;
207int len;
208int size;
209unsigned char *buf = mbr->buf;
210off_t where;
211
212size = disk->real->sector_size;
213where = mbr->offset * size;
214off = lseek(fd, where, SEEK_SET);
215if (off != where)
216return (off);
217len = write(fd, buf, size);
218if (len != size)
219return (len);
220#if defined(DIOCRLDINFO)
221(void) ioctl(fd, DIOCRLDINFO, 0);
222#endif
223return (0);
224}
225
226void
227MBR_pcopy(disk, mbr)
228disk_t *disk;
229mbr_t *mbr;
230{
231/*
232 * Copy partition table from the disk indicated
233 * to the supplied mbr structure
234 */
235
236int i, fd, offset = 0, reloff = 0;
237mbr_t *mbrd;
238
239mbrd = MBR_alloc(NULL);
240if (!mbr) errx(1, "out of memory");
241fd = DISK_open(disk->name, O_RDONLY);
242if (fd == -1)
243err(1, "Could not open %s", disk->name);
244MBR_read(disk, fd, offset, mbrd);
245DISK_close(fd);
246MBR_parse(disk, offset, reloff, mbrd);
247for (i = 0; i < NDOSPART; i++) {
248PRT_parse(disk, &mbrd->buf[MBR_PART_OFF +
249 MBR_PART_SIZE * i],
250 offset, reloff, &mbr->part[i], i);
251PRT_print(i, &mbr->part[i]);
252}
253MBR_free(mbrd);
254}
255
256
257static int
258parse_number(char *str, int default_val, int base) {
259if (str != NULL && *str != '\0') {
260 default_val = strtol(str, NULL, base);
261}
262return default_val;
263}
264
265static inline int
266null_arg(char *arg) {
267 if (arg == NULL || *arg == 0)
268 return 1;
269 else
270 return 0;
271}
272
273/* Parse a partition spec into a partition structure.
274 * Spec is of the form:
275 * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>]
276 * We require passing in the disk and mbr so we can
277 * set reasonable defaults for values, e.g. "the whole disk"
278 * or "starting after the last partition."
279 */
280#define N_ARGS 10
281static int
282MBR_parse_one_spec(char *line, disk_t *disk, mbr_t *mbr, int pn)
283{
284 int i;
285 char *args[N_ARGS];
286 prt_t *part = &mbr->part[pn];
287 int next_start, next_size;
288
289 /* There are up to 10 arguments. */
290 for (i=0; i<N_ARGS; i++) {
291 char *arg;
292 while (isspace(*line))
293 line++;
294 arg = strsep(&line, ",\n");
295 if (arg == NULL || line == NULL) {
296 break;
297 }
298 args[i] = arg;
299 }
300 for (; i<N_ARGS; i++) {
301 args[i] = NULL;
302 }
303 /* Set reasonable defaults. */
304 if (pn == 0) {
305 next_start = 0;
306 } else {
307 next_start = mbr->part[pn-1].bs + mbr->part[pn-1].ns;
308 }
309 next_size = disk->real->size;
310 for(i=0; i<pn; i++) {
311 next_size -= mbr->part[i].ns;
312 }
313
314 part->id = parse_number(args[2], 0xA8, 16);
315 if (!null_arg(args[3]) && *args[3] == '*') {
316 part->flag = 0x80;
317 } else {
318 part->flag = 0;
319 }
320 /* If you specify the start or end sector,
321 you have to give both. */
322 if ((null_arg(args[0]) && !null_arg(args[1])) ||
323 (!null_arg(args[0]) && null_arg(args[1]))) {
324 errx(1, "You must specify both start and size, or neither");
325 return -1;
326 }
327
328 /* If you specify one of the CHS args,
329 you have to give them all. */
330 if (!null_arg(args[4])) {
331 for (i=5; i<10; i++) {
332 if (null_arg(args[i])) {
333errx(1, "Either all CHS arguments must be specified, or none");
334return -1;
335 }
336 }
337
338 part->scyl = parse_number(args[4], 0, 10);
339 part->shead = parse_number(args[5], 0, 10);
340 part->ssect = parse_number(args[6], 0, 10);
341 part->scyl = parse_number(args[7], 0, 10);
342 part->shead = parse_number(args[8], 0, 10);
343 part->ssect = parse_number(args[9], 0, 10);
344 if (null_arg(args[0])) {
345 PRT_fix_BN(disk, part, pn);
346 }
347 } else {
348 /* See if they gave no CHS and no start/end */
349 if (null_arg(args[0])) {
350 errx(1, "You must specify either start sector and size or CHS");
351 return -1;
352 }
353 }
354 if (!null_arg(args[0])) {
355 part->bs = parse_number(args[0], next_start, 10);
356 part->ns = parse_number(args[1], next_size, 10);
357 PRT_fix_CHS(disk, part, pn);
358 }
359 return 0;
360}
361
362
363typedef struct _mbr_chain {
364 mbr_t mbr;
365 struct _mbr_chain *next;
366} mbr_chain_t;
367
368/* Parse some number of MBR spec lines.
369 * Spec is of the form:
370 * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>]
371 *
372 */
373mbr_t *
374MBR_parse_spec(FILE *f, disk_t *disk)
375{
376 int lineno;
377 int offset, firstoffset;
378 mbr_t *mbr, *head, *prev_mbr;
379
380 head = mbr = prev_mbr = NULL;
381 firstoffset = 0;
382 do {
383
384 offset = 0;
385 for (lineno = 0; lineno < NDOSPART && !feof(f); lineno++) {
386 char line[256];
387 char *str;
388prt_t *part;
389
390do {
391 str = fgets(line, 256, f);
392} while ((str != NULL) && (*str == '\0'));
393 if (str == NULL) {
394 break;
395 }
396
397if (mbr == NULL) {
398 mbr = MBR_alloc(prev_mbr);
399if (!mbr) errx(1, "out of memory");
400 if (head == NULL)
401head = mbr;
402}
403
404if (MBR_parse_one_spec(line, disk, mbr, lineno)) {
405 /* MBR_parse_one_spec printed the error message. */
406 return NULL;
407}
408part = &mbr->part[lineno];
409if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) {
410 offset = part->bs;
411 if (firstoffset == 0) firstoffset = offset;
412}
413 }
414 /* If fewer lines than partitions, zero out the rest of the partitions */
415 if (mbr != NULL) {
416for (; lineno < NDOSPART; lineno++) {
417 bzero(&mbr->part[lineno], sizeof(prt_t));
418}
419 }
420 prev_mbr = mbr;
421 mbr = NULL;
422 } while (offset >= 0 && !feof(f));
423
424 return head;
425}
426
427void
428MBR_dump(mbr_t *mbr)
429{
430 int i;
431 prt_t *part;
432
433 for (i=0; i<NDOSPART; i++) {
434 part = &mbr->part[i];
435 printf("%d,%d,0x%02X,%c,%d,%d,%d,%d,%d,%d\n",
436 part->bs,
437 part->ns,
438 part->id,
439 (part->flag == 0x80) ? '*' : '-',
440 part->scyl,
441 part->shead,
442 part->ssect,
443 part->ecyl,
444 part->ehead,
445 part->esect);
446 }
447}
448
449mbr_t *
450MBR_alloc(mbr_t *parent)
451{
452 mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
453 if (!mbr) return NULL;
454 bzero(mbr, sizeof(mbr_t));
455 if (parent) {
456 parent->next = mbr;
457 }
458 mbr->signature = MBR_SIGNATURE;
459 return mbr;
460}
461
462void
463MBR_free(mbr_t *mbr)
464{
465 mbr_t *tmp;
466 while (mbr) {
467 tmp = mbr->next;
468 free(mbr);
469 mbr = tmp;
470 }
471}
472
473/* Read and parse all the partition tables on the disk,
474 * including extended partitions.
475 */
476mbr_t *
477MBR_read_all(disk_t *disk)
478{
479 mbr_t *mbr = NULL, *head = NULL;
480 int i, fd, offset, firstoff;
481
482 fd = DISK_open(disk->name, O_RDONLY);
483 if (fd == -1)
484err(1, "Could not open %s", disk->name);
485 firstoff = offset = 0;
486 do {
487 mbr = MBR_alloc(mbr);
488if (!mbr) errx(1, "out of memory");
489 if (head == NULL) {
490 head = mbr;
491 }
492 MBR_read(disk, fd, offset, mbr);
493 MBR_parse(disk, offset, firstoff, mbr);
494 if (mbr->signature != MBR_SIGNATURE) {
495 /* The MBR signature is invalid. */
496 break;
497 }
498 offset = 0;
499 for (i=0; i<NDOSPART; i++) {
500 prt_t *part = &mbr->part[i];
501 if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) {
502offset = part->bs;
503if (firstoff == 0) {
504 firstoff = offset;
505}
506 }
507 }
508 } while (offset > 0);
509 DISK_close(fd);
510
511 return head;
512}
513
514
515int
516MBR_write_all(disk_t *disk, mbr_t *mbr)
517{
518 int result = 0;
519 int fd;
520
521 fd = DISK_open(disk->name, O_RDWR);
522 if (fd == -1)
523err(1, "Could not open %s", disk->name);
524 while (mbr) {
525 MBR_make(mbr);
526 result = MBR_write(disk, fd, mbr);
527 if (result)
528 break;
529 mbr = mbr->next;
530 }
531 DISK_close(fd);
532 return result;
533}
534
535void
536MBR_print_all(mbr_t *mbr) {
537 while (mbr) {
538 MBR_print(mbr);
539 mbr = mbr->next;
540 }
541}
542
543void
544MBR_dump_all(mbr_t *mbr) {
545 while (mbr) {
546 MBR_dump(mbr);
547 mbr = mbr->next;
548 }
549}
550
551void
552MBR_clear(mbr_t *mbr) {
553 int i;
554 if (mbr->next) {
555 MBR_free(mbr->next);
556 mbr->next = NULL;
557 }
558 for (i=0; i<4; i++) {
559 bzero(&mbr->part[i], sizeof(mbr->part[i]));
560 }
561 bzero(&mbr->buf, sizeof(mbr->buf));
562}
563
564

Archive Download this file

Revision: 2635