1 /* $NetBSD: disksubr.c,v 1.4 2019/04/17 20:46:38 skrll Exp $ */ 2 3 /* $OpenBSD: disksubr.c,v 1.6 2000/10/18 21:00:34 mickey Exp $ */ 4 5 /* 6 * Copyright (c) 1999 Michael Shalayeff 7 * Copyright (c) 1997 Niklas Hallqvist 8 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 36 */ 37 38 /* 39 * Copyright (c) 1996 Theo de Raadt. All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 53 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 54 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 59 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 /* 63 * This disksubr.c module started to take its present form on OpenBSD/alpha 64 * but it was always thought it should be made completely MI and not need to 65 * be in that alpha-specific tree at all. 66 * 67 * XXX HPUX disklabel is not understood yet. 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.4 2019/04/17 20:46:38 skrll Exp $"); 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/buf.h> 76 #include <sys/device.h> 77 #include <sys/disklabel.h> 78 #include <sys/syslog.h> 79 #include <sys/disk.h> 80 81 const char *readliflabel(struct buf *, void (*)(struct buf *), 82 struct disklabel *, struct cpu_disklabel *, int *, int *, int); 83 const char *readbsdlabel(struct buf *, void (*)(struct buf *), int, 84 int, int, struct disklabel *, int); 85 86 /* 87 * Try to read a standard BSD disklabel at a certain sector. 88 */ 89 const char * 90 readbsdlabel(struct buf *bp, void (*strat)(struct buf *), int cyl, int sec, 91 int off, struct disklabel *lp, int spoofonly) 92 { 93 struct disklabel *dlp; 94 const char *msg = NULL; 95 uint16_t cksum; 96 97 /* don't read the on-disk label if we are in spoofed-only mode */ 98 if (spoofonly) 99 return (NULL); 100 101 bp->b_blkno = sec; 102 bp->b_cylinder = cyl; 103 bp->b_bcount = lp->d_secsize; 104 bp->b_cflags = BC_BUSY; 105 bp->b_flags = B_READ; 106 bp->b_oflags = 0; 107 (*strat)(bp); 108 109 /* if successful, locate disk label within block and validate */ 110 if (biowait(bp)) { 111 /* XXX we return the faked label built so far */ 112 msg = "disk label I/O error"; 113 return (msg); 114 } 115 116 /* 117 * If off is negative, search until the end of the sector for 118 * the label, otherwise, just look at the specific location 119 * we're given. 120 */ 121 dlp = (struct disklabel *)((char *)bp->b_data + (off >= 0 ? off : 0)); 122 do { 123 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { 124 if (msg == NULL) 125 msg = "no disk label"; 126 } else { 127 cksum = dkcksum(dlp); 128 if (dlp->d_npartitions > MAXPARTITIONS || cksum != 0) { 129 msg = "disk label corrupted"; 130 } else { 131 *lp = *dlp; 132 msg = NULL; 133 break; 134 } 135 } 136 if (off >= 0) 137 break; 138 dlp = (struct disklabel *)((char *)dlp + sizeof(int32_t)); 139 } while (dlp <= (struct disklabel *)((char *)bp->b_data + 140 lp->d_secsize - sizeof(*dlp))); 141 return (msg); 142 } 143 144 /* 145 * Attempt to read a disk label from a device 146 * using the indicated strategy routine. 147 * The label must be partly set up before this: 148 * secpercyl, secsize and anything required for a block i/o read 149 * operation in the driver's strategy/start routines 150 * must be filled in before calling us. 151 * 152 * Returns null on success and an error string on failure. 153 */ 154 const char * 155 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 156 struct cpu_disklabel *osdep) 157 { 158 int spoofonly = 0; 159 struct buf *bp = NULL; 160 const char *msg = "no disk label"; 161 int i; 162 struct disklabel fallbacklabel; 163 164 /* minimal requirements for archetypal disk label */ 165 if (lp->d_secsize == 0) 166 lp->d_secsize = DEV_BSIZE; 167 if (lp->d_secperunit == 0) 168 lp->d_secperunit = 0x1fffffff; 169 if (lp->d_secpercyl == 0) 170 return "invalid geometry"; 171 172 lp->d_npartitions = RAW_PART + 1; 173 for (i = 0; i < RAW_PART; i++) { 174 lp->d_partitions[i].p_size = 0; 175 lp->d_partitions[i].p_offset = 0; 176 } 177 if (lp->d_partitions[i].p_size == 0) 178 lp->d_partitions[i].p_size = 0x1fffffff; 179 lp->d_partitions[i].p_offset = 0; 180 fallbacklabel = *lp; 181 182 /* get a buffer and initialize it */ 183 bp = geteblk((int)lp->d_secsize); 184 bp->b_dev = dev; 185 186 msg = readliflabel(bp, strat, lp, osdep, 0, 0, spoofonly); 187 188 #if defined(CD9660) 189 if (msg && iso_disklabelspoof(dev, strat, lp) == 0) 190 msg = NULL; 191 #endif 192 193 /* If there was an error, still provide a decent fake one. */ 194 if (msg) 195 *lp = fallbacklabel; 196 197 if (bp) { 198 brelse(bp, BC_INVAL); 199 } 200 return (msg); 201 } 202 203 204 const char * 205 readliflabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp, 206 struct cpu_disklabel *osdep, int *partoffp, int *cylp, int spoofonly) 207 { 208 int fsoff; 209 210 /* read LIF volume header */ 211 bp->b_blkno = btodb(HPPA_LIF_VOLSTART); 212 bp->b_bcount = lp->d_secsize; 213 bp->b_cflags = BC_BUSY; 214 bp->b_flags = B_READ; 215 bp->b_cylinder = btodb(HPPA_LIF_VOLSTART) / lp->d_secpercyl; 216 (*strat)(bp); 217 218 if (biowait(bp)) { 219 if (partoffp) 220 *partoffp = -1; 221 return "LIF volume header I/O error"; 222 } 223 224 memcpy(&osdep->lifvol, bp->b_data, sizeof(struct hppa_lifvol)); 225 if (osdep->lifvol.vol_id != HPPA_LIF_VOL_ID) { 226 fsoff = 0; 227 } else { 228 struct buf *dbp; 229 struct hppa_lifdir *p; 230 231 dbp = geteblk(lp->d_secsize); 232 dbp->b_dev = bp->b_dev; 233 234 /* read LIF directory */ 235 dbp->b_blkno = btodb(HPPA_LIF_DIRSTART); 236 dbp->b_bcount = lp->d_secsize; 237 dbp->b_cflags = BC_BUSY; 238 dbp->b_flags = B_READ; 239 dbp->b_cylinder = (HPPA_LIF_DIRSTART) / lp->d_secpercyl; 240 241 (*strat)(dbp); 242 243 if (biowait(dbp)) { 244 if (partoffp) 245 *partoffp = -1; 246 brelse(dbp, BC_INVAL); 247 248 return "LIF directory I/O error"; 249 } 250 251 memcpy(osdep->lifdir, dbp->b_data, HPPA_LIF_DIRSIZE); 252 brelse(dbp, BC_INVAL); 253 /* scan for LIF_DIR_FS dir entry */ 254 for (fsoff = -1, p = &osdep->lifdir[0]; 255 fsoff < 0 && p < &osdep->lifdir[HPPA_LIF_NUMDIR]; p++) 256 if (p->dir_type == HPPA_LIF_DIR_FS) 257 fsoff = hppa_lifstodb(p->dir_addr); 258 259 /* if no suitable lifdir entry found assume 0 */ 260 if (fsoff < 0) 261 fsoff = 0; 262 } 263 264 if (partoffp) 265 *partoffp = fsoff; 266 267 return readbsdlabel(bp, strat, 0, fsoff + LABELSECTOR, LABELOFFSET, 268 lp, spoofonly); 269 } 270 271 /* 272 * Write disk label back to device after modification. 273 */ 274 int 275 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 276 struct cpu_disklabel *osdep) 277 { 278 const char *msg = "no disk label"; 279 struct buf *bp; 280 struct disklabel dl; 281 struct cpu_disklabel cdl; 282 int labeloffset, error, partoff = 0, cyl = 0; 283 284 /* get a buffer and initialize it */ 285 bp = geteblk((int)lp->d_secsize); 286 bp->b_dev = dev; 287 288 /* 289 * I once played with the thought of using osdep->label{tag,sector} 290 * as a cache for knowing where (and what) to write. However, now I 291 * think it might be useful to reprobe if someone has written 292 * a newer disklabel of another type with disklabel(8) and -r. 293 */ 294 dl = *lp; 295 msg = readliflabel(bp, strat, &dl, &cdl, &partoff, &cyl, 0); 296 labeloffset = LABELOFFSET; 297 298 if (msg) { 299 if (partoff == -1) 300 return EIO; 301 302 /* Write it in the regular place with native byte order. */ 303 labeloffset = LABELOFFSET; 304 bp->b_blkno = partoff + LABELSECTOR; 305 bp->b_cylinder = cyl; 306 bp->b_bcount = lp->d_secsize; 307 } 308 309 *(struct disklabel *)((char *)bp->b_data + labeloffset) = *lp; 310 311 bp->b_cflags = BC_BUSY; 312 bp->b_flags = B_WRITE; 313 (*strat)(bp); 314 error = biowait(bp); 315 316 brelse(bp, BC_INVAL); 317 return (error); 318 } 319