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