diff options
author | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
---|---|---|
committer | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /diskdev_cmds/fdisk.tproj/mbr.c | |
download | apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip |
Import macOS userland
adv_cmds-176
basic_cmds-55
bootstrap_cmds-116.100.1
developer_cmds-66
diskdev_cmds-667.40.1
doc_cmds-53.60.1
file_cmds-321.40.3
mail_cmds-35
misc_cmds-34
network_cmds-606.40.1
patch_cmds-17
remote_cmds-63
shell_cmds-216.60.1
system_cmds-880.60.2
text_cmds-106
Diffstat (limited to 'diskdev_cmds/fdisk.tproj/mbr.c')
-rw-r--r-- | diskdev_cmds/fdisk.tproj/mbr.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/diskdev_cmds/fdisk.tproj/mbr.c b/diskdev_cmds/fdisk.tproj/mbr.c new file mode 100644 index 0000000..90c8809 --- /dev/null +++ b/diskdev_cmds/fdisk.tproj/mbr.c @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2002, 2005 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Copyright (c) 1997 Tobias Weingartner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Tobias Weingartner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <err.h> +#include <util.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <memory.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#if 0 +#include <sys/dkio.h> +#endif +#include <machine/param.h> +#include "disk.h" +#include "misc.h" +#include "mbr.h" +#include "part.h" + + +void +MBR_init(disk, mbr) + disk_t *disk; + mbr_t *mbr; +{ + /* Fix up given mbr for this disk */ + mbr->part[0].flag = 0; + mbr->part[1].flag = 0; + mbr->part[2].flag = 0; +#if !defined(DOSPTYP_OPENBSD) + mbr->part[3].flag = 0; + mbr->signature = MBR_SIGNATURE; +#else + + mbr->part[3].flag = DOSACTIVE; + mbr->signature = DOSMBR_SIGNATURE; + + /* Use whole disk, save for first head, on first cyl. */ + mbr->part[3].id = DOSPTYP_OPENBSD; + mbr->part[3].scyl = 0; + mbr->part[3].shead = 1; + mbr->part[3].ssect = 1; + + /* Go right to the end */ + mbr->part[3].ecyl = disk->real->cylinders - 1; + mbr->part[3].ehead = disk->real->heads - 1; + mbr->part[3].esect = disk->real->sectors; + + /* Fix up start/length fields */ + PRT_fix_BN(disk, &mbr->part[3], 3); + +#if defined(__powerpc__) || defined(__mips__) + /* Now fix up for the MS-DOS boot partition on PowerPC. */ + mbr->part[0].flag = DOSACTIVE; /* Boot from dos part */ + mbr->part[3].flag = 0; + mbr->part[3].ns += mbr->part[3].bs; + mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns; + mbr->part[3].ns -= mbr->part[3].bs; + PRT_fix_CHS(disk, &mbr->part[3], 3); + if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) { + /* align the partition on a cylinder boundary */ + mbr->part[3].shead = 0; + mbr->part[3].ssect = 1; + mbr->part[3].scyl += 1; + } + /* Fix up start/length fields */ + PRT_fix_BN(disk, &mbr->part[3], 3); +#endif +#endif +} + +void +MBR_parse(disk, offset, reloff, mbr) + disk_t *disk; + off_t offset; + off_t reloff; + mbr_t *mbr; +{ + int i; + unsigned char *mbr_buf = mbr->buf; + + memcpy(mbr->code, mbr_buf, MBR_CODE_SIZE); + mbr->offset = offset; + mbr->reloffset = reloff; + mbr->signature = getshort(&mbr_buf[MBR_SIG_OFF]); + + for (i = 0; i < NDOSPART; i++) + PRT_parse(disk, &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i], + offset, reloff, &mbr->part[i], i); +} + +void +MBR_make(mbr) + mbr_t *mbr; +{ + int i; + unsigned char *mbr_buf = mbr->buf; + + memcpy(mbr_buf, mbr->code, MBR_CODE_SIZE); + putshort(&mbr_buf[MBR_SIG_OFF], mbr->signature); + + for (i = 0; i < NDOSPART; i++) + PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset, + &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i]); +} + +void +MBR_print(mbr) + mbr_t *mbr; +{ + int i; + + /* Header */ + printf("Signature: 0x%X\n", + (int)mbr->signature); + PRT_print(0, NULL); + + /* Entries */ + for (i = 0; i < NDOSPART; i++) + PRT_print(i, &mbr->part[i]); +} + +int +MBR_read(disk, fd, where, mbr) + disk_t *disk; + int fd; + off_t where; + mbr_t *mbr; +{ + off_t off; + int len; + int size; + unsigned char *buf = mbr->buf; + + size = disk->real->sector_size; + where *= size; + off = lseek(fd, where, SEEK_SET); + if (off != where) + return (off); + len = read(fd, buf, size); + if (len != size) + return (len); + return (0); +} + +int +MBR_write(disk, fd, mbr) + disk_t *disk; + int fd; + mbr_t *mbr; +{ + off_t off; + int len; + int size; + unsigned char *buf = mbr->buf; + off_t where; + + size = disk->real->sector_size; + where = mbr->offset * size; + off = lseek(fd, where, SEEK_SET); + if (off != where) + return (off); + len = write(fd, buf, size); + if (len != size) + return (len); +#if defined(DIOCRLDINFO) + (void) ioctl(fd, DIOCRLDINFO, 0); +#endif + return (0); +} + +void +MBR_pcopy(disk, mbr) + disk_t *disk; + mbr_t *mbr; +{ + /* + * Copy partition table from the disk indicated + * to the supplied mbr structure + */ + + int i, fd, offset = 0, reloff = 0; + mbr_t *mbrd; + + mbrd = MBR_alloc(NULL); + fd = DISK_open(disk->name, O_RDONLY); + MBR_read(disk, fd, offset, mbrd); + DISK_close(fd); + MBR_parse(disk, offset, reloff, mbrd); + for (i = 0; i < NDOSPART; i++) { + PRT_parse(disk, &mbrd->buf[MBR_PART_OFF + + MBR_PART_SIZE * i], + offset, reloff, &mbr->part[i], i); + PRT_print(i, &mbr->part[i]); + } + MBR_free(mbrd); +} + + +static int +parse_number(char *str, int default_val, int base) { + if (str != NULL && *str != '\0') { + default_val = strtol(str, NULL, base); + } + return default_val; +} + +static inline int +null_arg(char *arg) { + if (arg == NULL || *arg == 0) + return 1; + else + return 0; +} + +/* Parse a partition spec into a partition structure. + * Spec is of the form: + * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>] + * We require passing in the disk and mbr so we can + * set reasonable defaults for values, e.g. "the whole disk" + * or "starting after the last partition." + */ +#define N_ARGS 10 +static int +MBR_parse_one_spec(char *line, disk_t *disk, mbr_t *mbr, int pn) +{ + int i; + char *args[N_ARGS]; + prt_t *part = &mbr->part[pn]; + int next_start, next_size; + + /* There are up to 10 arguments. */ + for (i=0; i<N_ARGS; i++) { + char *arg; + while (isspace(*line)) + line++; + arg = strsep(&line, ",\n"); + if (arg == NULL || line == NULL) { + break; + } + args[i] = arg; + } + for (; i<N_ARGS; i++) { + args[i] = NULL; + } + /* Set reasonable defaults. */ + if (pn == 0) { + next_start = 0; + } else { + next_start = mbr->part[pn-1].bs + mbr->part[pn-1].ns; + } + next_size = disk->real->size; + for(i=0; i<pn; i++) { + next_size -= mbr->part[i].ns; + } + + part->id = parse_number(args[2], 0xA8, 16); + if (!null_arg(args[3]) && *args[3] == '*') { + part->flag = 0x80; + } else { + part->flag = 0; + } + /* If you specify the start or end sector, + you have to give both. */ + if ((null_arg(args[0]) && !null_arg(args[1])) || + (!null_arg(args[0]) && null_arg(args[1]))) { + errx(1, "You must specify both start and size, or neither"); + return -1; + } + + /* If you specify one of the CHS args, + you have to give them all. */ + if (!null_arg(args[4])) { + for (i=5; i<10; i++) { + if (null_arg(args[i])) { + errx(1, "Either all CHS arguments must be specified, or none"); + return -1; + } + } + + part->scyl = parse_number(args[4], 0, 10); + part->shead = parse_number(args[5], 0, 10); + part->ssect = parse_number(args[6], 0, 10); + part->scyl = parse_number(args[7], 0, 10); + part->shead = parse_number(args[8], 0, 10); + part->ssect = parse_number(args[9], 0, 10); + if (null_arg(args[0])) { + PRT_fix_BN(disk, part, pn); + } + } else { + /* See if they gave no CHS and no start/end */ + if (null_arg(args[0])) { + errx(1, "You must specify either start sector and size or CHS"); + return -1; + } + } + if (!null_arg(args[0])) { + part->bs = parse_number(args[0], next_start, 10); + part->ns = parse_number(args[1], next_size, 10); + PRT_fix_CHS(disk, part, pn); + } + return 0; +} + + +typedef struct _mbr_chain { + mbr_t mbr; + struct _mbr_chain *next; +} mbr_chain_t; + +/* Parse some number of MBR spec lines. + * Spec is of the form: + * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>] + * + */ +mbr_t * +MBR_parse_spec(FILE *f, disk_t *disk) +{ + int lineno; + int offset, firstoffset; + mbr_t *mbr, *head, *prev_mbr; + + head = mbr = prev_mbr = NULL; + firstoffset = 0; + do { + + offset = 0; + for (lineno = 0; lineno < NDOSPART && !feof(f); lineno++) { + char line[256]; + char *str; + prt_t *part; + + do { + str = fgets(line, 256, f); + } while ((str != NULL) && (*str == '\0')); + if (str == NULL) { + break; + } + + if (mbr == NULL) { + mbr = MBR_alloc(prev_mbr); + if (head == NULL) + head = mbr; + } + + if (MBR_parse_one_spec(line, disk, mbr, lineno)) { + /* MBR_parse_one_spec printed the error message. */ + return NULL; + } + part = &mbr->part[lineno]; + if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) { + offset = part->bs; + if (firstoffset == 0) firstoffset = offset; + } + } + /* If fewer lines than partitions, zero out the rest of the partitions */ + if (mbr != NULL) { + for (; lineno < NDOSPART; lineno++) { + bzero(&mbr->part[lineno], sizeof(prt_t)); + } + } + prev_mbr = mbr; + mbr = NULL; + } while (offset >= 0 && !feof(f)); + + return head; +} + +void +MBR_dump(mbr_t *mbr) +{ + int i; + prt_t *part; + + for (i=0; i<NDOSPART; i++) { + part = &mbr->part[i]; + printf("%d,%d,0x%02X,%c,%u,%u,%u,%u,%u,%u\n", + part->bs, + part->ns, + part->id, + (part->flag == 0x80) ? '*' : '-', + part->scyl, + part->shead, + part->ssect, + part->ecyl, + part->ehead, + part->esect); + } +} + +mbr_t * +MBR_alloc(mbr_t *parent) +{ + mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t)); + bzero(mbr, sizeof(mbr_t)); + if (parent) { + parent->next = mbr; + } + mbr->signature = MBR_SIGNATURE; + return mbr; +} + +void +MBR_free(mbr_t *mbr) +{ + mbr_t *tmp; + while (mbr) { + tmp = mbr->next; + free(mbr); + mbr = tmp; + } +} + +/* Read and parse all the partition tables on the disk, + * including extended partitions. + */ +mbr_t * +MBR_read_all(disk_t *disk) +{ + mbr_t *mbr = NULL, *head = NULL; + int i, fd, offset, firstoff; + + fd = DISK_open(disk->name, O_RDONLY); + firstoff = offset = 0; + do { + mbr = MBR_alloc(mbr); + if (head == NULL) { + head = mbr; + } + MBR_read(disk, fd, offset, mbr); + MBR_parse(disk, offset, firstoff, mbr); + if (mbr->signature != MBR_SIGNATURE) { + /* The MBR signature is invalid. */ + break; + } + offset = 0; + for (i=0; i<NDOSPART; i++) { + prt_t *part = &mbr->part[i]; + if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) { + offset = part->bs; + if (firstoff == 0) { + firstoff = offset; + } + } + } + } while (offset > 0); + DISK_close(fd); + + return head; +} + + +int +MBR_write_all(disk_t *disk, mbr_t *mbr) +{ + int result = 0; + int fd; + + fd = DISK_open(disk->name, O_RDWR); + while (mbr) { + MBR_make(mbr); + result = MBR_write(disk, fd, mbr); + if (result) + break; + mbr = mbr->next; + } + DISK_close(fd); + return result; +} + +void +MBR_print_all(mbr_t *mbr) { + while (mbr) { + MBR_print(mbr); + mbr = mbr->next; + } +} + +void +MBR_dump_all(mbr_t *mbr) { + while (mbr) { + MBR_dump(mbr); + mbr = mbr->next; + } +} + +void +MBR_clear(mbr_t *mbr) { + int i; + if (mbr->next) { + MBR_free(mbr->next); + mbr->next = NULL; + } + for (i=0; i<4; i++) { + bzero(&mbr->part[i], sizeof(mbr->part[i])); + } + bzero(&mbr->buf, sizeof(mbr->buf)); +} + |