tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: disklabel endian issues



>>>>> "lp" == Lloyd Parkes <lloyd%must-have-coffee.gen.nz@localhost> writes:

    lp> Is it my imagination, or is disklabel not endian aware?

The attached half-decade-old patch might not help the kind of endian
aware you want, but in general the way to use it is,

# sleep 90 < /dev/rsd0c&
# disklabel -l sd0
# mount /dev/sd0a /mnt

it will load foreign labels into the kernel ephemerally, without
rewriting the on-disk label in the form of the native architecture.

I don't know if it has any use for writing labels, though.

Index: arch/mac68k/mac68k/disksubr.c
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sys/arch/mac68k/mac68k/disksubr.c,v
retrieving revision 1.1.1.6
retrieving revision 1.8
diff -u -r1.1.1.6 -r1.8
--- arch/mac68k/mac68k/disksubr.c       18 Jul 2005 14:03:52 -0000      1.1.1.6
+++ arch/mac68k/mac68k/disksubr.c       20 Jul 2005 22:50:58 -0000      1.8
@@ -311,6 +311,8 @@
 }
 
 /*
+ * XXX !! -- why is this cruft here?  w.t.f. is wrong with mbrlabel?
+ *
  * Scan the disk buffer for a DOS style master boot record.
  * Return if no match; otherwise, set up an in-core disklabel .
  *
@@ -465,7 +467,6 @@
 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
     struct cpu_disklabel *osdep)
 {
-#if 0
        int i;
        struct partition *opp, *npp;
 
@@ -512,7 +513,6 @@
        nlp->d_checksum = 0;
        nlp->d_checksum = dkcksum(nlp);
        *olp = *nlp;
-#endif
        return (0);
 }
 
Index: sbin/disklabel/disklabel.c
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sbin/disklabel/disklabel.c,v
retrieving revision 1.1.1.8
retrieving revision 1.11
diff -u -r1.1.1.8 -r1.11
--- sbin/disklabel/disklabel.c  18 Jul 2005 13:58:24 -0000      1.1.1.8
+++ sbin/disklabel/disklabel.c  21 Jul 2005 04:32:09 -0000      1.11
@@ -55,6 +55,8 @@
 #define DKTYPENAMES
 #define FSTYPENAMES
 #include <sys/disklabel.h>
+#include <sys/types.h>
+#include <machine/bswap.h>
 #include <sys/bootblock.h>
 
 #include <ufs/ufs/dinode.h>
@@ -70,6 +72,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <util.h>
+#include <strings.h>
 
 #include <disktab.h>
 
@@ -119,16 +122,17 @@
 #endif /* NUMBOOT > 0 */
 
 static enum    {
-       UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, WRITE, WRITEBOOT, INTERACT
+       UNSPEC, EDIT, READ, LOAD, RESTORE, SETWRITABLE, WRITE, WRITEBOOT, 
INTERACT
 } op = UNSPEC;
 
 static int     Fflag;
 static int     rflag;
 static int     tflag;
        int     Cflag;
+static  int     lflag;
 static int     Iflag;
 
-#define COMMON_OPTIONS "BCFINRWb:ef:irs:tw"
+#define COMMON_OPTIONS "BCFINRWb:ef:ilrs:tw"
 
 #ifdef DEBUG
 static int     debug;
@@ -159,6 +163,7 @@
                            struct disklabel *);
 static void             l_perror(const char *);
 static struct disklabel        *readlabel(int);
+static struct disklabel *bswapdisklabel __P((struct disklabel *));
 static struct disklabel        *makebootarea(char *, struct disklabel *, int);
 static int              edit(struct disklabel *, int);
 static int              editit(void);
@@ -244,6 +249,9 @@
                case 'r':
                        ++rflag;
                        break;
+               case 'l':
+                       ++lflag;
+                       break;
                case 'w':
                        if (op != UNSPEC)
                                usage();
@@ -267,13 +275,35 @@
                if (op == UNSPEC)
                        op = WRITEBOOT;
        } else {
-               if (op == UNSPEC)
-                       op = READ;
-       }
 #else  /* NUMBOOT <= 0 */
