1 /* $NetBSD: disksubr.c,v 1.25 2002/09/28 01:17:10 dbj Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. 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 * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, 39 * Michael L. Finch, Bradley A. Grantham, and 40 * Lawrence A. Kesteloot 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the Alice Group. 54 * 4. The names of the Alice Group or any of its members may not be used 55 * to endorse or promote products derived from this software without 56 * specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR 59 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 61 * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, 62 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 63 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 64 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 65 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 66 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 67 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 * 69 */ 70 /* 71 * Copyright (C) 1996 Wolfgang Solfrank. 72 * Copyright (C) 1996 TooLs GmbH. 73 * All rights reserved. 74 * 75 * Redistribution and use in source and binary forms, with or without 76 * modification, are permitted provided that the following conditions 77 * are met: 78 * 1. Redistributions of source code must retain the above copyright 79 * notice, this list of conditions and the following disclaimer. 80 * 2. Redistributions in binary form must reproduce the above copyright 81 * notice, this list of conditions and the following disclaimer in the 82 * documentation and/or other materials provided with the distribution. 83 * 3. All advertising materials mentioning features or use of this software 84 * must display the following acknowledgement: 85 * This product includes software developed by TooLs GmbH. 86 * 4. The name of TooLs GmbH may not be used to endorse or promote products 87 * derived from this software without specific prior written permission. 88 * 89 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 90 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 91 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 92 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 93 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 94 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 95 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 96 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 97 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 98 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 99 */ 100 101 /* rewritten, 2-5-93 MLF */ 102 /* its alot cleaner now, and adding support for new partition types 103 * isn't a bitch anymore 104 * known bugs: 105 * 1) when only an HFS_PART part exists on a drive it gets assigned to "B" 106 * this is because of line 623 of sd.c, I think this line should go. 107 * 2) /sbin/disklabel expects the whole disk to be in "D", we put it in 108 * "C" (I think) and we don't set that position in the disklabel structure 109 * as used. Again, not my fault. 110 */ 111 #include <sys/param.h> 112 #include <sys/systm.h> 113 #include <sys/buf.h> 114 #include <sys/conf.h> 115 #include <sys/disk.h> 116 #include <sys/disklabel.h> 117 #include <sys/disklabel_mbr.h> 118 #include <sys/syslog.h> 119 120 #include <machine/bswap.h> 121 122 #define NUM_PARTS 32 123 124 #define ROOT_PART 1 125 #define UFS_PART 2 126 #define SWAP_PART 3 127 #define HFS_PART 4 128 #define SCRATCH_PART 5 129 130 static int getFreeLabelEntry __P((struct disklabel *)); 131 static int whichType __P((struct part_map_entry *, u_int8_t *, int *)); 132 static void setpartition __P((struct part_map_entry *, 133 struct partition *, int)); 134 static int getNamedType __P((struct part_map_entry *, int, 135 struct disklabel *, int, int, int *)); 136 static char *read_mac_label __P((dev_t, void (*)(struct buf *), 137 struct disklabel *, struct cpu_disklabel *)); 138 static char *read_dos_label __P((dev_t, void (*)(struct buf *), 139 struct disklabel *, struct cpu_disklabel *)); 140 static int get_netbsd_label __P((dev_t, void (*)(struct buf *), 141 struct disklabel *, struct cpu_disklabel *)); 142 143 /* 144 * Find an entry in the disk label that is unused and return it 145 * or -1 if no entry 146 */ 147 static int 148 getFreeLabelEntry(lp) 149 struct disklabel *lp; 150 { 151 int i = 0; 152 153 for (i = 0; i < MAXPARTITIONS; i++) { 154 if ((i != RAW_PART) 155 && (lp->d_partitions[i].p_fstype == FS_UNUSED)) 156 return i; 157 } 158 159 return -1; 160 } 161 162 /* 163 * figure out what the type of the given part is and return it 164 */ 165 static int 166 whichType(struct part_map_entry *part, u_int8_t *fstype, int *clust) 167 { 168 struct blockzeroblock *bzb; 169 char typestr[32], *s; 170 int type; 171 172 /* Set default unix partition type. Certain partition types can 173 * specify a different partition type. */ 174 *fstype = FS_OTHER; 175 *clust = 0; /* only A/UX partitions not in cluster 0 */ 176 177 if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0') 178 return 0; 179 180 strncpy(typestr, (char *)part->pmPartType, sizeof(typestr)); 181 typestr[sizeof(typestr) - 1] = '\0'; 182 for (s = typestr; *s; s++) 183 if ((*s >= 'a') && (*s <= 'z')) 184 *s = (*s - 'a' + 'A'); 185 186 if (strncmp(PART_TYPE_DRIVER, typestr, strlen(PART_TYPE_DRIVER)) == 0 || 187 strcmp(PART_TYPE_DRIVER43, typestr) == 0 || 188 strcmp(PART_TYPE_DRIVERATA, typestr) == 0 || 189 strcmp(PART_TYPE_DRIVERIOKIT, typestr) == 0 || 190 strcmp(PART_TYPE_FWDRIVER, typestr) == 0 || 191 strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 || 192 strcmp(PART_TYPE_PARTMAP, typestr) == 0 || 193 strcmp(PART_TYPE_PATCHES, typestr) == 0) 194 type = 0; 195 else if (strcmp(PART_TYPE_NBSD_PPCBOOT, typestr) == 0) { 196 type = ROOT_PART; 197 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 198 if ((bzb->bzbMagic == BZB_MAGIC) && 199 (bzb->bzbType < FSMAXTYPES)) 200 *fstype = bzb->bzbType; 201 else 202 *fstype = FS_BSDFFS; 203 } else if (strcmp(PART_TYPE_NETBSD, typestr) == 0 || 204 strcmp(PART_TYPE_NBSD_68KBOOT, typestr) == 0) { 205 type = UFS_PART; 206 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 207 if ((bzb->bzbMagic == BZB_MAGIC) && 208 (bzb->bzbType < FSMAXTYPES)) 209 *fstype = bzb->bzbType; 210 else 211 *fstype = FS_BSDFFS; 212 } else if (strcmp(PART_TYPE_UNIX, typestr) == 0) { 213 /* unix part, swap, root, usr */ 214 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 215 *clust = bzb->bzbCluster; 216 if (bzb->bzbMagic != BZB_MAGIC) { 217 type = 0; 218 } else if (bzb->bzbFlags & BZB_ROOTFS) { 219 type = ROOT_PART; 220 *fstype = FS_BSDFFS; 221 } else if (bzb->bzbFlags & (BZB_USRFS | BZB_USRFS_NEW)) { 222 type = UFS_PART; 223 *fstype = FS_BSDFFS; 224 } else if (bzb->bzbType == BZB_TYPESWAP) { 225 type = SWAP_PART; 226 *fstype = FS_SWAP; 227 } else { 228 type = SCRATCH_PART; 229 *fstype = FS_OTHER; 230 } 231 } else if (strcmp(PART_TYPE_MAC, typestr) == 0) { 232 type = HFS_PART; 233 *fstype = FS_HFS; 234 } else if (strcmp(PART_TYPE_APPLEUFS, typestr) == 0) { 235 type = SCRATCH_PART; 236 *fstype = FS_APPLEUFS; 237 } else if (strcmp(PART_TYPE_LINUX, typestr) == 0) { 238 type = SCRATCH_PART; 239 *fstype = FS_OTHER; 240 } else if (strcmp(PART_TYPE_LINUX_SWAP, typestr) == 0) { 241 type = SCRATCH_PART; 242 *fstype = FS_OTHER; 243 } else { 244 type = SCRATCH_PART; /* no known type */ 245 *fstype = FS_OTHER; 246 } 247 248 return type; 249 } 250 251 static void 252 setpartition(struct part_map_entry *part, struct partition *pp, int fstype) 253 { 254 pp->p_size = part->pmPartBlkCnt; 255 pp->p_offset = part->pmPyPartStart; 256 pp->p_fstype = fstype; 257 258 part->pmPartType[0] = '\0'; 259 } 260 261 static int 262 getNamedType(part, num_parts, lp, type, alt, maxslot) 263 struct part_map_entry *part; 264 int num_parts; 265 struct disklabel *lp; 266 int type, alt; 267 int *maxslot; 268 { 269 struct blockzeroblock *bzb; 270 int i = 0, clust; 271 u_int8_t realtype; 272 273 for (i = 0; i < num_parts; i++) { 274 if (whichType(part + i, &realtype, &clust) != type) 275 continue; 276 277 if (type == ROOT_PART) { 278 bzb = (struct blockzeroblock *) 279 (&(part + i)->pmBootArgs); 280 if (alt >= 0 && alt != clust) 281 continue; 282 setpartition(part + i, &lp->d_partitions[0], realtype); 283 } else if (type == UFS_PART) { 284 bzb = (struct blockzeroblock *) 285 (&(part + i)->pmBootArgs); 286 if (alt >= 0 && alt != clust) 287 continue; 288 setpartition(part + i, &lp->d_partitions[6], realtype); 289 if (*maxslot < 6) 290 *maxslot = 6; 291 } else if (type == SWAP_PART) { 292 setpartition(part + i, &lp->d_partitions[1], realtype); 293 if (*maxslot < 1) 294 *maxslot = 1; 295 } else if (type == HFS_PART) { 296 setpartition(part + i, &lp->d_partitions[3], realtype); 297 if (*maxslot < 3) 298 *maxslot = 3; 299 } else 300 printf("disksubr.c: can't do type %d\n", type); 301 302 return 0; 303 } 304 305 return -1; 306 } 307 308 /* 309 * MF -- 310 * here's what i'm gonna do: 311 * read in the entire diskpartition table, it may be bigger or smaller 312 * than NUM_PARTS but read that many entries. Each entry has a magic 313 * number so we'll know if an entry is crap. 314 * next fill in the disklabel with info like this 315 * next fill in the root, usr, and swap parts. 316 * then look for anything else and fit it in. 317 * A: root 318 * B: Swap 319 * C: Whole disk 320 * G: Usr 321 * 322 * 323 * I'm not entirely sure what netbsd386 wants in c & d 324 * 386bsd wants other stuff, so i'll leave them alone 325 * 326 * AKB -- I added to Mike's original algorithm by searching for a bzbCluster 327 * of zero for root, first. This allows A/UX to live on cluster 1 and 328 * NetBSD to live on cluster 0--regardless of the actual order on the 329 * disk. This whole algorithm should probably be changed in the future. 330 */ 331 static char * 332 read_mac_label(dev, strat, lp, osdep) 333 dev_t dev; 334 void (*strat)(struct buf *); 335 struct disklabel *lp; 336 struct cpu_disklabel *osdep; 337 { 338 struct part_map_entry *part; 339 struct partition *pp; 340 struct buf *bp; 341 char *msg = NULL; 342 int i, slot, maxslot = 0, clust; 343 u_int8_t realtype; 344 345 /* get buffer and initialize it */ 346 bp = geteblk((int)lp->d_secsize * NUM_PARTS); 347 bp->b_dev = dev; 348 349 /* read partition map */ 350 bp->b_blkno = 1; /* partition map starts at blk 1 */ 351 bp->b_bcount = lp->d_secsize * NUM_PARTS; 352 bp->b_flags |= B_READ; 353 bp->b_cylinder = 1 / lp->d_secpercyl; 354 (*strat)(bp); 355 356 if (biowait(bp)) { 357 msg = "Macintosh partition map I/O error"; 358 goto done; 359 } 360 361 part = (struct part_map_entry *)bp->b_data; 362 363 /* Fill in standard partitions */ 364 lp->d_npartitions = RAW_PART + 1; 365 if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot)) 366 getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot); 367 if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot)) 368 getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot); 369 getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot); 370 getNamedType(part, NUM_PARTS, lp, HFS_PART, -1, &maxslot); 371 372 /* Now get as many of the rest of the partitions as we can */ 373 for (i = 0; i < NUM_PARTS; i++) { 374 slot = getFreeLabelEntry(lp); 375 if (slot < 0) 376 break; 377 378 pp = &lp->d_partitions[slot]; 379 380 /* 381 * Additional ROOT_PART will turn into a plain old 382 * UFS_PART partition, live with it. 383 */ 384 385 if (whichType(part + i, &realtype, &clust)) { 386 setpartition(part + i, pp, realtype); 387 } else { 388 slot = 0; 389 } 390 if (slot > maxslot) 391 maxslot = slot; 392 } 393 lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1; 394 395 done: 396 brelse(bp); 397 return msg; 398 } 399 400 /* Read MS-DOS partition table. 401 * 402 * XXX - 403 * Since FFS is endian sensitive, we pay no effort in attempting to 404 * dig up *BSD/i386 disk labels that may be present on the disk. 405 * Hence anything but DOS partitions is treated as unknown FS type, but 406 * this should suffice to mount_msdos Zip and other removable media. 407 */ 408 static char * 409 read_dos_label(dev, strat, lp, osdep) 410 dev_t dev; 411 void (*strat)(struct buf *); 412 struct disklabel *lp; 413 struct cpu_disklabel *osdep; 414 { 415 struct mbr_partition *dp; 416 struct buf *bp; 417 char *msg = NULL; 418 int i, slot, maxslot = 0; 419 u_int32_t bsdpartoff; 420 struct mbr_partition *bsdp; 421 422 /* get a buffer and initialize it */ 423 bp = geteblk((int)lp->d_secsize); 424 bp->b_dev = dev; 425 426 /* read master boot record */ 427 bp->b_blkno = MBR_BBSECTOR; 428 bp->b_bcount = lp->d_secsize; 429 bp->b_flags |= B_READ; 430 bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl; 431 (*strat)(bp); 432 433 bsdpartoff = 0; 434 435 /* if successful, wander through dos partition table */ 436 if (biowait(bp)) { 437 msg = "dos partition I/O error"; 438 goto done; 439 } 440 /* XXX */ 441 dp = (struct mbr_partition *)(bp->b_data + MBR_PARTOFF); 442 bsdp = NULL; 443 for (i = 0; i < NMBRPART; i++, dp++) { 444 switch (dp->mbrp_typ) { 445 case MBR_PTYPE_NETBSD: 446 bsdp = dp; 447 break; 448 case MBR_PTYPE_OPENBSD: 449 case MBR_PTYPE_386BSD: 450 if (!bsdp) 451 bsdp = dp; 452 break; 453 } 454 } 455 if (!bsdp) { 456 /* generate fake disklabel */ 457 dp = (struct mbr_partition *)(bp->b_data + MBR_PARTOFF); 458 for (i = 0; i < NMBRPART; i++, dp++) { 459 if (!dp->mbrp_typ) 460 continue; 461 slot = getFreeLabelEntry(lp); 462 if (slot < 0) 463 break; 464 if (slot > maxslot) 465 maxslot = slot; 466 467 lp->d_partitions[slot].p_offset = bswap32(dp->mbrp_start); 468 lp->d_partitions[slot].p_size = bswap32(dp->mbrp_size); 469 470 switch (dp->mbrp_typ) { 471 case MBR_PTYPE_FAT12: 472 case MBR_PTYPE_FAT16S: 473 case MBR_PTYPE_FAT16B: 474 case MBR_PTYPE_FAT32: 475 case MBR_PTYPE_FAT32L: 476 case MBR_PTYPE_FAT16L: 477 lp->d_partitions[slot].p_fstype = FS_MSDOS; 478 break; 479 default: 480 lp->d_partitions[slot].p_fstype = FS_OTHER; 481 break; 482 } 483 } 484 msg = "no NetBSD disk label"; 485 } else { 486 /* NetBSD partition on MBR */ 487 bsdpartoff = bswap32(bsdp->mbrp_start); 488 489 lp->d_partitions[2].p_size = bswap32(bsdp->mbrp_size); 490 lp->d_partitions[2].p_offset = bswap32(bsdp->mbrp_start); 491 if (2 > maxslot) 492 maxslot = 2; 493 /* read in disklabel, blkno + 1 for DOS disklabel offset */ 494 osdep->cd_labelsector = bsdpartoff + MBR_LABELSECTOR; 495 osdep->cd_labeloffset = MBR_LABELOFFSET; 496 if (get_netbsd_label(dev, strat, lp, osdep)) 497 goto done; 498 msg = "no NetBSD disk label"; 499 } 500 501 lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1; 502 503 done: 504 brelse(bp); 505 return (msg); 506 } 507 508 /* 509 * Get real NetBSD disk label 510 */ 511 static int 512 get_netbsd_label(dev, strat, lp, osdep) 513 dev_t dev; 514 void (*strat)(struct buf *); 515 struct disklabel *lp; 516 struct cpu_disklabel *osdep; 517 { 518 struct buf *bp; 519 struct disklabel *dlp; 520 521 /* get a buffer and initialize it */ 522 bp = geteblk((int)lp->d_secsize); 523 bp->b_dev = dev; 524 525 /* Now get the label block */ 526 bp->b_blkno = osdep->cd_labelsector; 527 bp->b_bcount = lp->d_secsize; 528 bp->b_flags |= B_READ; 529 bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 530 (*strat)(bp); 531 532 if (biowait(bp)) 533 goto done; 534 535 for (dlp = (struct disklabel *)(bp->b_data + osdep->cd_labeloffset); 536 dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof (*dlp)); 537 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 538 if (dlp->d_magic == DISKMAGIC 539 && dlp->d_magic2 == DISKMAGIC 540 && dlp->d_npartitions <= MAXPARTITIONS 541 && dkcksum(dlp) == 0) { 542 *lp = *dlp; 543 osdep->cd_labeloffset = (caddr_t)dlp - bp->b_data; 544 brelse(bp); 545 return 1; 546 } 547 } 548 done: 549 brelse(bp); 550 return 0; 551 } 552 553 /* 554 * Attempt to read a disk label from a device using the indicated strategy 555 * routine. The label must be partly set up before this: secpercyl and 556 * anything required in the strategy routine (e.g., sector size) must be 557 * filled in before calling us. Returns null on success and an error 558 * string on failure. 559 * 560 * This will read sector zero. If this contains what looks like a valid 561 * Macintosh boot sector, we attempt to fill in the disklabel structure. 562 * If the first longword of the disk is a NetBSD disk label magic number, 563 * then we assume that it's a real disklabel and return it. 564 */ 565 char * 566 readdisklabel(dev, strat, lp, osdep) 567 dev_t dev; 568 void (*strat)(struct buf *); 569 struct disklabel *lp; 570 struct cpu_disklabel *osdep; 571 { 572 struct buf *bp; 573 char *msg = NULL; 574 575 if (lp->d_secperunit == 0) 576 lp->d_secperunit = 0x1fffffff; 577 578 if (lp->d_secpercyl == 0) { 579 return msg = "Zero secpercyl"; 580 } 581 bp = geteblk((int)lp->d_secsize); 582 583 bp->b_dev = dev; 584 bp->b_blkno = 0; 585 bp->b_resid = 0; 586 bp->b_bcount = lp->d_secsize; 587 bp->b_flags |= B_READ; 588 bp->b_cylinder = 1 / lp->d_secpercyl; 589 (*strat)(bp); 590 591 osdep->cd_start = -1; 592 593 /* XXX cd_start is abused as a flag for fictious disklabel */ 594 595 if (biowait(bp)) { 596 msg = "I/O error reading block zero"; 597 goto done; 598 } 599 osdep->cd_labelsector = LABELSECTOR; 600 osdep->cd_labeloffset = LABELOFFSET; 601 if (get_netbsd_label(dev, strat, lp, osdep)) 602 osdep->cd_start = 0; 603 else { 604 u_int16_t *sbSigp; 605 606 sbSigp = (u_int16_t *)bp->b_data; 607 if (*sbSigp == 0x4552) { 608 /* it ignores labelsector/offset */ 609 msg = read_mac_label(dev, strat, lp, osdep); 610 /* the disklabel is fictious */ 611 } else if (bswap16(*(u_int16_t *)(bp->b_data + MBR_MAGICOFF)) 612 == MBR_MAGIC) { 613 /* read_dos_label figures out labelsector/offset */ 614 msg = read_dos_label(dev, strat, lp, osdep); 615 if (!msg) 616 osdep->cd_start = 0; 617 } else { 618 msg = "no disk label -- NetBSD or Macintosh"; 619 osdep->cd_start = 0; /* XXX for now */ 620 } 621 } 622 623 done: 624 brelse(bp); 625 return (msg); 626 } 627 628 /* 629 * Check new disk label for sensibility before setting it. 630 */ 631 int 632 setdisklabel(olp, nlp, openmask, osdep) 633 struct disklabel *olp, *nlp; 634 u_long openmask; 635 struct cpu_disklabel *osdep; 636 { 637 /* sanity clause */ 638 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 639 || (nlp->d_secsize % DEV_BSIZE) != 0) 640 return EINVAL; 641 642 /* special case to allow disklabel to be invalidated */ 643 if (nlp->d_magic == 0xffffffff) { 644 *olp = *nlp; 645 return 0; 646 } 647 648 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC 649 || dkcksum(nlp) != 0) 650 return EINVAL; 651 652 /* openmask parameter ignored */ 653 654 *olp = *nlp; 655 return 0; 656 } 657 658 /* 659 * Write disk label back to device after modification. 660 */ 661 int 662 writedisklabel(dev, strat, lp, osdep) 663 dev_t dev; 664 void (*strat)(struct buf *); 665 struct disklabel *lp; 666 struct cpu_disklabel *osdep; 667 { 668 struct buf *bp; 669 int error; 670 struct disklabel label; 671 672 /* 673 * Try to re-read a disklabel, in case he changed the MBR. 674 */ 675 label = *lp; 676 readdisklabel(dev, strat, &label, osdep); 677 if (osdep->cd_start < 0) 678 return EINVAL; 679 680 /* get a buffer and initialize it */ 681 bp = geteblk(lp->d_secsize); 682 bp->b_dev = dev; 683 684 bp->b_blkno = osdep->cd_start + osdep->cd_labelsector; 685 bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 686 bp->b_bcount = lp->d_secsize; 687 688 bp->b_flags |= B_READ; 689 (*strat)(bp); 690 error = biowait(bp); 691 if (error != 0) 692 goto done; 693 694 bp->b_flags &= ~(B_READ|B_DONE); 695 bp->b_flags |= B_WRITE; 696 697 memcpy((caddr_t)bp->b_data + osdep->cd_labeloffset, (caddr_t)lp, 698 sizeof *lp); 699 700 (*strat)(bp); 701 error = biowait(bp); 702 703 done: 704 brelse(bp); 705 706 return error; 707 } 708 709 /* 710 * Determine the size of the transfer, and make sure it is 711 * within the boundaris of the partition. Adjust transfer 712 * if needed, and signal errors or early completion. 713 */ 714 int 715 bounds_check_with_label(bp, lp, wlabel) 716 struct buf *bp; 717 struct disklabel *lp; 718 int wlabel; 719 { 720 struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); 721 int sz; 722 723 sz = howmany(bp->b_bcount, lp->d_secsize); 724 725 if (bp->b_blkno + sz > p->p_size) { 726 sz = p->p_size - bp->b_blkno; 727 if (sz == 0) { 728 /* If axactly at end of disk, return EOF. */ 729 bp->b_resid = bp->b_bcount; 730 goto done; 731 } 732 if (sz < 0) { 733 /* If past end of disk, return EINVAL. */ 734 bp->b_error = EINVAL; 735 goto bad; 736 } 737 /* Otherwise truncate request. */ 738 bp->b_bcount = sz * lp->d_secsize; 739 } 740 741 /* calculate cylinder for disksort to order transfers with */ 742 bp->b_cylinder = (bp->b_blkno + p->p_offset) 743 / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 744 745 return 1; 746 747 bad: 748 bp->b_flags |= B_ERROR; 749 done: 750 return 0; 751 } 752