summaryrefslogtreecommitdiffstats
path: root/lib/libdisk/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libdisk/disk.c')
-rw-r--r--lib/libdisk/disk.c1153
1 files changed, 1153 insertions, 0 deletions
diff --git a/lib/libdisk/disk.c b/lib/libdisk/disk.c
new file mode 100644
index 0000000..ddb4db7
--- /dev/null
+++ b/lib/libdisk/disk.c
@@ -0,0 +1,1153 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/diskslice.h>
+#ifndef PC98
+#include <sys/diskmbr.h>
+#endif
+#include <paths.h>
+#include "libdisk.h"
+
+#define HAVE_GEOM
+#ifdef HAVE_GEOM
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#endif /*HAVE_GEOM*/
+
+#ifndef PC98
+#define DOSPTYP_EXTENDED 5
+#define DOSPTYP_ONTRACK 84
+#endif
+
+#ifdef DEBUG
+#define DPRINT(x) warn x
+#define DPRINTX(x) warnx x
+#else
+#define DPRINT(x)
+#define DPRINTX(x)
+#endif
+
+const char *chunk_n[] = {
+ "whole",
+ "unknown",
+ "fat",
+ "freebsd",
+ "extended",
+ "part",
+ "unused",
+ NULL
+};
+
+struct disk *
+Open_Disk(const char *name)
+{
+ return Int_Open_Disk(name, 0);
+}
+
+#ifndef PC98
+static u_int32_t
+Read_Int32(u_int32_t *p)
+{
+ u_int8_t *bp = (u_int8_t *)p;
+ return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24);
+}
+#endif
+
+#ifdef HAVE_GEOM
+/*
+ * XXX BEGIN HACK XXX
+ * Scan/parse the XML geom data to retrieve what we need to
+ * carry out the work of Int_Open_Disk. This is a total hack
+ * and should be replaced with a real XML parser.
+ */
+typedef enum {
+ XML_MESH,
+ XML_MESH_END,
+ XML_CLASS,
+ XML_CLASS_END,
+ XML_GEOM,
+ XML_GEOM_END,
+ XML_CONFIG,
+ XML_CONFIG_END,
+ XML_PROVIDER,
+ XML_PROVIDER_END,
+ XML_NAME,
+ XML_NAME_END,
+ XML_INDEX,
+ XML_INDEX_END,
+ XML_SECLENGTH,
+ XML_SECLENGTH_END,
+ XML_SECOFFSET,
+ XML_SECOFFSET_END,
+ XML_TYPE,
+ XML_TYPE_END,
+ XML_MEDIASIZE,
+ XML_MEDIASIZE_END,
+ XML_SECTORSIZE,
+ XML_SECTORSIZE_END,
+ XML_FWHEADS,
+ XML_FWHEADS_END,
+ XML_FWSECTORS,
+ XML_FWSECTORS_END,
+
+ XML_OTHER,
+ XML_OTHER_END
+} XMLToken;
+
+const struct {
+ XMLToken t;
+ const char* token;
+ const char* name;
+} xmltokens[] = {
+ { XML_MESH, "mesh", "XML_MESH" },
+ { XML_CLASS, "class", "XML_CLASS" },
+ { XML_GEOM, "geom", "XML_GEOM" },
+ { XML_CONFIG, "config", "XML_CONFIG" },
+ { XML_PROVIDER, "provider", "XML_PROVIDE" },
+ { XML_NAME, "name", "XML_NAME" },
+ { XML_INDEX, "index", "XML_INDEX" },
+ { XML_SECLENGTH, "seclength", "XML_SECLENGTH" },
+ { XML_SECOFFSET, "secoffset", "XML_SECOFFSET" },
+ { XML_TYPE, "type", "XML_TYPE" },
+ { XML_FWHEADS, "fwheads", "XML_FWHEADS" },
+ { XML_FWSECTORS, "fwsectors", "XML_FWSECTORS" },
+ { XML_MEDIASIZE, "mediasize", "XML_MEDIASIZE" },
+ { XML_SECTORSIZE, "sectorsize", "XML_SECTORSIZE" },
+ /* NB: this must be last */
+ { XML_OTHER, NULL, "XML_OTHER" },
+};
+#define N(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef DEBUG
+static const char*
+xmltokenname(XMLToken t)
+{
+ int i;
+
+ for (i = 0; i < N(xmltokens); i++) {
+ if (t == xmltokens[i].t)
+ return xmltokens[i].name;
+ if ((t-1) == xmltokens[i].t) {
+ static char tbuf[80];
+ snprintf(tbuf, sizeof (tbuf), "%s_END",
+ xmltokens[i].name);
+ return tbuf;
+ }
+ }
+ return "???";
+}
+#endif /*DEBUG*/
+
+/*
+ * Parse the next XML token delimited by <..>. If the token
+ * has a "builtin terminator" (<... />) then just skip it and
+ * go the next token.
+ */
+static int
+xmltoken(const char *start, const char **next, XMLToken *t)
+{
+ const char *cp = start;
+ const char *token;
+ int i;
+
+again:
+ while (*cp != '<') {
+ if (*cp == '\0') {
+ *next = cp;
+ DPRINTX(("xmltoken: EOD"));
+ return 0;
+ }
+ cp++;
+ }
+ token = ++cp;
+ for (; *cp && *cp != '>' && !isspace(*cp); cp++)
+ ;
+ if (*cp == '\0') {
+ *next = cp;
+ DPRINTX(("xmltoken: EOD"));
+ return 0;
+ }
+ *t = (*token == '/');
+ if (*t)
+ token++;
+ for (i = 0; xmltokens[i].token != NULL; i++)
+ if (strncasecmp(token, xmltokens[i].token, cp-token) == 0)
+ break;
+ *t += xmltokens[i].t;
+ /* now collect the remainder of the string */
+ for (; *cp != '>' && *cp != '\0'; cp++)
+ ;
+ if (*cp == '\0') {
+ *next = cp;
+ DPRINTX(("xmltoken: EOD"));
+ return 0;
+ }
+ if (cp > token && cp[-1] == '/') {
+ /* e.g. <geom ref="0xc1c8c100"/> */
+ start = cp+1;
+ goto again;
+ }
+ *next = cp+1;
+ DPRINTX(("xmltoken: %s \"%.*s\"", xmltokenname(*t), cp-token, token));
+ return 1;
+}
+
+/*
+ * Parse and discard XML up to the token terminator.
+ */
+static int
+discardxml(const char **next, XMLToken terminator)
+{
+ const char *xml = *next;
+ XMLToken t;
+
+ DPRINTX(("discard XML up to %s", xmltokenname(terminator)));
+ for (;;) {
+ if (xmltoken(xml, next, &t) == 0)
+ return EINVAL;
+ if (t == terminator)
+ break;
+ if ((t & 1) == 0) {
+ int error = discardxml(next, t+1);
+ if (error)
+ return error;
+ }
+ xml = *next;
+ }
+ return 0;
+}
+
+/*
+ * Parse XML from between a range of markers; e.g. <mesh> ... </mesh>.
+ * When the specified class name is located we descend looking for the
+ * geometry information given by diskname. Once inside there we process
+ * tags calling f back for each useful one. The arg is passed into f
+ * for use in storing the parsed data.
+ */
+static int
+parsexmlpair(
+ const char *xml,
+ const char **next,
+ const char *classname,
+ XMLToken terminator,
+ const char *diskname,
+ int (*f)(void *, XMLToken, u_int *, u_int64_t),
+ void *arg
+)
+{
+ const char *cp;
+ XMLToken t;
+ int error;
+ u_int ix = (u_int) -1;
+
+ DPRINTX(("parse XML up to %s", xmltokenname(terminator)));
+ do {
+ if (xmltoken(xml, next, &t) == 0) {
+ error = EINVAL;
+ break;
+ }
+ if (t == terminator) {
+ error = 0;
+ break;
+ }
+ if (t & 1) { /* </mumble> w/o matching <mumble> */
+ DPRINTX(("Unexpected token %s", xmltokenname(t)));
+ error = EINVAL;
+ break;
+ }
+ switch ((int) t) {
+ case XML_NAME:
+ for (cp = *next; *cp && *cp != '<'; cp++)
+ ;
+ if (*cp == '\0') {
+ DPRINTX(("parsexmlpair: EOD"));
+ error = EINVAL;
+ goto done;
+ }
+ DPRINTX(("parsexmlpair: \"%.*s\"", cp-*next, *next));
+ switch ((int) terminator) {
+ case XML_CLASS_END:
+ if (strncasecmp(*next, classname, cp-*next))
+ return discardxml(next, terminator);
+ break;
+ case XML_GEOM_END:
+ if (strncasecmp(*next, diskname, cp-*next))
+ return discardxml(next, terminator);
+ break;
+ }
+ break;
+ case XML_SECOFFSET:
+ case XML_SECLENGTH:
+ case XML_TYPE:
+ if (ix == (u_int) -1) {
+ DPRINTX(("parsexmlpair: slice data w/o "
+ "preceding index"));
+ error = EINVAL;
+ goto done;
+ }
+ /* fall thru... */
+ case XML_INDEX:
+ case XML_FWHEADS:
+ case XML_FWSECTORS:
+ case XML_MEDIASIZE:
+ case XML_SECTORSIZE:
+ if (terminator != XML_CONFIG_END &&
+ terminator != XML_PROVIDER_END) {
+ DPRINTX(("parsexmlpair: %s in unexpected "
+ "context: terminator %s",
+ xmltokenname(t),
+ xmltokenname(terminator)));
+ error = EINVAL;
+ goto done;
+ }
+ error = (*f)(arg, t, &ix, strtoull(*next, NULL, 10));
+ if (error)
+ goto done;
+ break;
+ }
+ error = parsexmlpair(*next, &xml, classname,
+ t+1, diskname, f, arg);
+ } while (error == 0);
+done:
+ return error;
+}
+
+/*
+ * XML parser. Just barely smart enough to handle the
+ * gibberish that geom passed back from the kernel.
+ */
+static int
+xmlparse(
+ const char *confxml,
+ const char *classname,
+ const char *diskname,
+ int (*f)(void *, XMLToken, u_int *, u_int64_t),
+ void *arg
+)
+{
+ const char *next;
+ XMLToken t;
+ int error;
+
+ next = confxml;
+ while (xmltoken(next, &next, &t) && t != XML_MESH)
+ ;
+ if (t == XML_MESH)
+ error = parsexmlpair(next, &next, classname, XML_MESH_END, diskname, f, arg);
+ else {
+ DPRINTX(("xmlparse: expecting mesh token, got %s",
+ xmltokenname(t)));
+ error = EINVAL;
+ }
+
+ return (error ? -1 : 0);
+}
+
+/*
+ * Callback to collect slice-related data.
+ */
+static int
+assignToSlice(void *arg, XMLToken t, u_int *slice, u_int64_t v)
+{
+ struct diskslices *ds = (struct diskslices *) arg;
+
+ switch ((int) t) {
+ case XML_INDEX:
+ *slice = BASE_SLICE + (u_int) v;
+ if (*slice >= MAX_SLICES) {
+ DPRINTX(("assignToSlice: invalid slice index %u > max %u",
+ *slice, MAX_SLICES));
+ return EINVAL;
+ }
+ if (*slice >= ds->dss_nslices)
+ ds->dss_nslices = (*slice)+1;
+ break;
+ case XML_SECOFFSET:
+ ds->dss_slices[*slice].ds_offset = (u_long) v;
+ break;
+ case XML_SECLENGTH:
+ ds->dss_slices[*slice].ds_size = (u_long) v;
+ break;
+ case XML_TYPE:
+ ds->dss_slices[*slice].ds_type = (int) v;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Callback to collect disk-related data.
+ */
+static int
+assignToDisk(void *arg, XMLToken t, u_int *slice, u_int64_t v)
+{
+ struct disklabel *dl = (struct disklabel *) arg;
+
+ switch ((int) t) {
+ case XML_FWHEADS:
+ dl->d_ntracks = (u_int32_t) v;
+ case XML_FWSECTORS:
+ dl->d_nsectors = (u_int32_t) v;
+ break;
+ case XML_MEDIASIZE:
+ /* store this temporarily; it gets moved later */
+ dl->d_secpercyl = v >> 32;
+ dl->d_secperunit = v & 0xffffffff;
+ break;
+ case XML_SECTORSIZE:
+ dl->d_secsize = (u_int32_t) v;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Callback to collect partition-related data.
+ */
+static int
+assignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v)
+{
+ struct disklabel *dl = (struct disklabel *) arg;
+
+ switch ((int) t) {
+ case XML_INDEX:
+ *part = (u_int) v;
+ if (*part >= MAXPARTITIONS) {
+ DPRINTX(("assignToPartition: invalid partition index %u > max %u",
+ *part, MAXPARTITIONS));
+ return EINVAL;
+ }
+ if (*part >= dl->d_npartitions)
+ dl->d_npartitions = (*part)+1;
+ break;
+ case XML_SECOFFSET:
+ dl->d_partitions[*part].p_offset = (u_int32_t) v;
+ break;
+ case XML_SECLENGTH:
+ dl->d_partitions[*part].p_size = (u_int32_t) v;
+ break;
+ case XML_TYPE:
+ dl->d_partitions[*part].p_fstype = (u_int8_t) v;
+ break;
+ }
+ return 0;
+}
+#undef N
+#endif /*HAVE_GEOM*/
+
+struct disk *
+Int_Open_Disk(const char *name, u_long size)
+{
+ int i;
+ int fd = -1;
+ struct diskslices ds;
+ struct disklabel dl;
+ char device[64];
+ struct disk *d;
+#ifdef PC98
+ unsigned char *p;
+#else
+ struct dos_partition *dp;
+ void *p;
+#endif
+ u_long offset = 0;
+#ifdef HAVE_GEOM
+ char *confxml = NULL;
+ size_t xmlsize;
+ u_int64_t mediasize;
+ int error;
+#else
+ u_long sector_size;
+ char *buf;
+#endif /*HAVE_GEOM*/
+
+ strlcpy(device, _PATH_DEV, sizeof(device));
+ strlcat(device, name, sizeof(device));
+
+ d = (struct disk *)malloc(sizeof *d);
+ if(!d) return NULL;
+ memset(d, 0, sizeof *d);
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0) {
+ DPRINT(("open(%s) failed", device));
+ goto bad;
+ }
+
+ memset(&dl, 0, sizeof dl);
+ memset(&ds, 0, sizeof ds);
+#ifdef HAVE_GEOM
+ /*
+ * Read and hack-parse the XML that provides the info we need.
+ */
+ error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0);
+ if (error) {
+ warn("kern.geom.confxml sysctl not available, giving up!");
+ goto bad;
+ }
+ confxml = (char *) malloc(xmlsize+1);
+ if (confxml == NULL) {
+ DPRINT(("cannot malloc memory for confxml"));
+ goto bad;
+ }
+ error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0);
+ if (error) {
+ DPRINT(("error reading kern.geom.confxml from the system"));
+ goto bad;
+ }
+ confxml[xmlsize] = '\0'; /* in case kernel bug is still there */
+
+ if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) {
+ DPRINTX(("Error parsing MBR geometry specification."));
+ goto bad;
+ }
+ if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) {
+ DPRINTX(("Error parsing DISK geometry specification."));
+ goto bad;
+ }
+ if (dl.d_nsectors == 0) {
+ DPRINTX(("No (zero) sector information in DISK geometry"));
+ goto bad;
+ }
+ if (dl.d_ntracks == 0) {
+ DPRINTX(("No (zero) track information in DISK geometry"));
+ goto bad;
+ }
+ if (dl.d_secsize == 0) {
+ DPRINTX(("No (zero) sector size information in DISK geometry"));
+ goto bad;
+ }
+ if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) {
+ DPRINTX(("No (zero) media size information in DISK geometry"));
+ goto bad;
+ }
+ /*
+ * Now patch up disklabel and diskslice.
+ */
+ d->sector_size = dl.d_secsize;
+ /* NB: media size was stashed in two parts while parsing */
+ mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit;
+ dl.d_secpercyl = 0;
+ dl.d_secperunit = 0;
+ size = mediasize / d->sector_size;
+ dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors);
+ /* "whole disk" slice maintained for compatibility */
+ ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size;
+#else /* !HAVE_GEOM */
+ if (ioctl(fd, DIOCGDINFO, &dl) < 0) {
+ DPRINT(("DIOCGDINFO(%s) failed", device));
+ goto bad;
+ }
+ i = ioctl(fd, DIOCGSLICEINFO, &ds);
+ if (i < 0) {
+ DPRINT(("DIOCGSLICEINFO(%s) failed", device));
+ goto bad;
+ }
+
+#ifdef DEBUG
+ for(i = 0; i < ds.dss_nslices; i++)
+ if(ds.dss_slices[i].ds_openmask)
+ printf(" open(%d)=0x%2x",
+ i, ds.dss_slices[i].ds_openmask);
+ printf("\n");
+#endif
+
+/* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
+#ifdef PC98
+ if (!size)
+ size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors;
+#else
+ if (!size)
+ size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
+#endif
+
+ /* determine media sector size */
+ if ((buf = malloc(MAX_SEC_SIZE)) == NULL)
+ return NULL;
+ for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) {
+ if (read(fd, buf, sector_size) == sector_size) {
+ d->sector_size = sector_size;
+ break;
+ }
+ }
+ free (buf);
+ if (sector_size > MAX_SEC_SIZE) {
+ DPRINT(("Int_Open_Disk: could not determine sector size, "
+ "calculated %u, max %u\n", sector_size, MAX_SEC_SIZE));
+ /* could not determine sector size */
+ goto bad;
+ }
+#endif /*HAVE_GEOM*/
+
+#ifdef PC98
+ p = (unsigned char*)read_block(fd, 1, d->sector_size);
+#else
+ p = read_block(fd, 0, d->sector_size);
+ dp = (struct dos_partition*)(p + DOSPARTOFF);
+ for (i = 0; i < NDOSPART; i++) {
+ if (Read_Int32(&dp->dp_start) >= size)
+ continue;
+ if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
+ continue;
+ if (!Read_Int32(&dp->dp_size))
+ continue;
+
+ if (dp->dp_typ == DOSPTYP_ONTRACK) {
+ d->flags |= DISK_ON_TRACK;
+ offset = 63;
+ }
+
+ }
+ free(p);
+#endif
+
+ d->bios_sect = dl.d_nsectors;
+ d->bios_hd = dl.d_ntracks;
+
+ d->name = strdup(name);
+
+
+ if (dl.d_ntracks && dl.d_nsectors)
+ d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
+
+#ifdef PC98
+ if (Add_Chunk(d, -offset, size, name, whole, 0, 0, "-"))
+#else
+ if (Add_Chunk(d, -offset, size, name, whole, 0, 0))
+#endif
+ DPRINT(("Failed to add 'whole' chunk"));
+
+#ifdef __i386__
+#ifdef PC98
+ /* XXX -- Quick Hack!
+ * Check MS-DOS MO
+ */
+ if ((*p == 0xf0 || *p == 0xf8) &&
+ (*(p+1) == 0xff) &&
+ (*(p+2) == 0xff)) {
+ Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
+ free(p);
+ goto pc98_mo_done;
+ }
+ free(p);
+#endif /* PC98 */
+ for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
+ char sname[20];
+ char pname[20];
+ chunk_e ce;
+ u_long flags=0;
+ int subtype=0;
+ int j;
+
+ if (! ds.dss_slices[i].ds_size)
+ continue;
+ ds.dss_slices[i].ds_offset -= offset;
+ snprintf(sname, sizeof(sname), "%ss%d", name, i - 1);
+#ifdef PC98
+ subtype = ds.dss_slices[i].ds_type |
+ ds.dss_slices[i].ds_subtype << 8;
+ switch (ds.dss_slices[i].ds_type & 0x7f) {
+ case 0x14:
+ ce = freebsd;
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ ce = fat;
+ break;
+#else /* IBM-PC */
+ subtype = ds.dss_slices[i].ds_type;
+ switch (ds.dss_slices[i].ds_type) {
+ case 0xa5:
+ ce = freebsd;
+ break;
+ case 0x1:
+ case 0x6:
+ case 0x4:
+ case 0xb:
+ case 0xc:
+ case 0xe:
+ ce = fat;
+ break;
+ case DOSPTYP_EXTENDED:
+ case 0xf:
+ ce = extended;
+ break;
+#endif
+ default:
+ ce = unknown;
+ break;
+ }
+#ifdef PC98
+ if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
+ ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
+ ds.dss_slices[i].ds_name))
+#else
+ if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
+ ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
+#endif
+ DPRINT(("failed to add chunk for slice %d", i - 1));
+
+#ifdef PC98
+ if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
+#else
+ if (ds.dss_slices[i].ds_type != 0xa5)
+#endif
+ continue;
+#ifdef HAVE_GEOM
+ if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) {
+ DPRINTX(("Error parsing MBR geometry specification."));
+ goto bad;
+ }
+#else
+ {
+ struct disklabel dl;
+ int k;
+
+ strlcpy(pname, _PATH_DEV, sizeof(pname));
+ strlcat(pname, sname, sizeof(pname));
+ j = open(pname, O_RDONLY);
+ if (j < 0) {
+ DPRINT(("open(%s)", pname));
+ continue;
+ }
+ k = ioctl(j, DIOCGDINFO, &dl);
+ if (k < 0) {
+ DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
+ close(j);
+ continue;
+ }
+ close(j);
+ }
+#endif /*HAVE_GEOM*/
+
+ for(j = 0; j <= dl.d_npartitions; j++) {
+ if (j == RAW_PART)
+ continue;
+ if (j == 3)
+ continue;
+ if (j == dl.d_npartitions) {
+ j = 3;
+ dl.d_npartitions = 0;
+ }
+ if (!dl.d_partitions[j].p_size)
+ continue;
+ if (dl.d_partitions[j].p_size +
+ dl.d_partitions[j].p_offset >
+ ds.dss_slices[i].ds_size)
+ continue;
+ snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a');
+ if (Add_Chunk(d,
+ dl.d_partitions[j].p_offset +
+ ds.dss_slices[i].ds_offset,
+ dl.d_partitions[j].p_size,
+ pname,part,
+ dl.d_partitions[j].p_fstype,
+#ifdef PC98
+ 0,
+ ds.dss_slices[i].ds_name) && j != 3)
+#else
+ 0) && j != 3)
+#endif
+ DPRINT((
+ "Failed to add chunk for partition %c [%lu,%lu]",
+ j + 'a', dl.d_partitions[j].p_offset,
+ dl.d_partitions[j].p_size));
+ }
+ }
+#endif /* __i386__ */
+#ifdef __alpha__
+ {
+ struct disklabel dl;
+ char pname[20];
+ int j,k;
+
+ strlcpy(pname, _PATH_DEV, sizeof(pname));
+ strlcat(pname, name, sizeof(pname));
+ j = open(pname, O_RDONLY);
+ if (j < 0) {
+ DPRINT(("open(%s)", pname));
+ goto nolabel;
+ }
+ k = ioctl(j, DIOCGDINFO, &dl);
+ if (k < 0) {
+ DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
+ close(j);
+ goto nolabel;
+ }
+ close(j);
+ All_FreeBSD(d, 1);
+
+ for(j = 0; j <= dl.d_npartitions; j++) {
+ if (j == RAW_PART)
+ continue;
+ if (j == 3)
+ continue;
+ if (j == dl.d_npartitions) {
+ j = 3;
+ dl.d_npartitions = 0;
+ }
+ if (!dl.d_partitions[j].p_size)
+ continue;
+ if (dl.d_partitions[j].p_size +
+ dl.d_partitions[j].p_offset >
+ ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
+ continue;
+ snprintf(pname, sizeof(pname), "%s%c", name, j + 'a');
+ if (Add_Chunk(d,
+ dl.d_partitions[j].p_offset,
+ dl.d_partitions[j].p_size,
+ pname,part,
+ dl.d_partitions[j].p_fstype,
+ 0) && j != 3)
+ DPRINT((
+ "Failed to add chunk for partition %c [%lu,%lu]",
+ j + 'a', dl.d_partitions[j].p_offset,
+ dl.d_partitions[j].p_size));
+ }
+ nolabel:;
+ }
+#endif /* __alpha__ */
+#ifdef PC98
+pc98_mo_done:
+#endif
+ close(fd);
+ Fixup_Names(d);
+ return d;
+bad:
+ if (confxml != NULL)
+ free(confxml);
+ if (fd >= 0)
+ close(fd);
+ return NULL;
+}
+
+void
+Debug_Disk(struct disk *d)
+{
+ printf("Debug_Disk(%s)", d->name);
+ printf(" flags=%lx", d->flags);
+#if 0
+ printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
+#endif
+ printf(" bios_geom=%lu/%lu/%lu = %lu\n",
+ d->bios_cyl, d->bios_hd, d->bios_sect,
+ d->bios_cyl * d->bios_hd * d->bios_sect);
+#if defined(PC98)
+ printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
+ d->boot1, d->boot2, d->bootipl, d->bootmenu);
+#elif defined(__i386__)
+ printf(" boot1=%p, boot2=%p, bootmgr=%p\n",
+ d->boot1, d->boot2, d->bootmgr);
+#elif defined(__alpha__)
+ printf(" boot1=%p, bootmgr=%p\n",
+ d->boot1, d->bootmgr);
+#endif
+ Debug_Chunk(d->chunks);
+}
+
+void
+Free_Disk(struct disk *d)
+{
+ if(d->chunks) Free_Chunk(d->chunks);
+ if(d->name) free(d->name);
+#ifdef PC98
+ if(d->bootipl) free(d->bootipl);
+ if(d->bootmenu) free(d->bootmenu);
+#else
+ if(d->bootmgr) free(d->bootmgr);
+#endif
+ if(d->boot1) free(d->boot1);
+#if defined(__i386__)
+ if(d->boot2) free(d->boot2);
+#endif
+ free(d);
+}
+
+struct disk *
+Clone_Disk(struct disk *d)
+{
+ struct disk *d2;
+
+ d2 = (struct disk*) malloc(sizeof *d2);
+ if(!d2) return NULL;
+ *d2 = *d;
+ d2->name = strdup(d2->name);
+ d2->chunks = Clone_Chunk(d2->chunks);
+#ifdef PC98
+ if(d2->bootipl) {
+ d2->bootipl = malloc(d2->bootipl_size);
+ memcpy(d2->bootipl, d->bootipl, d2->bootipl_size);
+ }
+ if(d2->bootmenu) {
+ d2->bootmenu = malloc(d2->bootmenu_size);
+ memcpy(d2->bootmenu, d->bootmenu, d2->bootmenu_size);
+ }
+#else
+ if(d2->bootmgr) {
+ d2->bootmgr = malloc(d2->bootmgr_size);
+ memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size);
+ }
+#endif
+#if defined(__i386__)
+ if(d2->boot1) {
+ d2->boot1 = malloc(512);
+ memcpy(d2->boot1, d->boot1, 512);
+ }
+ if(d2->boot2) {
+ d2->boot2 = malloc(512 * 15);
+ memcpy(d2->boot2, d->boot2, 512 * 15);
+ }
+#elif defined(__alpha__)
+ if(d2->boot1) {
+ d2->boot1 = malloc(512 * 15);
+ memcpy(d2->boot1, d->boot1, 512 * 15);
+ }
+#endif
+ return d2;
+}
+
+#if 0
+void
+Collapse_Disk(struct disk *d)
+{
+
+ while(Collapse_Chunk(d, d->chunks))
+ ;
+}
+#endif
+
+#ifdef PC98
+static char * device_list[] = {"wd", "aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
+#else
+static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
+#endif
+
+int qstrcmp(const void* a, const void* b) {
+
+ char *str1 = *(char**)a;
+ char *str2 = *(char**)b;
+ return strcmp(str1, str2);
+
+}
+
+char **
+Disk_Names()
+{
+ int i,j,disk_cnt;
+ char disk[25];
+ char diskname[25];
+ struct stat st;
+ struct diskslices ds;
+ int fd;
+ static char **disks;
+ int error;
+ size_t listsize;
+ char *disklist;
+
+ disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
+ if (disks == NULL)
+ return NULL;
+ memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
+ error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
+ if (!error) {
+ disklist = (char *)malloc(listsize+1);
+ if (disklist == NULL) {
+ free(disks);
+ return NULL;
+ }
+ memset(disklist, 0, listsize+1);
+ error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
+ if (error) {
+ free(disklist);
+ free(disks);
+ return NULL;
+ }
+ for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
+ disks[disk_cnt] = strsep(&disklist, " ");
+ if (disks[disk_cnt] == NULL)
+ break;
+ }
+ } else {
+ warn("kern.disks sysctl not available");
+ disk_cnt = 0;
+ for (j = 0; device_list[j]; j++) {
+ if(disk_cnt >= MAX_NO_DISKS)
+ break;
+ for (i = 0; i < MAX_NO_DISKS; i++) {
+ snprintf(diskname, sizeof(diskname), "%s%d",
+ device_list[j], i);
+ snprintf(disk, sizeof(disk), _PATH_DEV"%s", diskname);
+ if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
+ continue;
+ if ((fd = open(disk, O_RDWR)) == -1)
+ continue;
+ if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
+ DPRINT(("DIOCGSLICEINFO %s", disk));
+ close(fd);
+ continue;
+ }
+ close(fd);
+ disks[disk_cnt++] = strdup(diskname);
+ if(disk_cnt >= MAX_NO_DISKS)
+ break;
+ }
+ }
+ }
+ qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
+
+ return disks;
+}
+
+#ifdef PC98
+void
+Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
+ const u_char *bootmenu, const size_t bootmenu_size)
+#else
+void
+Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
+#endif
+{
+#ifdef PC98
+ if (bootipl_size % d->sector_size != 0)
+ return;
+ if (d->bootipl)
+ free(d->bootipl);
+ if (!bootipl) {
+ d->bootipl = NULL;
+ } else {
+ d->bootipl_size = bootipl_size;
+ d->bootipl = malloc(bootipl_size);
+ if(!d->bootipl) return;
+ memcpy(d->bootipl, bootipl, bootipl_size);
+ }
+
+ if (bootmenu_size % d->sector_size != 0)
+ return;
+ if (d->bootmenu)
+ free(d->bootmenu);
+ if (!bootmenu) {
+ d->bootmenu = NULL;
+ } else {
+ d->bootmenu_size = bootmenu_size;
+ d->bootmenu = malloc(bootmenu_size);
+ if(!d->bootmenu) return;
+ memcpy(d->bootmenu, bootmenu, bootmenu_size);
+ }
+#else
+ if (s % d->sector_size != 0)
+ return;
+ if (d->bootmgr)
+ free(d->bootmgr);
+ if (!b) {
+ d->bootmgr = NULL;
+ } else {
+ d->bootmgr_size = s;
+ d->bootmgr = malloc(s);
+ if(!d->bootmgr) return;
+ memcpy(d->bootmgr, b, s);
+ }
+#endif
+}
+
+int
+Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
+{
+#if defined(__i386__)
+ if (d->boot1) free(d->boot1);
+ d->boot1 = malloc(512);
+ if(!d->boot1) return -1;
+ memcpy(d->boot1, b1, 512);
+ if (d->boot2) free(d->boot2);
+ d->boot2 = malloc(15 * 512);
+ if(!d->boot2) return -1;
+ memcpy(d->boot2, b2, 15 * 512);
+#elif defined(__alpha__)
+ if (d->boot1) free(d->boot1);
+ d->boot1 = malloc(15 * 512);
+ if(!d->boot1) return -1;
+ memcpy(d->boot1, b1, 15 * 512);
+#endif
+ return 0;
+}
+
+const char *
+slice_type_name( int type, int subtype )
+{
+ switch (type) {
+ case 0: return "whole";
+#ifndef PC98
+ case 1: switch (subtype) {
+ case 1: return "fat (12-bit)";
+ case 2: return "XENIX /";
+ case 3: return "XENIX /usr";
+ case 4: return "fat (16-bit,<=32Mb)";
+ case 5: return "extended DOS";
+ case 6: return "fat (16-bit,>32Mb)";
+ case 7: return "NTFS/HPFS/QNX";
+ case 8: return "AIX bootable";
+ case 9: return "AIX data";
+ case 10: return "OS/2 bootmgr";
+ case 11: return "fat (32-bit)";
+ case 12: return "fat (32-bit,LBA)";
+ case 14: return "fat (16-bit,>32Mb,LBA)";
+ case 15: return "extended DOS, LBA";
+ case 18: return "Compaq Diagnostic";
+ case 84: return "OnTrack diskmgr";
+ case 100: return "Netware 2.x";
+ case 101: return "Netware 3.x";
+ case 115: return "SCO UnixWare";
+ case 128: return "Minix 1.1";
+ case 129: return "Minix 1.5";
+ case 130: return "linux_swap";
+ case 131: return "ext2fs";
+ case 166: return "OpenBSD FFS"; /* 0xA6 */
+ case 169: return "NetBSD FFS"; /* 0xA9 */
+ case 182: return "OpenBSD"; /* dedicated */
+ case 183: return "bsd/os";
+ case 184: return "bsd/os swap";
+ case 238: return "EFI GPT";
+ case 239: return "EFI Sys. Part.";
+ default: return "unknown";
+ }
+#endif
+ case 2: return "fat";
+ case 3: switch (subtype) {
+#ifdef PC98
+ case 0xc494: return "freebsd";
+#else
+ case 165: return "freebsd";
+#endif
+ default: return "unknown";
+ }
+#ifndef PC98
+ case 4: return "extended";
+ case 5: return "part";
+ case 6: return "unused";
+#endif
+ default: return "unknown";
+ }
+}
OpenPOWER on IntegriCloud