Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Trunk/i386/util/fdisk/mbr.c

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

Archive Download this file

Revision: 2045