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 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +__FBSDID("$FreeBSD: src/sbin/bsdlabel/bsdlabel.c,v 1.111 2005/08/14 22:46:50 iedowse Exp $"); + +#include +#include +#include +#include +#include +#include +#define DKTYPENAMES +#define FSTYPENAMES +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include #include #include #include @@ -20,39 +21,40 @@ #include #include #include +#include /* 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; }