[RFC] Patch to add GEOM support to libdisk and sysinstall
Craig Rodrigues
rodrigc at crodrigues.org
Thu Sep 15 09:59:41 PDT 2005
Hi,
I have been working on a patch to add GEOM support
to libdisk and sysinstall. These
fixes allow you to label a disk which you
currently have a partition mounted on.
This is one of the "Desired features" for
the 6.0-RELEASE. I copied a lot of code
from boot0cfg and bsdlabel into libdisk.
My code is available in Perforce on the
"rodrigc_libdisk_geom" branch.
Also attached are patches against CURRENT CVS.
Note: my code is not in CVS yet.
Since I am new to GEOM and disk partitioning
issues, I would appreciate any feedback.
--
Craig Rodrigues
rodrigc at crodrigues.org
-------------- next part --------------
Index: Makefile
===================================================================
RCS file: /home/ncvs/src/lib/libdisk/Makefile,v
retrieving revision 1.44
diff -u -u -r1.44 Makefile
--- Makefile 21 Dec 2004 09:33:46 -0000 1.44
+++ Makefile 15 Sep 2005 16:52:55 -0000
@@ -1,5 +1,7 @@
# $FreeBSD: src/lib/libdisk/Makefile,v 1.44 2004/12/21 09:33:46 ru Exp $
+.PATH: ${.CURDIR}/../../sys/geom
+
.if ${MACHINE_ARCH} == "ia64"
_open_disk= open_ia64_disk.c
.else
@@ -9,12 +11,13 @@
LIB= disk
SRCS= blocks.c ${_change} chunk.c create_chunk.c disk.c ${_open_disk} \
- rules.c write_disk.c write_${MACHINE}_disk.c
+ rules.c write_disk.c write_${MACHINE}_disk.c geom_bsd_enc.c \
+ bsdlabel.c boot0cfg.c
INCS= libdisk.h
WARNS?= 2
-CFLAGS+= -I${.CURDIR}/../../sys/geom
+CFLAGS+= -I${.CURDIR}/../../sys/geom -I${.CURDIR}/../../sbin/bsdlabel
.if ${MACHINE} == "pc98"
CFLAGS+= -DPC98
@@ -29,7 +32,7 @@
.include <bsd.lib.mk>
tst01: tst01.o libdisk.a
- cc ${CFLAGS} -static tst01.o -o tst01 libdisk.a
+ cc ${CFLAGS} -static tst01.o -o tst01 libdisk.a -lgeom
ad0: all install tst01
./tst01 ad0
Index: boot0cfg.c
===================================================================
RCS file: boot0cfg.c
diff -N boot0cfg.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ boot0cfg.c 15 Sep 2005 16:52:55 -0000
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1999 Robert Nordier
+ * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS
+ * 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.
+ */
+#ifdef _STDIO_H_
+#error "BLAH"
+#endif
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <libgeom.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "boot0cfg.h"
+
+/*
+ * Read in the MBR of the disk. If it is boot0, then use the version to
+ * read in all of it if necessary. Use pointers to return a malloc'd
+ * buffer containing the MBR and then return its size.
+ */
+int
+read_mbr(const char *disk, u_int8_t **mbr, int check_version)
+{
+ u_int8_t buf[MBRSIZE];
+ int mbr_size, fd;
+ ssize_t n;
+
+ if ((fd = open(disk, O_RDONLY)) == -1)
+ err(1, "open %s", disk);
+ if ((n = read(fd, buf, MBRSIZE)) == -1) {
+ warn("read %s", disk);
+ return -1;
+ }
+ if (n != MBRSIZE) {
+ warnx("%s: short read", disk);
+ return -1;
+ }
+ if (cv2(buf + OFF_MAGIC) != 0xaa55)
+ warnx("%s: bad magic", disk);
+
+ if (!boot0bs(buf)) {
+ if (check_version)
+ warnx("%s: unknown or incompatible boot code", disk);
+ } else if (boot0version(buf) == 0x101) {
+ mbr_size = 1024;
+ if ((*mbr = malloc(mbr_size)) == NULL)
+ errx(1, "%s: unable to allocate read buffer", disk);
+ if (lseek(fd, 0, SEEK_SET) == -1 ||
+ (n = read(fd, *mbr, mbr_size)) == -1)
+ err(1, "%s", disk);
+ if (n != mbr_size)
+ errx(1, "%s: short read", disk);
+ return (mbr_size);
+ }
+ *mbr = malloc(sizeof(buf));
+ memcpy(*mbr, buf, sizeof(buf));
+
+ return sizeof(buf);
+}
+
+extern FILE *libdisk_debug;
+/*
+ * Write out the mbr to the specified file.
+ */
+int
+write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size)
+{
+ int fd, p;
+ ssize_t n;
+ char *s;
+ const char *q;
+ struct gctl_req *grq;
+
+ fd = open(fname, O_WRONLY | flags, 0666);
+ if (fd != -1) {
+ n = write(fd, mbr, mbr_size);
+ close(fd);
+ if (n != mbr_size) {
+ warn("%s:%d %s: short write", __FILE__, __LINE__, fname);
+ return (-1);
+ }
+ return (0);
+ }
+
+ if (flags != 0) {
+ warn("%s:%d %s", __FILE__, __LINE__, fname);
+ return (-1);
+ }
+ grq = gctl_get_handle();
+ gctl_ro_param(grq, "verb", -1, "write MBR");
+ gctl_ro_param(grq, "class", -1, "MBR");
+ q = strrchr(fname, '/');
+ if (q == NULL)
+ q = fname;
+ else
+ q++;
+ gctl_ro_param(grq, "geom", -1, q);
+ gctl_ro_param(grq, "data", mbr_size, mbr);
+ q = gctl_issue(grq);
+ gctl_dump(grq, libdisk_debug);
+ if (q == NULL) {
+ warnx("%s:%d Succeeded", __FILE__, __LINE__);
+ gctl_free(grq);
+ return (0);
+ }
+
+ warnx("FAILED: %s:%d %s: %s", __FILE__, __LINE__, fname, q);
+ gctl_free(grq);
+
+#ifdef DIOCSMBR
+ for (p = 1; p < 5; p++) {
+ asprintf(&s, "%ss%d", fname, p);
+ fd = open(s, O_RDONLY);
+ if (fd < 0) {
+ free(s);
+ continue;
+ }
+ n = ioctl(fd, DIOCSMBR, (mbr));
+ if (n != 0) {
+ warn("%s: ioctl DIOCSMBR", fname);
+ return (-1);
+ }
+ close(fd);
+ free(s);
+ return (0);
+ }
+#endif
+ warn("write_mbr: %s", fname);
+ return (-1);
+}
+
+/*
+ * Return the boot0 version with the minor revision in the low byte, and
+ * the major revision in the next higher byte.
+ */
+int
+boot0version(const u_int8_t *bs)
+{
+ static u_int8_t idold[] = {0xfe, 0x45, 0xf2, 0xe9, 0x00, 0x8a};
+
+ /* Check for old version, and return 0x100 if found. */
+ if (memcmp(bs + 0x1c, idold, sizeof(idold)) == 0)
+ return 0x100;
+
+ /* We have a newer boot0, so extract the version number and return it. */
+ return *(const int *)(bs + OFF_VERSION) & 0xffff;
+}
+
+/*
+ * Decide if we have valid boot0 boot code by looking for
+ * characteristic byte sequences at fixed offsets.
+ */
+int
+boot0bs(const u_int8_t *bs)
+{
+ static u_int8_t id0[] = {0xfc, 0x31, 0xc0, 0x8e, 0xc0, 0x8e, 0xd8,
+ 0x8e, 0xd0, 0xbc, 0x00, 0x7c };
+ static u_int8_t id1[] = {'D', 'r', 'i', 'v', 'e', ' '};
+ static struct {
+ unsigned off;
+ unsigned len;
+ u_int8_t *key;
+ } ident[2] = {
+ {0x0, sizeof(id0), id0},
+ {0x1b2, sizeof(id1), id1}
+ };
+ unsigned int i;
+
+ for (i = 0; i < sizeof(ident) / sizeof(ident[0]); i++)
+ if (memcmp(bs + ident[i].off, ident[i].key, ident[i].len))
+ return 0;
+ return 1;
+}
Index: boot0cfg.h
===================================================================
RCS file: boot0cfg.h
diff -N boot0cfg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ boot0cfg.h 15 Sep 2005 16:52:55 -0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1999 Robert Nordier
+ * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BOOT0CFG_H_
+#define _BOOT0CFG_H_
+
+#define MBRSIZE 512 /* master boot record size */
+
+#define OFF_VERSION 0x1b0 /* offset: version number */
+#define OFF_OPT 0x1b9 /* offset: default boot option */
+#define OFF_DRIVE 0x1ba /* offset: setdrv drive */
+#define OFF_FLAGS 0x1bb /* offset: option flags */
+#define OFF_TICKS 0x1bc /* offset: clock ticks */
+#define OFF_PTBL 0x1be /* offset: partition table */
+#define OFF_MAGIC 0x1fe /* offset: magic number */
+
+#define cv2(p) ((p)[0] | (p)[1] << 010)
+
+#define mk2(p, x) \
+ (p)[0] = (u_int8_t)(x), \
+ (p)[1] = (u_int8_t)((x) >> 010)
+
+__BEGIN_DECLS
+int read_mbr(const char *, u_int8_t **, int);
+int write_mbr(const char *, int, u_int8_t *, int);
+int boot0version(const u_int8_t *);
+int boot0bs(const u_int8_t *);
+__END_DECLS
+
+#endif /* ! _BOOT0CFG_H_ */
Index: bsdlabel.c
===================================================================
RCS file: bsdlabel.c
diff -N bsdlabel.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ bsdlabel.c 15 Sep 2005 16:52:55 -0000
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 1994, 1995 Gordon W. Ross
+ * Copyright (c) 1994 Theo de Raadt
+ * All rights reserved.
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Symmetric Computer Systems.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * This product includes software developed by Theo de Raadt.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94";
+/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sbin/bsdlabel/bsdlabel.c,v 1.111 2005/08/14 22:46:50 iedowse Exp $");
+
+#include <sys/param.h>
+#include <stdint.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/disk.h>
+#define DKTYPENAMES
+#define FSTYPENAMES
+#include <sys/disklabel.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgeom.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include "bsdlabel.h"
+#include "pathnames.h"
+
+static char *skip(char *);
+static char *word(char *);
+static int editit(void);
+static int getasciilabel(const char *, FILE *, struct disklabel *, int, int);
+static int getasciipartspec(char *, struct disklabel *, int, int);
+static struct disklabel *getvirginlabel(const char *specname, int);
+
+#define DEFEDITOR _PATH_VI
+
+static char tmpfil[] = PATH_TMPFILE;
+
+//static struct disklabel lab;
+static off_t mediasize;
+static u_int secsize;
+//static char blank[] = "";
+//static char unknown[] = "unknown";
+
+#define MAX_PART ('z')
+#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
+static char part_size_type[MAX_NUM_PARTS];
+static char part_offset_type[MAX_NUM_PARTS];
+static int part_set[MAX_NUM_PARTS];
+
+//static int allfields; /* present all fields in edit */
+//static char const *xxboot; /* primary boot */
+
+static off_t mbroffset;
+#ifndef LABELSECTOR
+#define LABELSECTOR -1
+#endif
+#ifndef LABELOFFSET
+#define LABELOFFSET -1
+#endif
+static int labelsoffset = LABELSECTOR;
+static int labeloffset = LABELOFFSET;
+static int bbsize = BBSIZE;
+static int alphacksum =
+#if defined(__alpha__)
+ 1;
+#else
+ 0;
+#endif
+
+enum {
+ UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
+} op = UNSPEC;
+
+
+void
+fixlabel(struct disklabel *lp)
+{
+ struct partition *dp;
+ int i;
+
+ for (i = 0; i < MAXPARTITIONS; i++) {
+ if (i == RAW_PART)
+ continue;
+ if (lp->d_partitions[i].p_size)
+ return;
+ }
+
+ dp = &lp->d_partitions[0];
+ dp->p_offset = BBSIZE / secsize;
+ dp->p_size = lp->d_secperunit - dp->p_offset;
+}
+
+/*
+ * Construct a prototype disklabel from /etc/disktab.
+ */
+void
+makelabel(const char *specname, const char *type, struct disklabel *lp, int is_file)
+{
+ struct disklabel *dp;
+
+ if (strcmp(type, "auto") == 0)
+ dp = getvirginlabel(specname, is_file);
+ else
+ dp = getdiskbyname(type);
+ if (dp == NULL)
+ errx(1, "%s: unknown disk type", type);
+ *lp = *dp;
+ bzero(lp->d_packname, sizeof(lp->d_packname));
+}
+
+static void
+readboot(const char *xxboot, u_char *bootarea)
+{
+ int fd, i;
+ struct stat st;
+ uint64_t *p;
+
+ if (xxboot == NULL)
+ xxboot = "/boot/boot";
+ fd = open(xxboot, O_RDONLY);
+ if (fd < 0)
+ err(1, "cannot open %s", xxboot);
+ fstat(fd, &st);
+ if (alphacksum && st.st_size <= BBSIZE - 512) {
+ i = read(fd, bootarea + 512, st.st_size);
+ if (i != st.st_size)
+ err(1, "read error %s", xxboot);
+
+ /*
+ * Set the location and length so SRM can find the
+ * boot blocks.
+ */
+ p = (uint64_t *)bootarea;
+ p[60] = (st.st_size + secsize - 1) / secsize;
+ p[61] = 1;
+ p[62] = 0;
+ return;
+ } else if ((!alphacksum) && st.st_size <= BBSIZE) {
+ i = read(fd, bootarea, st.st_size);
+ if (i != st.st_size)
+ err(1, "read error %s", xxboot);
+ return;
+ }
+ errx(1, "boot code %s is wrong size", xxboot);
+}
+
+int
+writelabel(struct disklabel *lp, const char *specname, const char *dkname, const char *xxboot,
+ int disable_write, int is_file, int installboot, int allfields)
+{
+ uint64_t *p, sum;
+ int i, fd;
+ struct gctl_req *grq;
+ char const *errstr;
+ static u_char bootarea[BBSIZE];
+
+ if (disable_write) {
+ warnx("write to disk label supressed - label was as follows:");
+ display(specname, stdout, NULL, allfields);
+ return (0);
+ }
+
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ lp->d_checksum = 0;
+ lp->d_checksum = dkcksum(lp);
+ if (installboot)
+ readboot(xxboot, bootarea);
+ for (i = 0; i < lp->d_npartitions; i++)
+ if (lp->d_partitions[i].p_size)
+ lp->d_partitions[i].p_offset += mbroffset;
+ bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * secsize,
+ lp);
+ if (alphacksum) {
+ /* Generate the bootblock checksum for the SRM console. */
+ for (p = (uint64_t *)bootarea, i = 0, sum = 0; i < 63; i++)
+ sum += p[i];
+ p[63] = sum;
+ }
+
+ fd = open(specname, O_RDWR);
+ if (fd < 0) {
+ if (is_file) {
+ warn("cannot open file %s for writing label", specname);
+ return(1);
+ }
+ grq = gctl_get_handle();
+ gctl_ro_param(grq, "verb", -1, "write label");
+ gctl_ro_param(grq, "class", -1, "BSD");
+ gctl_ro_param(grq, "geom", -1, dkname);
+ gctl_ro_param(grq, "label", 148+16*8,
+ bootarea + labeloffset + labelsoffset * secsize);
+ errstr = gctl_issue(grq);
+ if (errstr != NULL) {
+ warnx("%s", errstr);
+ gctl_free(grq);
+ return(1);
+ }
+ gctl_free(grq);
+ if (installboot) {
+ grq = gctl_get_handle();
+ gctl_ro_param(grq, "verb", -1, "write bootcode");
+ gctl_ro_param(grq, "class", -1, "BSD");
+ gctl_ro_param(grq, "geom", -1, dkname);
+ gctl_ro_param(grq, "bootcode", BBSIZE, bootarea);
+ errstr = gctl_issue(grq);
+ if (errstr != NULL) {
+ warnx("%s", errstr);
+ gctl_free(grq);
+ return (1);
+ }
+ gctl_free(grq);
+ }
+ } else {
+ if (write(fd, bootarea, bbsize) != bbsize) {
+ warn("write %s", specname);
+ close (fd);
+ return (1);
+ }
+ close (fd);
+ }
+ return (0);
+}
+
+static void
+get_file_parms(const char *specname, int f)
+{
+ int i;
+ struct stat sb;
+
+ if (fstat(f, &sb) != 0)
+ err(4, "fstat failed");
+ i = sb.st_mode & S_IFMT;
+ if (i != S_IFREG && i != S_IFLNK)
+ errx(4, "%s is not a valid file or link", specname);
+ secsize = DEV_BSIZE;
+ mediasize = sb.st_size;
+}
+
+/*
+ * Fetch disklabel for disk.
+ * Use ioctl to get label unless -r flag is given.
+ */
+int
+readlabel(struct disklabel *lp, const char *specname, const char *dkname, u_char *bootarea,
+ int flag, int is_file)
+{
+ int f, i;
+ int error;
+ struct gctl_req *grq;
+ char const *errstr;
+
+ f = open(specname, O_RDONLY);
+ if (f < 0)
+ err(1, specname);
+ if (is_file)
+ get_file_parms(specname, f);
+ else if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
+ (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
+ err(4, "cannot get disk geometry");
+ }
+ if (mediasize > (off_t)0xffffffff * secsize)
+ errx(1,
+ "disks with more than 2^32-1 sectors are not supported");
+ (void)lseek(f, (off_t)0, SEEK_SET);
+ if (read(f, bootarea, BBSIZE) != BBSIZE)
+ err(4, "%s read", specname);
+ close (f);
+ error = bsd_disklabel_le_dec(
+ bootarea + (labeloffset + labelsoffset * secsize),
+ lp, MAXPARTITIONS);
+ if (flag && error)
+ errx(1, "%s: no valid label found", specname);
+
+ grq = gctl_get_handle();
+ gctl_ro_param(grq, "verb", -1, "read mbroffset");
+ gctl_ro_param(grq, "class", -1, "BSD");
+ gctl_ro_param(grq, "geom", -1, dkname);
+ gctl_rw_param(grq, "mbroffset", sizeof(mbroffset), &mbroffset);
+ errstr = gctl_issue(grq);
+ if (errstr != NULL) {
+ mbroffset = 0;
+ gctl_free(grq);
+ return (error);
+ }
+ if (secsize != 0)
+ mbroffset /= secsize;
+
+ if (lp->d_partitions[RAW_PART].p_offset == mbroffset)
+ for (i = 0; i < lp->d_npartitions; i++)
+ if (lp->d_partitions[i].p_size)
+ lp->d_partitions[i].p_offset -= mbroffset;
+ return (error);
+}
+
+
+void
+display(const char *specname, FILE *f, const struct disklabel *lp, int allfields)
+{
+ int i, j;
+ const struct partition *pp;
+
+ if (lp == NULL)
+ return;
+
+ fprintf(f, "# %s:\n", specname);
+ if (allfields) {
+ if (lp->d_type < DKMAXTYPES)
+ fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
+ else
+ fprintf(f, "type: %u\n", lp->d_type);
+ fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
+ lp->d_typename);
+ fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
+ lp->d_packname);
+ fprintf(f, "flags:");
+ if (lp->d_flags & D_REMOVABLE)
+ fprintf(f, " removeable");
+ if (lp->d_flags & D_ECC)
+ fprintf(f, " ecc");
+ if (lp->d_flags & D_BADSECT)
+ fprintf(f, " badsect");
+ fprintf(f, "\n");
+ fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
+ fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
+ fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
+ fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
+ fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
+ fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
+ fprintf(f, "rpm: %u\n", lp->d_rpm);
+ fprintf(f, "interleave: %u\n", lp->d_interleave);
+ fprintf(f, "trackskew: %u\n", lp->d_trackskew);
+ fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
+ fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
+ (u_long)lp->d_headswitch);
+ fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
+ (u_long)lp->d_trkseek);
+ fprintf(f, "drivedata: ");
+ for (i = NDDATA - 1; i >= 0; i--)
+ if (lp->d_drivedata[i])
+ break;
+ if (i < 0)
+ i = 0;
+ for (j = 0; j <= i; j++)
+ fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
+ fprintf(f, "\n\n");
+ }
+ fprintf(f, "%u partitions:\n", lp->d_npartitions);
+ fprintf(f,
+ "# size offset fstype [fsize bsize bps/cpg]\n");
+ pp = lp->d_partitions;
+ for (i = 0; i < lp->d_npartitions; i++, pp++) {
+ if (pp->p_size) {
+ fprintf(f, " %c: %8lu %8lu ", 'a' + i,
+ (u_long)pp->p_size, (u_long)pp->p_offset);
+ if (pp->p_fstype < FSMAXTYPES)
+ fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
+ else
+ fprintf(f, "%8d", pp->p_fstype);
+ switch (pp->p_fstype) {
+
+ case FS_UNUSED: /* XXX */
+ fprintf(f, " %5lu %5lu %5.5s ",
+ (u_long)pp->p_fsize,
+ (u_long)(pp->p_fsize * pp->p_frag), "");
+ break;
+
+ case FS_BSDFFS:
+ fprintf(f, " %5lu %5lu %5u ",
+ (u_long)pp->p_fsize,
+ (u_long)(pp->p_fsize * pp->p_frag),
+ pp->p_cpg);
+ break;
+
+ case FS_BSDLFS:
+ fprintf(f, " %5lu %5lu %5d",
+ (u_long)pp->p_fsize,
+ (u_long)(pp->p_fsize * pp->p_frag),
+ pp->p_cpg);
+ break;
+
+ default:
+ fprintf(f, "%20.20s", "");
+ break;
+ }
+ if (i == RAW_PART) {
+ fprintf(f, " # \"raw\" part, don't edit");
+ }
+ fprintf(f, "\n");
+ }
+ }
+ fflush(f);
+}
+
+int
+edit(const char *specname, const char *dkname, int disable_write, int is_file, int installboot, int allfields)
+{
+ int c, fd;
+ struct disklabel label;
+ FILE *fp;
+ struct disklabel lab;
+
+ if ((fd = mkstemp(tmpfil)) == -1 ||
+ (fp = fdopen(fd, "w")) == NULL) {
+ warnx("can't create %s", tmpfil);
+ return (1);
+ }
+ display(specname, fp, NULL, allfields);
+ fclose(fp);
+ for (;;) {
+ if (!editit())
+ break;
+ fp = fopen(tmpfil, "r");
+ if (fp == NULL) {
+ warnx("can't reopen %s for reading", tmpfil);
+ break;
+ }
+ bzero((char *)&label, sizeof(label));
+ c = getasciilabel(specname, fp, &label, is_file, allfields);
+ fclose(fp);
+ if (c) {
+ lab = label;
+ if (writelabel(&lab, specname, dkname, NULL, disable_write,
+ is_file, installboot, allfields) == 0) {
+ (void) unlink(tmpfil);
+ return (0);
+ }
+ }
+ printf("re-edit the label? [y]: ");
+ fflush(stdout);
+ c = getchar();
+ if (c != EOF && c != (int)'\n')
+ while (getchar() != (int)'\n')
+ ;
+ if (c == (int)'n')
+ break;
+ }
+ (void) unlink(tmpfil);
+ return (1);
+}
+
+static int
+editit(void)
+{
+ int pid, xpid;
+ int locstat, omask;
+ const char *ed;
+
+ omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+ while ((pid = fork()) < 0) {
+ if (errno == EPROCLIM) {
+ warnx("you have too many processes");
+ return(0);
+ }
+ if (errno != EAGAIN) {
+ warn("fork");
+ return(0);
+ }
+ sleep(1);
+ }
+ if (pid == 0) {
+ sigsetmask(omask);
+ setgid(getgid());
+ setuid(getuid());
+ if ((ed = getenv("EDITOR")) == (char *)0)
+ ed = DEFEDITOR;
+ execlp(ed, ed, tmpfil, (char *)0);
+ err(1, "%s", ed);
+ }
+ while ((xpid = wait(&locstat)) >= 0)
+ if (xpid == pid)
+ break;
+ sigsetmask(omask);
+ return(!locstat);
+}
+
+static char *
+skip(char *cp)
+{
+
+ while (*cp != '\0' && isspace(*cp))
+ cp++;
+ if (*cp == '\0' || *cp == '#')
+ return (NULL);
+ return (cp);
+}
+
+static char *
+word(char *cp)
+{
+ char c;
+
+ while (*cp != '\0' && !isspace(*cp) && *cp != '#')
+ cp++;
+ if ((c = *cp) != '\0') {
+ *cp++ = '\0';
+ if (c != '#')
+ return (skip(cp));
+ }
+ return (NULL);
+}
+
+/*
+ * Read an ascii label in from fd f,
+ * in the same format as that put out by display(),
+ * and fill in lp.
+ */
+static int
+getasciilabel(const char *specname, FILE *f, struct disklabel *lp, int is_file, int allfields)
+{
+ char *cp;
+ const char **cpp;
+ u_int part;
+ char *tp, line[BUFSIZ];
+ u_long v;
+ int lineno = 0, errors = 0;
+ int i;
+ char blank[] = "";
+ char unknown[] = "unknown";
+
+ makelabel(specname, "auto", lp, is_file);
+ bzero(&part_set, sizeof(part_set));
+ bzero(&part_size_type, sizeof(part_size_type));
+ bzero(&part_offset_type, sizeof(part_offset_type));
+ lp->d_bbsize = BBSIZE; /* XXX */
+ lp->d_sbsize = 0; /* XXX */
+ while (fgets(line, sizeof(line) - 1, f)) {
+ lineno++;
+ if ((cp = index(line,'\n')) != 0)
+ *cp = '\0';
+ cp = skip(line);
+ if (cp == NULL)
+ continue;
+ tp = index(cp, ':');
+ if (tp == NULL) {
+ fprintf(stderr, "line %d: syntax error\n", lineno);
+ errors++;
+ continue;
+ }
+ *tp++ = '\0', tp = skip(tp);
+ if (!strcmp(cp, "type")) {
+ if (tp == NULL)
+ tp = unknown;
+ cpp = dktypenames;
+ for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
+ if (*cpp && !strcmp(*cpp, tp)) {
+ lp->d_type = cpp - dktypenames;
+ break;
+ }
+ if (cpp < &dktypenames[DKMAXTYPES])
+ continue;
+ v = strtoul(tp, NULL, 10);
+ if (v >= DKMAXTYPES)
+ fprintf(stderr, "line %d:%s %lu\n", lineno,
+ "Warning, unknown disk type", v);
+ lp->d_type = v;
+ continue;
+ }
+ if (!strcmp(cp, "flags")) {
+ for (v = 0; (cp = tp) && *cp != '\0';) {
+ tp = word(cp);
+ if (!strcmp(cp, "removeable"))
+ v |= D_REMOVABLE;
+ else if (!strcmp(cp, "ecc"))
+ v |= D_ECC;
+ else if (!strcmp(cp, "badsect"))
+ v |= D_BADSECT;
+ else {
+ fprintf(stderr,
+ "line %d: %s: bad flag\n",
+ lineno, cp);
+ errors++;
+ }
+ }
+ lp->d_flags = v;
+ continue;
+ }
+ if (!strcmp(cp, "drivedata")) {
+ for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
+ lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
+ tp = word(cp);
+ }
+ continue;
+ }
+ if (sscanf(cp, "%lu partitions", &v) == 1) {
+ if (v == 0 || v > MAXPARTITIONS) {
+ fprintf(stderr,
+ "line %d: bad # of partitions\n", lineno);
+ lp->d_npartitions = MAXPARTITIONS;
+ errors++;
+ } else
+ lp->d_npartitions = v;
+ continue;
+ }
+ if (tp == NULL)
+ tp = blank;
+ if (!strcmp(cp, "disk")) {
+ strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
+ continue;
+ }
+ if (!strcmp(cp, "label")) {
+ strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
+ continue;
+ }
+ if (!strcmp(cp, "bytes/sector")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0 || (v % DEV_BSIZE) != 0) {
+ fprintf(stderr,
+ "line %d: %s: bad sector size\n",
+ lineno, tp);
+ errors++;
+ } else
+ lp->d_secsize = v;
+ continue;
+ }
+ if (!strcmp(cp, "sectors/track")) {
+ v = strtoul(tp, NULL, 10);
+#if (ULONG_MAX != 0xffffffffUL)
+ if (v == 0 || v > 0xffffffff)
+#else
+ if (v == 0)
+#endif
+ {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_nsectors = v;
+ continue;
+ }
+ if (!strcmp(cp, "sectors/cylinder")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_secpercyl = v;
+ continue;
+ }
+ if (!strcmp(cp, "tracks/cylinder")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_ntracks = v;
+ continue;
+ }
+ if (!strcmp(cp, "cylinders")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_ncylinders = v;
+ continue;
+ }
+ if (!strcmp(cp, "sectors/unit")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_secperunit = v;
+ continue;
+ }
+ if (!strcmp(cp, "rpm")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0 || v > USHRT_MAX) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_rpm = v;
+ continue;
+ }
+ if (!strcmp(cp, "interleave")) {
+ v = strtoul(tp, NULL, 10);
+ if (v == 0 || v > USHRT_MAX) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_interleave = v;
+ continue;
+ }
+ if (!strcmp(cp, "trackskew")) {
+ v = strtoul(tp, NULL, 10);
+ if (v > USHRT_MAX) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_trackskew = v;
+ continue;
+ }
+ if (!strcmp(cp, "cylinderskew")) {
+ v = strtoul(tp, NULL, 10);
+ if (v > USHRT_MAX) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_cylskew = v;
+ continue;
+ }
+ if (!strcmp(cp, "headswitch")) {
+ v = strtoul(tp, NULL, 10);
+ lp->d_headswitch = v;
+ continue;
+ }
+ if (!strcmp(cp, "track-to-track seek")) {
+ v = strtoul(tp, NULL, 10);
+ lp->d_trkseek = v;
+ continue;
+ }
+ /* the ':' was removed above */
+ if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
+ fprintf(stderr,
+ "line %d: %s: Unknown disklabel field\n", lineno,
+ cp);
+ errors++;
+ continue;
+ }
+
+ /* Process a partition specification line. */
+ part = *cp - 'a';
+ if (part >= lp->d_npartitions) {
+ fprintf(stderr,
+ "line %d: partition name out of range a-%c: %s\n",
+ lineno, 'a' + lp->d_npartitions - 1, cp);
+ errors++;
+ continue;
+ }
+ part_set[part] = 1;
+
+ if (getasciipartspec(tp, lp, part, lineno) != 0) {
+ errors++;
+ break;
+ }
+ }
+ errors += checklabel(specname, lp, is_file, allfields);
+ return (errors == 0);
+}
+
+#define NXTNUM(n) do { \
+ if (tp == NULL) { \
+ fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
+ return (1); \
+ } else { \
+ cp = tp, tp = word(cp); \
+ (n) = strtoul(cp, NULL, 10); \
+ } \
+} while (0)
+
+/* retain 1 character following number */
+#define NXTWORD(w,n) do { \
+ if (tp == NULL) { \
+ fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
+ return (1); \
+ } else { \
+ char *tmp; \
+ cp = tp, tp = word(cp); \
+ (n) = strtoul(cp, &tmp, 10); \
+ if (tmp) (w) = *tmp; \
+ } \
+} while (0)
+
+/*
+ * Read a partition line into partition `part' in the specified disklabel.
+ * Return 0 on success, 1 on failure.
+ */
+static int
+getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
+{
+ struct partition *pp;
+ char *cp;
+ const char **cpp;
+ u_long v;
+
+ pp = &lp->d_partitions[part];
+ cp = NULL;
+
+ v = 0;
+ NXTWORD(part_size_type[part],v);
+ if (v == 0 && part_size_type[part] != '*') {
+ fprintf(stderr,
+ "line %d: %s: bad partition size\n", lineno, cp);
+ return (1);
+ }
+ pp->p_size = v;
+
+ v = 0;
+ NXTWORD(part_offset_type[part],v);
+ if (v == 0 && part_offset_type[part] != '*' &&
+ part_offset_type[part] != '\0') {
+ fprintf(stderr,
+ "line %d: %s: bad partition offset\n", lineno, cp);
+ return (1);
+ }
+ pp->p_offset = v;
+ if (tp == NULL) {
+ fprintf(stderr, "line %d: missing file system type\n", lineno);
+ return (1);
+ }
+ cp = tp, tp = word(cp);
+ for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
+ if (*cpp && !strcmp(*cpp, cp))
+ break;
+ if (*cpp != NULL) {
+ pp->p_fstype = cpp - fstypenames;
+ } else {
+ if (isdigit(*cp))
+ v = strtoul(cp, NULL, 10);
+ else
+ v = FSMAXTYPES;
+ if (v >= FSMAXTYPES) {
+ fprintf(stderr,
+ "line %d: Warning, unknown file system type %s\n",
+ lineno, cp);
+ v = FS_UNUSED;
+ }
+ pp->p_fstype = v;
+ }
+
+ switch (pp->p_fstype) {
+ case FS_UNUSED:
+ case FS_BSDFFS:
+ case FS_BSDLFS:
+ /* accept defaults for fsize/frag/cpg */
+ if (tp) {
+ NXTNUM(pp->p_fsize);
+ if (pp->p_fsize == 0)
+ break;
+ NXTNUM(v);
+ pp->p_frag = v / pp->p_fsize;
+ if (tp != NULL)
+ NXTNUM(pp->p_cpg);
+ }
+ /* else default to 0's */
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+/*
+ * Check disklabel for errors and fill in
+ * derived fields according to supplied values.
+ */
+int
+checklabel(const char *specname, struct disklabel *lp, int is_file, int allfields)
+{
+ struct partition *pp;
+ int i, errors = 0;
+ char part;
+ u_long base_offset, needed, total_size, total_percent, current_offset;
+ long free_space;
+ int seen_default_offset;
+ int hog_part;
+ int j;
+ struct partition *pp2;
+
+ if (lp == NULL)
+ return(-1);
+
+ if (allfields) {
+
+ if (lp->d_secsize == 0) {
+ fprintf(stderr, "sector size 0\n");
+ return (1);
+ }
+ if (lp->d_nsectors == 0) {
+ fprintf(stderr, "sectors/track 0\n");
+ return (1);
+ }
+ if (lp->d_ntracks == 0) {
+ fprintf(stderr, "tracks/cylinder 0\n");
+ return (1);
+ }
+ if (lp->d_ncylinders == 0) {
+ fprintf(stderr, "cylinders/unit 0\n");
+ errors++;
+ }
+ if (lp->d_rpm == 0)
+ warnx("revolutions/minute 0");
+ if (lp->d_secpercyl == 0)
+ lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
+ if (lp->d_secperunit == 0)
+ lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
+ if (lp->d_bbsize == 0) {
+ fprintf(stderr, "boot block size 0\n");
+ errors++;
+ } else if (lp->d_bbsize % lp->d_secsize)
+ warnx("boot block size %% sector-size != 0");
+ if (lp->d_npartitions > MAXPARTITIONS)
+ warnx("number of partitions (%lu) > MAXPARTITIONS (%d)",
+ (u_long)lp->d_npartitions, MAXPARTITIONS);
+ } else {
+ struct disklabel *vl;
+
+ vl = getvirginlabel(specname, is_file);
+ lp->d_secsize = vl->d_secsize;
+ lp->d_nsectors = vl->d_nsectors;
+ lp->d_ntracks = vl->d_ntracks;
+ lp->d_ncylinders = vl->d_ncylinders;
+ lp->d_rpm = vl->d_rpm;
+ lp->d_interleave = vl->d_interleave;
+ lp->d_secpercyl = vl->d_secpercyl;
+ lp->d_secperunit = vl->d_secperunit;
+ lp->d_bbsize = vl->d_bbsize;
+ lp->d_npartitions = vl->d_npartitions;
+ }
+
+
+ /* first allocate space to the partitions, then offsets */
+ total_size = 0; /* in sectors */
+ total_percent = 0; /* in percent */
+ hog_part = -1;
+ /* find all fixed partitions */
+ for (i = 0; i < lp->d_npartitions; i++) {
+ pp = &lp->d_partitions[i];
+ if (part_set[i]) {
+ if (part_size_type[i] == '*') {
+ if (i == RAW_PART) {
+ pp->p_size = lp->d_secperunit;
+ } else {
+ if (hog_part != -1)
+ warnx("Too many '*' partitions (%c and %c)",
+ hog_part + 'a',i + 'a');
+ else
+ hog_part = i;
+ }
+ } else {
+ off_t size;
+
+ size = pp->p_size;
+ switch (part_size_type[i]) {
+ case '%':
+ total_percent += size;
+ break;
+ case 't':
+ case 'T':
+ size *= 1024ULL;
+ /* FALLTHROUGH */
+ case 'g':
+ case 'G':
+ size *= 1024ULL;
+ /* FALLTHROUGH */
+ case 'm':
+ case 'M':
+ size *= 1024ULL;
+ /* FALLTHROUGH */
+ case 'k':
+ case 'K':
+ size *= 1024ULL;
+ break;
+ case '\0':
+ break;
+ default:
+ warnx("unknown multiplier suffix '%c' for partition %c (should be K, M, G or T)",
+ part_size_type[i], i + 'a');
+ break;
+ }
+ /* don't count %'s yet */
+ if (part_size_type[i] != '%') {
+ /*
+ * for all not in sectors, convert to
+ * sectors
+ */
+ if (part_size_type[i] != '\0') {
+ if (size % lp->d_secsize != 0)
+ warnx("partition %c not an integer number of sectors",
+ i + 'a');
+ size /= lp->d_secsize;
+ pp->p_size = size;
+ }
+ /* else already in sectors */
+ if (i != RAW_PART)
+ total_size += size;
+ }
+ }
+ }
+ }
+
+ /* Find out the total free space, excluding the boot block area. */
+ base_offset = BBSIZE / secsize;
+ free_space = 0;
+ for (i = 0; i < lp->d_npartitions; i++) {
+ pp = &lp->d_partitions[i];
+ if (!part_set[i] || i == RAW_PART ||
+ part_size_type[i] == '%' || part_size_type[i] == '*')
+ continue;
+ if (pp->p_offset > base_offset)
+ free_space += pp->p_offset - base_offset;
+ if (pp->p_offset + pp->p_size > base_offset)
+ base_offset = pp->p_offset + pp->p_size;
+ }
+ if (base_offset < lp->d_secperunit)
+ free_space += lp->d_secperunit - base_offset;
+
+ /* handle % partitions - note %'s don't need to add up to 100! */
+ if (total_percent != 0) {
+ if (total_percent > 100) {
+ fprintf(stderr,"total percentage %lu is greater than 100\n",
+ total_percent);
+ errors++;
+ }
+
+ if (free_space > 0) {
+ for (i = 0; i < lp->d_npartitions; i++) {
+ pp = &lp->d_partitions[i];
+ if (part_set[i] && part_size_type[i] == '%') {
+ /* careful of overflows! and integer roundoff */
+ pp->p_size = ((double)pp->p_size/100) * free_space;
+ total_size += pp->p_size;
+
+ /* FIX we can lose a sector or so due to roundoff per
+ partition. A more complex algorithm could avoid that */
+ }
+ }
+ } else {
+ fprintf(stderr,
+ "%ld sectors available to give to '*' and '%%' partitions\n",
+ free_space);
+ errors++;
+ /* fix? set all % partitions to size 0? */
+ }
+ }
+ /* give anything remaining to the hog partition */
+ if (hog_part != -1) {
+ /*
+ * Find the range of offsets usable by '*' partitions around
+ * the hog partition and how much space they need.
+ */
+ needed = 0;
+ base_offset = BBSIZE / secsize;
+ for (i = hog_part - 1; i >= 0; i--) {
+ pp = &lp->d_partitions[i];
+ if (!part_set[i] || i == RAW_PART)
+ continue;
+ if (part_offset_type[i] == '*') {
+ needed += pp->p_size;
+ continue;
+ }
+ base_offset = pp->p_offset + pp->p_size;
+ break;
+ }
+ current_offset = lp->d_secperunit;
+ for (i = lp->d_npartitions - 1; i > hog_part; i--) {
+ pp = &lp->d_partitions[i];
+ if (!part_set[i] || i == RAW_PART)
+ continue;
+ if (part_offset_type[i] == '*') {
+ needed += pp->p_size;
+ continue;
+ }
+ current_offset = pp->p_offset;
+ }
+
+ if (current_offset - base_offset <= needed) {
+ fprintf(stderr, "Cannot find space for partition %c\n",
+ hog_part + 'a');
+ fprintf(stderr,
+ "Need more than %lu sectors between %lu and %lu\n",
+ needed, base_offset, current_offset);
+ errors++;
+ lp->d_partitions[hog_part].p_size = 0;
+ } else {
+ lp->d_partitions[hog_part].p_size = current_offset -
+ base_offset - needed;
+ total_size += lp->d_partitions[hog_part].p_size;
+ }
+ }
+
+ /* Now set the offsets for each partition */
+ current_offset = BBSIZE / secsize; /* in sectors */
+ seen_default_offset = 0;
+ for (i = 0; i < lp->d_npartitions; i++) {
+ part = 'a' + i;
+ pp = &lp->d_partitions[i];
+ if (part_set[i]) {
+ if (part_offset_type[i] == '*') {
+ if (i == RAW_PART) {
+ pp->p_offset = 0;
+ } else {
+ pp->p_offset = current_offset;
+ seen_default_offset = 1;
+ }
+ } else {
+ /* allow them to be out of order for old-style tables */
+ if (pp->p_offset < current_offset &&
+ seen_default_offset && i != RAW_PART &&
+ pp->p_fstype != FS_VINUM) {
+ fprintf(stderr,
+"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
+ (long)pp->p_offset,i+'a',current_offset);
+ fprintf(stderr,
+"Labels with any *'s for offset must be in ascending order by sector\n");
+ errors++;
+ } else if (pp->p_offset != current_offset &&
+ i != RAW_PART && seen_default_offset) {
+ /*
+ * this may give unneeded warnings if
+ * partitions are out-of-order
+ */
+ warnx(
+"Offset %ld for partition %c doesn't match expected value %ld",
+ (long)pp->p_offset, i + 'a', current_offset);
+ }
+ }
+ if (i != RAW_PART)
+ current_offset = pp->p_offset + pp->p_size;
+ }
+ }
+
+ for (i = 0; i < lp->d_npartitions; i++) {
+ part = 'a' + i;
+ pp = &lp->d_partitions[i];
+ if (pp->p_size == 0 && pp->p_offset != 0)
+ warnx("partition %c: size 0, but offset %lu",
+ part, (u_long)pp->p_offset);
+#ifdef notdef
+ if (pp->p_size % lp->d_secpercyl)
+ warnx("partition %c: size %% cylinder-size != 0",
+ part);
+ if (pp->p_offset % lp->d_secpercyl)
+ warnx("partition %c: offset %% cylinder-size != 0",
+ part);
+#endif
+ if (pp->p_offset > lp->d_secperunit) {
+ fprintf(stderr,
+ "partition %c: offset past end of unit\n", part);
+ errors++;
+ }
+ if (pp->p_offset + pp->p_size > lp->d_secperunit) {
+ fprintf(stderr,
+ "partition %c: partition extends past end of unit\n",
+ part);
+ errors++;
+ }
+ if (i == RAW_PART) {
+ if (pp->p_fstype != FS_UNUSED)
+ warnx("partition %c is not marked as unused!",part);
+ if (pp->p_offset != 0)
+ warnx("partition %c doesn't start at 0!",part);
+ if (pp->p_size != lp->d_secperunit)
+ warnx("partition %c doesn't cover the whole unit!",part);
+
+ if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
+ (pp->p_size != lp->d_secperunit)) {
+ warnx("An incorrect partition %c may cause problems for "
+ "standard system utilities",part);
+ }
+ }
+
+ /* check for overlaps */
+ /* this will check for all possible overlaps once and only once */
+ for (j = 0; j < i; j++) {
+ pp2 = &lp->d_partitions[j];
+ if (j != RAW_PART && i != RAW_PART &&
+ pp->p_fstype != FS_VINUM &&
+ pp2->p_fstype != FS_VINUM &&
+ part_set[i] && part_set[j]) {
+ if (pp2->p_offset < pp->p_offset + pp->p_size &&
+ (pp2->p_offset + pp2->p_size > pp->p_offset ||
+ pp2->p_offset >= pp->p_offset)) {
+ fprintf(stderr,"partitions %c and %c overlap!\n",
+ j + 'a', i + 'a');
+ errors++;
+ }
+ }
+ }
+ }
+ for (; i < MAXPARTITIONS; i++) {
+ part = 'a' + i;
+ pp = &lp->d_partitions[i];
+ if (pp->p_size || pp->p_offset)
+ warnx("unused partition %c: size %d offset %lu",
+ 'a' + i, pp->p_size, (u_long)pp->p_offset);
+ }
+ return (errors);
+}
+
+/*
+ * When operating on a "virgin" disk, try getting an initial label
+ * from the associated device driver. This might work for all device
+ * drivers that are able to fetch some initial device parameters
+ * without even having access to a (BSD) disklabel, like SCSI disks,
+ * most IDE drives, or vn devices.
+ *
+ * The device name must be given in its "canonical" form.
+ */
+static struct disklabel *
+getvirginlabel(const char *specname, int is_file)
+{
+ static struct disklabel loclab;
+ struct partition *dp;
+ int f;
+ u_int u;
+
+ if ((f = open(specname, O_RDONLY)) == -1) {
+ warn("cannot open %s", specname);
+ return (NULL);
+ }
+
+ if (is_file)
+ get_file_parms(specname, f);
+ else if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
+ (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
+ close (f);
+ return (NULL);
+ }
+ memset(&loclab, 0, sizeof loclab);
+ loclab.d_magic = DISKMAGIC;
+ loclab.d_magic2 = DISKMAGIC;
+ loclab.d_secsize = secsize;
+ loclab.d_secperunit = mediasize / secsize;
+
+ /*
+ * Nobody in these enligthened days uses the CHS geometry for
+ * anything, but nontheless try to get it right. If we fail
+ * to get any good ideas from the device, construct something
+ * which is IBM-PC friendly.
+ */
+ if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
+ loclab.d_nsectors = u;
+ else
+ loclab.d_nsectors = 63;
+ if (ioctl(f, DIOCGFWHEADS, &u) == 0)
+ loclab.d_ntracks = u;
+ else if (loclab.d_secperunit <= 63*1*1024)
+ loclab.d_ntracks = 1;
+ else if (loclab.d_secperunit <= 63*16*1024)
+ loclab.d_ntracks = 16;
+ else
+ loclab.d_ntracks = 255;
+ loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
+ loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
+ loclab.d_npartitions = MAXPARTITIONS;
+
+ /* Various (unneeded) compat stuff */
+ loclab.d_rpm = 3600;
+ loclab.d_bbsize = BBSIZE;
+ loclab.d_interleave = 1;
+ strncpy(loclab.d_typename, "amnesiac",
+ sizeof(loclab.d_typename));
+
+ dp = &loclab.d_partitions[RAW_PART];
+ dp->p_size = loclab.d_secperunit;
+ loclab.d_checksum = dkcksum(&loclab);
+ close (f);
+ return (&loclab);
+}
Index: bsdlabel.h
===================================================================
RCS file: bsdlabel.h
diff -N bsdlabel.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ bsdlabel.h 15 Sep 2005 16:52:55 -0000
@@ -0,0 +1,14 @@
+#ifndef _BSDLABEL_H_
+#define _BSD_LABEL_H_
+
+__BEGIN_DECLS
+void makelabel(const char *, const char *, struct disklabel *, int);
+int writelabel(struct disklabel *, const char *, const char *, const char *, int, int, int, int);
+int readlabel(struct disklabel *, const char *, const char *, u_char *, int, int);
+void display(const char *specname, FILE *, const struct disklabel *, int);
+int edit(const char *, const char *, int, int, int, int);
+void fixlabel(struct disklabel *);
+int checklabel(const char *, struct disklabel *, int, int);
+__END_DECLS
+
+#endif /* ! _BSDLABEL_H_ */
Index: libdisk.h
===================================================================
RCS file: /home/ncvs/src/lib/libdisk/libdisk.h,v
retrieving revision 1.62
diff -u -u -r1.62 libdisk.h
--- libdisk.h 21 Apr 2004 23:21:13 -0000 1.62
+++ libdisk.h 15 Sep 2005 16:52:55 -0000
@@ -10,6 +10,9 @@
*
*/
+#ifndef LIBDISK_H
+#define LIBDISK_H
+
/* #define DEBUG 1 */
/* You can define a particular architecture here if you are debugging. */
/* #define P_DEBUG p_sparc64 */
@@ -361,3 +364,5 @@
*
*
*/
+
+#endif /* ! LIBDISK_H */
Index: write_i386_disk.c
===================================================================
RCS file: /home/ncvs/src/lib/libdisk/write_i386_disk.c,v
retrieving revision 1.9
diff -u -u -r1.9 write_i386_disk.c
--- write_i386_disk.c 4 Jun 2004 11:49:11 -0000 1.9
+++ write_i386_disk.c 15 Sep 2005 16:52:55 -0000
@@ -11,6 +11,7 @@
__FBSDID("$FreeBSD: src/lib/libdisk/write_i386_disk.c,v 1.9 2004/06/04 11:49:11 brian Exp $");
#include <stdio.h>
+#include <libgeom.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
@@ -20,39 +21,40 @@
#include <sys/disklabel.h>
#include <sys/diskmbr.h>
#include <paths.h>
+#include <err.h> /* XXX: debug */
#include "libdisk.h"
+#include "boot0cfg.h"
+#include "bsdlabel.h"
+#define LABELSIZE (148 + 16 * MAXPARTITIONS)
+
+/* XXX: debug */
+FILE *libdisk_debug;
+const char *junk = "CRAIG"__DATE__ __TIME__ ;
/*
* XXX: A lot of hardcoded 512s probably should be foo->sector_size;
* I'm not sure which, so I leave it like it worked before. --schweikh
*/
static int
-Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+Write_BSDLabel(const char *device, const struct disk *new, const struct chunk *c1)
{
- struct disklabel *dl;
- int i;
- void *p;
+ struct disklabel dl = { 0 };
+ //int i, fd;
+ //void *p;
u_char buf[BBSIZE];
+ //u_char label[LABELSIZE];
+ int installboot = (new->boot1 || new->boot2);
+ //const char *q;
+ //struct gctl_req *grq;
+ int error;
+
+ readlabel(&dl, device, c1->name, buf, 0, 0);
+ makelabel(device, "auto", &dl, 0);
+ fixlabel(&dl);
+ if(checklabel(device, &dl, 0, 0) == 0)
+ error = writelabel(&dl, device, c1->name, NULL, 0, 0, installboot, 1);
- for (i = 0; i < BBSIZE/512; i++) {
- if (!(p = read_block(fd, i + c1->offset, 512)))
- return (1);
- memcpy(buf + 512 * i, p, 512);
- free(p);
- }
- if (new->boot1)
- memcpy(buf, new->boot1, 512);
-
- if (new->boot2)
- memcpy(buf + 512, new->boot2, BBSIZE - 512);
-
- dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
- Fill_Disklabel(dl, new, c1);
-
- for (i = 0; i < BBSIZE / 512; i++)
- write_block(fd, i + c1->offset, buf + 512 * i, 512);
-
- return 0;
+ return(error);
}
static void
@@ -84,7 +86,7 @@
int
Write_Disk(const struct disk *d1)
{
- int fd, j;
+ int j, fd;
uint i;
struct chunk *c1;
int ret = 0;
@@ -92,24 +94,24 @@
u_char *mbrblk;
struct dos_partition *dp,work[NDOSPART];
int s[4];
+ int mbr_size;
int need_edd = 0; /* Need EDD (packet interface) */
strcpy(device, _PATH_DEV);
strcat(device, d1->name);
- fd = open(device, O_RDWR);
- if (fd < 0)
- return 1;
+ /* XXX: debug */
+ libdisk_debug = fopen("/tmp/debug.txt", "w");
+ err_set_file(libdisk_debug);
memset(s, 0, sizeof s);
- if (!(mbrblk = read_block(fd, 0, d1->sector_size))) {
- close (fd);
- return (1);
+ if ((mbr_size = read_mbr(device, &mbrblk, 1)) < 0) {
+ return 1;
}
dp = (struct dos_partition *)(mbrblk + DOSPARTOFF);
memcpy(work, dp, sizeof work);
dp = work;
- free(mbrblk);
+
for (c1 = d1->chunks->part; c1; c1 = c1->next) {
if (c1->type == unused)
continue;
@@ -119,8 +121,6 @@
if (j < 0 || j > 3)
continue;
s[j]++;
- if (c1->type == freebsd)
- ret += Write_FreeBSD(fd, d1, c1);
Write_Int32(&dp[j].dp_start, c1->offset);
Write_Int32(&dp[j].dp_size, c1->size);
@@ -182,10 +182,6 @@
if (dp[i].dp_typ == 0xa5)
dp[i].dp_flag = 0x80;
- if (!(mbrblk = read_block(fd, 0, d1->sector_size))) {
- close (fd);
- return (1);
- }
if (d1->bootmgr) {
memcpy(mbrblk, d1->bootmgr, DOSPARTOFF);
Cfg_Boot_Mgr(mbrblk, need_edd);
@@ -193,12 +189,40 @@
memcpy(mbrblk + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
mbrblk[512-2] = 0x55;
mbrblk[512-1] = 0xaa;
- write_block(fd, 0, mbrblk, d1->sector_size);
+
if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
- for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
- write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
- d1->sector_size);
+ for (i = 1; (i * d1->sector_size <= d1->bootmgr_size) && i + d1->sector_size < mbr_size; i++) {
+ memcpy(&mbrblk[i], &d1->bootmgr[i * d1->sector_size],
+ d1->sector_size);
+
+ }
+ /* XXX: debug */
+ warnx("LIBDISK: writing mbrblk here\n");
+ ret = write_mbr(device, 0, mbrblk, mbr_size);
+ if (ret != 0) {
+ warnx("LIBDISK: failed writing mbrblk\n");
+ } else { // XXX: extra warning
+ warnx("LIBDISK: succeeded mbrblk\n");
+ }
+
+ /* open the device to let GEOM reconfigure */
+ fd = open(device, O_WRONLY);
+ if (fd != -1)
+ close(fd);
- close(fd);
- return 0;
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == freebsd) {
+ j = Write_BSDLabel(device, d1, c1);
+ if (j !=0) {
+ warnx("LIBDISK: failed to write bsdlabel %s",
+ c1->name);
+ } else { /* XXX: extra warning */
+ warnx("LIBDISK: succeeded writing bsdlabel %s",
+ c1->name);
+ }
+
+ ret +=j;
+ }
+ }
+ return ret;
}
-------------- next part --------------
Index: Makefile
===================================================================
RCS file: /home/ncvs/src/usr.sbin/sysinstall/Makefile,v
retrieving revision 1.134
diff -u -u -r1.134 Makefile
--- Makefile 19 Mar 2005 02:28:02 -0000 1.134
+++ Makefile 15 Sep 2005 16:53:22 -0000
@@ -24,8 +24,8 @@
.endif
CFLAGS+= -I${.CURDIR}/../../gnu/lib/libdialog -I.
-DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBUTIL} ${LIBDISK} ${LIBFTPIO}
-LDADD= -ldialog -lncurses -lutil -ldisk -lftpio
+DPADD= ${LIBDIALOG} ${LIBNCURSES} ${LIBUTIL} ${LIBDISK} ${LIBFTPIO} ${LIBGEOM}
+LDADD= -ldialog -lncurses -lutil -ldisk -lftpio -lgeom
CLEANFILES= makedevs.c rtermcap
CLEANFILES+= keymap.tmp keymap.h
More information about the freebsd-current
mailing list