diff options
Diffstat (limited to 'lib/libdisk/open_ia64_disk.c')
-rw-r--r-- | lib/libdisk/open_ia64_disk.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/lib/libdisk/open_ia64_disk.c b/lib/libdisk/open_ia64_disk.c new file mode 100644 index 0000000..8fc9f64 --- /dev/null +++ b/lib/libdisk/open_ia64_disk.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003 Marcel Moolenaar + * 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. + * + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/disklabel.h> +#include <sys/diskmbr.h> +#include <sys/gpt.h> +#include <sys/uuid.h> + +#include <fcntl.h> +#include <inttypes.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <uuid.h> + +#include "libdisk.h" + +static uuid_t _efi = GPT_ENT_TYPE_EFI; +static uuid_t _mbr = GPT_ENT_TYPE_MBR; +static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD; +static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS; + +static struct disk * +parse_disk(char *conftxt, const char *name) +{ + char devname[64]; + struct disk *disk; + struct dos_partition *part; + struct gpt_hdr *gpt; + char *buffer, *p, *q; + int fd, i; + + disk = (struct disk *)calloc(sizeof *disk, 1); + if (disk == NULL) + return (NULL); + + disk->name = strdup(name); + p = strsep(&conftxt, " "); /* media size */ + disk->media_size = strtoimax(p, &q, 0); + if (*q) + goto fail; + + p = strsep(&conftxt, " "); /* sector size */ + disk->sector_size = strtoul(p, &q, 0); + if (*q) + goto fail; + + if (disk->sector_size == 0) + disk->sector_size = 512; + + if (disk->media_size % disk->sector_size) + goto fail; + + /* + * We need to read the disk to get GPT specific information. + */ + + snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, name); + fd = open(devname, O_RDONLY); + if (fd == -1) + goto fail; + buffer = malloc(2 * disk->sector_size); + if (buffer == NULL) { + close (fd); + goto fail; + } + if (read(fd, buffer, 2 * disk->sector_size) == -1) { + free(buffer); + close(fd); + goto fail; + } + close(fd); + + gpt = (struct gpt_hdr *)(buffer + disk->sector_size); + if (memcmp(gpt->hdr_sig, GPT_HDR_SIG, sizeof(gpt->hdr_sig))) { + /* + * No GPT present. Check if the MBR is empty (if present) + * or is a PMBR before declaring this disk as empty. If + * the MBR isn't empty, bail out. Let's not risk nuking a + * disk. + */ + if (*(u_short *)(buffer + DOSMAGICOFFSET) == DOSMAGIC) { + for (i = 0; i < 4; i++) { + part = (struct dos_partition *) + (buffer + DOSPARTOFF + i * DOSPARTSIZE); + if (part->dp_typ != 0 && + part->dp_typ != DOSPTYP_PMBR) + break; + } + if (i < 4) { + free(buffer); + goto fail; + } + } + disk->gpt_size = 128; + disk->lba_start = (disk->gpt_size * sizeof(struct gpt_ent)) / + disk->sector_size + 2; + disk->lba_end = (disk->media_size / disk->sector_size) - + disk->lba_start; + } else { + disk->lba_start = gpt->hdr_lba_start; + disk->lba_end = gpt->hdr_lba_end; + disk->gpt_size = gpt->hdr_entries; + } + free(buffer); + Add_Chunk(disk, disk->lba_start, disk->lba_end - disk->lba_start + 1, + name, whole, 0, 0, "-"); + return (disk); + +fail: + free(disk->name); + free(disk); + return (NULL); +} + +struct disk * +Int_Open_Disk(const char *name, char *conftxt) +{ + struct chunk chunk; + uuid_t uuid; + struct disk *disk; + char *p, *q, *r, *s, *sd, *type; + u_long i; + uint32_t status; + + p = conftxt; + while (p != NULL && *p != 0) { + q = strsep(&p, " "); + if (strcmp(q, "0") == 0) { + q = strsep(&p, " "); + if (strcmp(q, "DISK") == 0) { + q = strsep(&p, " "); + if (strcmp(q, name) == 0) + break; + } + } + p = strchr(p, '\n'); + if (p != NULL && *p == '\n') + p++; + conftxt = p; + } + if (p == NULL || *p == 0) + return (NULL); + + conftxt = strchr(p, '\n'); + if (conftxt != NULL) + *conftxt++ = '\0'; + + disk = parse_disk(p, name); + if (disk == NULL) + return (NULL); + + while (conftxt != NULL && *conftxt != 0) { + p = conftxt; + conftxt = strchr(p, '\n'); + if (conftxt != NULL) + *conftxt++ = '\0'; + + sd = strsep(&p, " "); /* depth */ + if (strcmp(sd, "0") == 0) + break; + + type = strsep(&p, " "); /* type */ + chunk.name = strsep(&p, " "); /* name */ + q = strsep(&p, " "); /* length */ + i = strtoimax(q, &r, 0); + if (*r) + abort(); + chunk.end = i / disk->sector_size; + q = strsep(&p, " "); /* sector size */ + + for (;;) { + q = strsep(&p, " "); + if (q == NULL) + break; + r = strsep(&p, " "); + i = strtoimax(r, &s, 0); + if (*s) { + uuid_from_string(r, &uuid, &status); + if (status != uuid_s_ok) + abort(); + } else + status = uuid_s_invalid_string_uuid; + if (!strcmp(q, "o")) + chunk.offset = i / disk->sector_size; + else if (!strcmp(q, "i")) + chunk.flags = CHUNK_ITOF(i) | CHUNK_HAS_INDEX; + else if (!strcmp(q, "ty")) + chunk.subtype = i; + } + + if (strncmp(type, "MBR", 3) == 0) { + switch (chunk.subtype) { + case 0xa5: + chunk.type = freebsd; + break; + case 0x01: + case 0x04: + case 0x06: + case 0x0b: + case 0x0c: + case 0x0e: + chunk.type = fat; + break; + case 0xef: /* EFI */ + chunk.type = efi; + break; + default: + chunk.type = mbr; + break; + } + } else if (strcmp(type, "BSD") == 0) { + chunk.type = part; + } else if (strcmp(type, "GPT") == 0) { + chunk.subtype = 0; + if (status != uuid_s_ok) + abort(); + if (uuid_is_nil(&uuid, NULL)) + chunk.type = unused; + else if (uuid_equal(&uuid, &_efi, NULL)) + chunk.type = efi; + else if (uuid_equal(&uuid, &_mbr, NULL)) + chunk.type = mbr; + else if (uuid_equal(&uuid, &_fbsd, NULL)) { + chunk.type = freebsd; + chunk.subtype = 0xa5; + } else if (uuid_equal(&uuid, &_swap, NULL)) { + chunk.type = part; + chunk.subtype = FS_SWAP; + } else if (uuid_equal(&uuid, &_ufs, NULL)) { + chunk.type = part; + chunk.subtype = FS_BSDFFS; + } else + chunk.type = part; + } else + abort(); + + Add_Chunk(disk, chunk.offset, chunk.end, chunk.name, + chunk.type, chunk.subtype, chunk.flags, 0); + } + + return (disk); +} |