-       if (op == UNSPEC)
-               op = READ;
+       if (1) {
 #endif /* NUMBOOT <= 0 */
+               if (lflag) {
+                       if (op == UNSPEC) {
+                               op = LOAD;
+                               ++rflag;
+                       } else {
+                               if (op != WRITE && op != EDIT && op != INTERACT 
&& op != RESTORE)
+                                       usage();
+                               /*
+                                * rflag and lflag will actually work fine 
+                                * together in EDIT mode--the label is read 
+                                * in raw mode, and then loaded into the 
+                                * kernel without writing it to disk.  but 
+                                * 'disklabel -l; disklabel -el' is equivalent 
+                                * as long as no partitions are open, and 
+                                * treating -l and -r as mutually exclusive 
+                                * brings the user closer to an intuitive 
+                                * understanding of their meanings.
+                                */
+                               if (rflag)
+                                       usage();
+                       }
+               } else {
+                       if (op == UNSPEC)
+                               op = READ;
+               }
+       }
 
        if (argc < 1)
                usage();
@@ -347,6 +377,18 @@
                        error += 100;
                break;
 
+       case LOAD:
+               if (argc != 1)
+                       usage();
+               lp = readlabel(f);
+               if (checklabel(lp) && ~DE_WARN)
+                       error = writelabel(f, bootarea, lp);
+               else {
+                       error = 1;
+                       warnx("label not loaded.");
+               }
+               break;
+
        case RESTORE:
                if (argc < 2 || argc > 3)
                        usage();
@@ -376,8 +418,10 @@
                *lp = lab;
                if (checklabel(lp) == 0)
                        error = writelabel(f, bootarea, lp);
-               else
+               else {
                        error = 1;
+                       warnx("label not written.");
+               }
                break;
 
        case WRITEBOOT:
@@ -393,8 +437,10 @@
                *lp = tlab;
                if (checklabel(lp) == 0)
                        error = writelabel(f, bootarea, lp);
-               else
+               else {
                        error = 1;
+                       warnx("label not written.");
+               }
                break;
        }
 #endif /* NUMBOOT > 0 */
@@ -485,7 +531,15 @@
        lp->d_magic = DISKMAGIC;
        lp->d_magic2 = DISKMAGIC;
        lp->d_checksum = 0;
