look for disk label at any reasonable offset
[unix-history] / usr / src / sys / ufs / ffs / ufs_disksubr.c
index d6cd682..4b53405 100644 (file)
@@ -3,9 +3,17 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)ufs_disksubr.c      7.1 (Berkeley) %G%
+ *     @(#)ufs_disksubr.c      7.4 (Berkeley) %G%
  */
 
  */
 
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "disklabel.h"
+
+#include "dir.h"
+#include "user.h"
+
 /*
  * Seek sort for disks.  We depend on the driver
  * which calls us using b_resid as the current cylinder number.
 /*
  * Seek sort for disks.  We depend on the driver
  * which calls us using b_resid as the current cylinder number.
  * blocks are allocated.
  */
 
  * blocks are allocated.
  */
 
-#include "param.h"
-#include "systm.h"
-#include "buf.h"
-
 #define        b_cylin b_resid
 
 disksort(dp, bp)
 #define        b_cylin b_resid
 
 disksort(dp, bp)
@@ -106,3 +110,76 @@ insert:
        if (ap == dp->b_actl)
                dp->b_actl = bp;
 }
        if (ap == dp->b_actl)
                dp->b_actl = bp;
 }
+
+/*
+ * Attempt to read a disk label from a device
+ * using the indicated stategy routine.
+ * The label must be partly set up before this:
+ * secpercyl and anything required in the strategy routine
+ * (e.g., sector size) must be filled in before calling us.
+ * Returns null on success and an error string on failure.
+ */
+char *
+readdisklabel(dev, strat, lp)
+       dev_t dev;
+       int (*strat)();
+       register struct disklabel *lp;
+{
+       register struct buf *bp;
+       struct disklabel *dlp;
+       char *msg = NULL;
+
+       if (lp->d_secperunit == 0)
+               lp->d_secperunit = 0x1fffffff;
+       lp->d_npartitions = 1;
+       if (lp->d_partitions[0].p_size == 0)
+               lp->d_partitions[0].p_size = 0x1fffffff;
+       lp->d_partitions[0].p_offset = 0;
+
+       bp = geteblk(lp->d_secsize);
+       bp->b_dev = dev;
+       bp->b_blkno = LABELSECTOR;
+       bp->b_bcount = lp->d_secsize;
+       bp->b_flags = B_BUSY | B_READ;
+       bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
+       (*strat)(bp);
+       biowait(bp);
+       if (bp->b_flags & B_ERROR) {
+               u.u_error = 0;          /* XXX */
+               msg = "I/O error";
+       } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
+           dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
+           dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
+               if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
+                       if (msg == NULL)
+                               msg = "no disk label";
+               } else if (dkcksum(dlp) != 0)
+                       msg = "disk label corrupted";
+               else {
+                       *lp = *dlp;
+                       msg = NULL;
+                       break;
+               }
+       }
+       if (lp->d_npartitions > MAXPARTITIONS)
+               lp->d_npartitions = MAXPARTITIONS;
+       bp->b_flags = B_INVAL | B_AGE;
+       brelse(bp);
+       return (msg);
+}
+
+/*
+ * Compute checksum for disk label.
+ */
+dkcksum(lp)
+       register struct disklabel *lp;
+{
+       register u_short *start, *end;
+       register u_short sum = 0;
+
+       start = (u_short *)lp;
+       end = (u_short *)&lp->d_partitions[lp->d_npartitions];
+       while (start < end)
+               sum ^= *start++;
+       return (sum);
+}