Chameleon

Chameleon Svn Source Tree

Root/branches/JrCs/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);
240fd = DISK_open(disk->name, O_RDONLY);
241MBR_read(disk, fd, offset, mbrd);
242DISK_close(fd);
243MBR_parse(disk, offset, reloff, mbrd);
244for (i = 0; i < NDOSPART; i++) {
245PRT_parse(disk, &mbrd->buf[MBR_PART_OFF +
246 MBR_PART_SIZE * i],
247 offset, reloff, &mbr->part[i], i);
248PRT_print(i, &mbr->part[i]);
249}
250MBR_free(mbrd);
251}
252
253
254static int
255parse_number(char *str, int default_val, int base) {
256if (str != NULL && *str != '\0') {
257 default_val = strtol(str, NULL, base);
258}
259return default_val;
260}
261
262static inline int
263null_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
278static int
279MBR_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])) {
330errx(1, "Either all CHS arguments must be specified, or none");
331return -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
360typedef 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 */
370mbr_t *
371MBR_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;
385prt_t *part;
386
387do {
388 str = fgets(line, 256, f);
389} while ((str != NULL) && (*str == '\0'));
390 if (str == NULL) {
391 break;
392 }
393
394if (mbr == NULL) {
395 mbr = MBR_alloc(prev_mbr);
396 if (head == NULL)
397head = mbr;
398}
399
400if (MBR_parse_one_spec(line, disk, mbr, lineno)) {
401 /* MBR_parse_one_spec printed the error message. */
402 return NULL;
403}
404part = &mbr->part[lineno];
405if ((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) {
412for (; 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
423void
424MBR_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,%d,%d,%d,%d,%d,%d\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
445mbr_t *
446MBR_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
457void
458MBR_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 */
471mbr_t *
472MBR_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)) {
494offset = part->bs;
495if (firstoff == 0) {
496 firstoff = offset;
497}
498 }
499 }
500 } while (offset > 0);
501 DISK_close(fd);
502
503 return head;
504}
505
506
507int
508MBR_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
525void
526MBR_print_all(mbr_t *mbr) {
527 while (mbr) {
528 MBR_print(mbr);
529 mbr = mbr->next;
530 }
531}
532
533void
534MBR_dump_all(mbr_t *mbr) {
535 while (mbr) {
536 MBR_dump(mbr);
537 mbr = mbr->next;
538 }
539}
540
541void
542MBR_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
554

Archive Download this file

Revision: 1466