-       lp->d_checksum = dkcksum(lp);
+       lp->d_checksum = dkcksum(lp, lp->d_npartitions);
+
+       if (lflag) {
+               if (ioctl(f, DIOCSDINFO, lp) < 0) {
+                       perror("ioctl DIOCSDINFO");
+                       return (1);
+               }
+               return 0;
+       }
 
        if (Fflag || rflag || Iflag)
        {
@@ -883,7 +937,7 @@
 static struct disklabel *
 readlabel(int f)
 {
-       struct disklabel *lp;
+       struct disklabel *lp, *bslp;
 
        if (Fflag || rflag || Iflag) {
                const char *msg;
@@ -913,10 +967,19 @@
                        if (lp->d_magic == DISKMAGIC &&
                            lp->d_magic2 == DISKMAGIC) {
                                if (lp->d_npartitions <= MAXPARTITIONS &&
-                                   dkcksum(lp) == 0)
+                                   dkcksum(lp, lp->d_npartitions) == 0)
                                        return (lp);
                                msg = "disk label corrupted";
                        }
+                       if (lp->d_magic == bswap32(DISKMAGIC) &&
+                           lp->d_magic2 == bswap32(DISKMAGIC)) {
+                               if (bswap16(lp->d_npartitions) <= MAXPARTITIONS 
&&
+                                   dkcksum(lp, bswap16(lp->d_npartitions)) == 
0) {
+                                       bslp = bswapdisklabel(lp);
+                                       return (bslp);
+                               }
+                               msg = "disk label corrupted";
+                       }
                }
                if (msg != NULL && !Iflag)
                        errx(1, "%s", msg);
@@ -937,6 +1000,74 @@
 }
 
 /*
+ * byte-swap all the individual fields inside a disklabel.
+ * returns a pointer to the freshly-malloc'd disklabel.
+ * call with lp->d_npartitions as a sane (foreign-endiness) number, because 
+ *  bswapdisklabel will allocate enough memory to hold more than MAXPARTITIONS
+ */
+static struct disklabel *
+bswapdisklabel(lp)
+       struct disklabel *lp;
+{
+       struct disklabel *bslp;
+       int i;
+       struct partition *part, *bspart, *partend;
+       size_t sz;
+
+       /* sys/disklabel.h:  ``actually may be more'' */
+       sz = sizeof(*lp) + sizeof(struct partition) * 
(bswap16(lp->d_npartitions) - MAXPARTITIONS);
+       bslp = (struct disklabel *)malloc(sz < sizeof(*lp) ? sizeof(*lp) : sz);
+       /*
+        * bcopy without swapping, so we don't have to bother with strings.
+        * the variable-lengthyness expressed in the ? construct above is 
bzero'ed in the partition loop.
+        */
+       bcopy(lp, bslp, sz);
+
+       bslp->d_magic = bswap32(lp->d_magic);
+       bslp->d_type = bswap16(lp->d_type);
+       bslp->d_subtype = bswap16(lp->d_subtype);
+       bslp->d_secsize = bswap32(lp->d_secsize);
+       bslp->d_nsectors = bswap32(lp->d_nsectors);
+       bslp->d_ntracks = bswap32(lp->d_ntracks);
+       bslp->d_ncylinders = bswap32(lp->d_ncylinders);
+       bslp->d_secpercyl = bswap32(lp->d_secpercyl);
+       bslp->d_secperunit = bswap32(lp->d_secperunit);
+       bslp->d_sparespertrack = bswap16(lp->d_sparespertrack);
+       bslp->d_sparespercyl = bswap16(lp->d_sparespercyl);
+       bslp->d_acylinders = bswap32(lp->d_acylinders);
+       bslp->d_rpm = bswap16(lp->d_rpm);
+       bslp->d_interleave = bswap16(lp->d_interleave);
+       bslp->d_trackskew = bswap16(lp->d_trackskew);
+       bslp->d_cylskew = bswap16(lp->d_cylskew);
+       bslp->d_headswitch = bswap32(lp->d_headswitch);
+       bslp->d_trkseek = bswap32(lp->d_trkseek);
+       bslp->d_flags = bswap32(lp->d_flags);
+       for (i = 0; i < NDDATA; i++)
+               bslp->d_drivedata[i] = bswap32(lp->d_drivedata[i]);
+       for (i = 0; i < NSPARE; i++)
+               bslp->d_spare[i] = bswap32(lp->d_spare[i]);
+       bslp->d_magic2 = bswap32(lp->d_magic2);
+       bslp->d_checksum = 0; /* hopeless.  but, checksumming is 
endian-independent so endian-ignorant routines elsewhere can fill this in. */
+       bslp->d_npartitions = bswap16(lp->d_npartitions);
+       bslp->d_bbsize = bswap32(lp->d_bbsize);
+       bslp->d_sbsize = bswap32(lp->d_sbsize);
+
+       bzero(bslp->d_partitions, sizeof(struct partition) * MAXPARTITIONS);
+       for (part = lp->d_partitions, bspart = bslp->d_partitions, partend = 
bslp->d_partitions + sizeof(struct partition) * bslp->d_npartitions; bspart < 
partend; bspart++, part++) {
+               bspart->p_size = bswap32(part->p_size);
+               bspart->p_offset = bswap32(part->p_offset);
+               bspart->p_fsize = bswap32(part->p_fsize);
+               /* p_fstype and p_frag don't need bswap, but we bzero'ed 'em */
+               bspart->p_fstype = part->p_fstype;
+               bspart->p_frag = part->p_frag;
+               bspart->p_cpg = bswap16(part->p_cpg);
+       }
+
+       return(bslp);
+}
+
+
+/*
  * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
  * Returns a pointer to the disklabel portion of the bootarea.
  */
@@ -1724,19 +1855,19 @@
        errors = 0;
        if (lp->d_secsize == 0) {
                warnx("sector size %d", lp->d_secsize);
-               return (1);
+               return (DE_ERROR);
        }
        if (lp->d_nsectors == 0) {
                warnx("sectors/track %d", lp->d_nsectors);
-               return (1);
+               return (DE_ERROR);
        }
        if (lp->d_ntracks == 0) {
                warnx("tracks/cylinder %d", lp->d_ntracks);
-               return (1);
+               return (DE_ERROR);
        }
        if  (lp->d_ncylinders == 0) {
                warnx("cylinders/unit %d", lp->d_ncylinders);
-               errors++;
+               return (DE_ERROR);
        }
        if (lp->d_rpm == 0)
                warnx("warning, revolutions/minute %d", lp->d_rpm);
@@ -1747,7 +1878,7 @@
 #ifdef __i386__notyet__
        if (dosdp && lp->d_secperunit > dosdp->mbrp_start + dosdp->mbrp_size) {
                warnx("exceeds DOS partition size");
-               errors++;
+               errors |= DE_WARN;
                lp->d_secperunit = dosdp->mbrp_start + dosdp->mbrp_size;
        }
        /* XXX should also check geometry against BIOS's idea */
