freebsd-skq/lib/libdisk/open_ia64_disk.c
Marcel Moolenaar 727b08eb66 Correct an off-by-1 for GPART. The literal partition type (i.e.
the actual UUID) is prefixed by '!' to distinguish them from
well-known aliases.

MFC after: 3 days
2008-04-23 03:00:26 +00:00

291 lines
7.1 KiB
C

/*
* 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) {
status = uuid_s_ok;
if (!strcmp(r, "efi"))
uuid = _efi;
else if (!strcmp(r, "mbr"))
uuid = _mbr;
else if (!strcmp(r, "freebsd"))
uuid = _fbsd;
else if (!strcmp(r, "freebsd-swap"))
uuid = _swap;
else if (!strcmp(r, "freebsd-ufs"))
uuid = _ufs;
else {
if (!strcmp(type, "PART"))
uuid_from_string(r + 1, &uuid,
&status);
else
uuid_from_string(r, &uuid,
&status);
}
} 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 ||
strcmp(type, "PART") == 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);
}