@@ -1757,12 +1888,12 @@
 #endif /* __arm32__notyet__ */
        if (lp->d_bbsize == 0) {
                warnx("boot block size %d", lp->d_bbsize);
-               errors++;
+               errors |= DE_WARN;
        } else if (lp->d_bbsize % lp->d_secsize)
                warnx("warning, boot block size %% sector-size != 0");
        if (lp->d_sbsize == 0) {
                warnx("super block size %d", lp->d_sbsize);
-               errors++;
+               errors |= DE_WARN;
        } else if (lp->d_sbsize % lp->d_secsize)
                warnx("warning, super block size %% sector-size != 0");
        if (lp->d_npartitions > MAXPARTITIONS)
@@ -1791,18 +1922,18 @@
                        warnx("warning, partition %c:"
                            " not starting on cylinder boundary",
                            part);
-                       errors++;
+                       errors |= DE_WARN;
                }
 #endif /* STRICT_CYLINDER_ALIGNMENT */
                if (pp->p_offset > lp->d_secperunit) {
                        warnx("partition %c: offset past end of unit", part);
-                       errors++;
+                       errors |= DE_ERROR;
                }
                if (pp->p_offset + pp->p_size > lp->d_secperunit) {
                        warnx("partition %c: partition extends"
                            " past end of unit",
                            part);
-                       errors++;
+                       errors |= DE_ERROR;
                }
                if (pp->p_fstype != FS_UNUSED)
                        for (j = i + 1; j < lp->d_npartitions; j++) {
@@ -1871,18 +2002,20 @@
        } usages[] = {
        { "[-rt] [-C] [-F] disk",
            "(to read label)" },
-       { "-w [-r] [-F] [-f disktab] disk type [ packid ]",
+       { "-l disk",
+           "(to read label and load it into the kernel)" },
+       { "-w [-r|-l] [-F] [-f disktab] disk type [ packid ]",
 #if NUMBOOT > 0
            "(to write label with existing boot program)"
 #else
            "(to write label)"
 #endif
        },
-       { "-e [-r] [-I] [-C] [-F] disk",
+       { "-e [-r|-l] [-I] [-C] [-F] disk",
            "(to edit label)" },
-       { "-i [-I] [-r] [-F] disk",
+       { "-i [-I] [-r|-l] [-F] disk",
            "(to create a label interactively)" },
-       { "-R [-r] [-F] disk protofile",
+       { "-R [-r|-l] [-F] disk protofile",
 #if NUMBOOT > 0
            "(to restore label with existing boot program)"
 #else
Index: sbin/disklabel/dkcksum.c
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sbin/disklabel/dkcksum.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sbin/disklabel/dkcksum.c    12 Dec 2003 11:29:04 -0000      1.1.1.2
+++ sbin/disklabel/dkcksum.c    12 Dec 2003 20:30:02 -0000      1.3
@@ -43,14 +43,14 @@
 #include "dkcksum.h"
 
 u_short
-dkcksum(struct disklabel *lp)
+dkcksum(struct disklabel *lp, u_int16_t npart)
 {
        u_short *start, *end;
        u_short  sum;
 
        sum = 0;
        start = (u_short *)lp;
-       end = (u_short *)&lp->d_partitions[lp->d_npartitions];
+       end = (u_short *)&lp->d_partitions[npart];
        while (start < end)
                sum ^= *start++;
        return (sum);
Index: sbin/disklabel/dkcksum.h
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sbin/disklabel/dkcksum.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- sbin/disklabel/dkcksum.h    4 Mar 2002 18:38:33 -0000       1.1.1.1
+++ sbin/disklabel/dkcksum.h    8 Mar 2002 23:58:21 -0000       1.2
@@ -1,3 +1,3 @@
 /*     $NetBSD: dkcksum.h,v 1.3 2000/12/24 05:59:11 lukem Exp $        */
 
-u_short        dkcksum(struct disklabel *);
+u_short dkcksum __P((struct disklabel *, u_int16_t));
Index: sbin/disklabel/extern.h
===================================================================
RCS file: /scratch/cvsroot/netbsd/src/sbin/disklabel/extern.h,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sbin/disklabel/extern.h     19 Apr 2002 18:31:56 -0000      1.1.1.2
+++ sbin/disklabel/extern.h     24 Apr 2002 23:26:03 -0000      1.3
@@ -29,6 +29,10 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/* error codes for checklabel */
+#define DE_WARN                (1 << 0)
+#define DE_ERROR       (1 << 1)
+
 int    writelabel(int, char *, struct disklabel *);
 int    checklabel(struct disklabel *);
 void   showinfo(FILE *, struct disklabel *, const char *);

Attachment: pgpwS5n_fWtSq.pgp
Description: PGP signature



Home | Main Index | Thread Index | Old Index