Line data Source code
1 : /* $OpenBSD: subr_disk.c,v 1.234 2018/04/28 15:44:59 jasper Exp $ */
2 : /* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1995 Jason R. Thorpe. All rights reserved.
6 : * Copyright (c) 1982, 1986, 1988, 1993
7 : * The Regents of the University of California. All rights reserved.
8 : * (c) UNIX System Laboratories, Inc.
9 : * All or some portions of this file are derived from material licensed
10 : * to the University of California by American Telephone and Telegraph
11 : * Co. or Unix System Laboratories, Inc. and are reproduced herein with
12 : * the permission of UNIX System Laboratories, Inc.
13 : *
14 : * Redistribution and use in source and binary forms, with or without
15 : * modification, are permitted provided that the following conditions
16 : * are met:
17 : * 1. Redistributions of source code must retain the above copyright
18 : * notice, this list of conditions and the following disclaimer.
19 : * 2. Redistributions in binary form must reproduce the above copyright
20 : * notice, this list of conditions and the following disclaimer in the
21 : * documentation and/or other materials provided with the distribution.
22 : * 3. Neither the name of the University nor the names of its contributors
23 : * may be used to endorse or promote products derived from this software
24 : * without specific prior written permission.
25 : *
26 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 : * SUCH DAMAGE.
37 : *
38 : * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
39 : */
40 :
41 : #include <sys/param.h>
42 : #include <sys/systm.h>
43 : #include <sys/kernel.h>
44 : #include <sys/malloc.h>
45 : #include <sys/fcntl.h>
46 : #include <sys/buf.h>
47 : #include <sys/stat.h>
48 : #include <sys/syslog.h>
49 : #include <sys/device.h>
50 : #include <sys/time.h>
51 : #include <sys/disklabel.h>
52 : #include <sys/conf.h>
53 : #include <sys/lock.h>
54 : #include <sys/disk.h>
55 : #include <sys/reboot.h>
56 : #include <sys/dkio.h>
57 : #include <sys/vnode.h>
58 : #include <sys/task.h>
59 : #include <sys/stdint.h>
60 :
61 : #include <sys/socket.h>
62 : #include <sys/socketvar.h>
63 :
64 : #include <net/if.h>
65 :
66 : #include <dev/rndvar.h>
67 : #include <dev/cons.h>
68 :
69 : #include <lib/libz/zlib.h>
70 :
71 : #include "softraid.h"
72 :
73 : #ifdef DEBUG
74 : #define DPRINTF(x...) printf(x)
75 : #else
76 : #define DPRINTF(x...)
77 : #endif
78 :
79 : /*
80 : * A global list of all disks attached to the system. May grow or
81 : * shrink over time.
82 : */
83 : struct disklist_head disklist; /* TAILQ_HEAD */
84 : int disk_count; /* number of drives in global disklist */
85 : int disk_change; /* set if a disk has been attached/detached
86 : * since last we looked at this variable. This
87 : * is reset by hw_sysctl()
88 : */
89 :
90 : #define DUID_SIZE 8
91 :
92 : u_char bootduid[DUID_SIZE]; /* DUID of boot disk. */
93 : u_char rootduid[DUID_SIZE]; /* DUID of root disk. */
94 :
95 : /* softraid callback, do not use! */
96 : void (*softraid_disk_attach)(struct disk *, int);
97 :
98 : void sr_map_root(void);
99 :
100 : struct disk_attach_task {
101 : struct task task;
102 : struct disk *dk;
103 : };
104 :
105 : void disk_attach_callback(void *);
106 :
107 : int spoofgptlabel(struct buf *, void (*)(struct buf *), struct disklabel *);
108 :
109 : int gpt_chk_mbr(struct dos_partition *, u_int64_t);
110 : int gpt_chk_hdr(struct gpt_header *, struct disklabel *);
111 : int gpt_chk_parts(struct gpt_header *, struct gpt_partition *);
112 : int gpt_get_fstype(struct uuid *);
113 :
114 : int duid_equal(u_char *, u_char *);
115 :
116 : /*
117 : * Compute checksum for disk label.
118 : */
119 : u_int
120 0 : dkcksum(struct disklabel *lp)
121 : {
122 : u_int16_t *start, *end;
123 : u_int16_t sum = 0;
124 :
125 0 : start = (u_int16_t *)lp;
126 0 : end = (u_int16_t *)&lp->d_partitions[lp->d_npartitions];
127 0 : while (start < end)
128 0 : sum ^= *start++;
129 0 : return (sum);
130 : }
131 :
132 : int
133 0 : initdisklabel(struct disklabel *lp)
134 : {
135 : int i;
136 :
137 : /* minimal requirements for archetypal disk label */
138 0 : if (lp->d_secsize < DEV_BSIZE)
139 0 : lp->d_secsize = DEV_BSIZE;
140 0 : if (DL_GETDSIZE(lp) == 0)
141 0 : DL_SETDSIZE(lp, MAXDISKSIZE);
142 0 : if (lp->d_secpercyl == 0)
143 0 : return (ERANGE);
144 0 : lp->d_npartitions = MAXPARTITIONS;
145 0 : for (i = 0; i < RAW_PART; i++) {
146 0 : DL_SETPSIZE(&lp->d_partitions[i], 0);
147 0 : DL_SETPOFFSET(&lp->d_partitions[i], 0);
148 : }
149 0 : if (DL_GETPSIZE(&lp->d_partitions[RAW_PART]) == 0)
150 0 : DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
151 0 : DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0);
152 0 : DL_SETBSTART(lp, 0);
153 0 : DL_SETBEND(lp, DL_GETDSIZE(lp));
154 0 : lp->d_version = 1;
155 0 : lp->d_bbsize = 8192;
156 0 : lp->d_sbsize = 64*1024; /* XXX ? */
157 0 : return (0);
158 0 : }
159 :
160 : /*
161 : * Check an incoming block to make sure it is a disklabel, convert it to
162 : * a newer version if needed, etc etc.
163 : */
164 : int
165 0 : checkdisklabel(void *rlp, struct disklabel *lp, u_int64_t boundstart,
166 : u_int64_t boundend)
167 : {
168 0 : struct disklabel *dlp = rlp;
169 : struct __partitionv0 *v0pp;
170 : struct partition *pp;
171 : u_int64_t disksize;
172 : int error = 0;
173 : int i;
174 :
175 0 : if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
176 0 : error = ENOENT; /* no disk label */
177 0 : else if (dlp->d_npartitions > MAXPARTITIONS)
178 0 : error = E2BIG; /* too many partitions */
179 0 : else if (dlp->d_secpercyl == 0)
180 0 : error = EINVAL; /* invalid label */
181 0 : else if (dlp->d_secsize == 0)
182 0 : error = ENOSPC; /* disk too small */
183 0 : else if (dkcksum(dlp) != 0)
184 0 : error = EINVAL; /* incorrect checksum */
185 :
186 0 : if (error) {
187 : u_int16_t *start, *end, sum = 0;
188 :
189 : /* If it is byte-swapped, attempt to convert it */
190 0 : if (swap32(dlp->d_magic) != DISKMAGIC ||
191 0 : swap32(dlp->d_magic2) != DISKMAGIC ||
192 0 : swap16(dlp->d_npartitions) > MAXPARTITIONS)
193 0 : return (error);
194 :
195 : /*
196 : * Need a byte-swap aware dkcksum variant
197 : * inlined, because dkcksum uses a sub-field
198 : */
199 0 : start = (u_int16_t *)dlp;
200 0 : end = (u_int16_t *)&dlp->d_partitions[
201 : swap16(dlp->d_npartitions)];
202 0 : while (start < end)
203 0 : sum ^= *start++;
204 0 : if (sum != 0)
205 0 : return (error);
206 :
207 0 : dlp->d_magic = swap32(dlp->d_magic);
208 0 : dlp->d_type = swap16(dlp->d_type);
209 :
210 : /* d_typename and d_packname are strings */
211 :
212 0 : dlp->d_secsize = swap32(dlp->d_secsize);
213 0 : dlp->d_nsectors = swap32(dlp->d_nsectors);
214 0 : dlp->d_ntracks = swap32(dlp->d_ntracks);
215 0 : dlp->d_ncylinders = swap32(dlp->d_ncylinders);
216 0 : dlp->d_secpercyl = swap32(dlp->d_secpercyl);
217 0 : dlp->d_secperunit = swap32(dlp->d_secperunit);
218 :
219 : /* d_uid is a string */
220 :
221 0 : dlp->d_acylinders = swap32(dlp->d_acylinders);
222 :
223 0 : dlp->d_flags = swap32(dlp->d_flags);
224 :
225 0 : for (i = 0; i < NDDATA; i++)
226 0 : dlp->d_drivedata[i] = swap32(dlp->d_drivedata[i]);
227 :
228 0 : dlp->d_secperunith = swap16(dlp->d_secperunith);
229 0 : dlp->d_version = swap16(dlp->d_version);
230 :
231 0 : for (i = 0; i < NSPARE; i++)
232 0 : dlp->d_spare[i] = swap32(dlp->d_spare[i]);
233 :
234 0 : dlp->d_magic2 = swap32(dlp->d_magic2);
235 :
236 0 : dlp->d_npartitions = swap16(dlp->d_npartitions);
237 0 : dlp->d_bbsize = swap32(dlp->d_bbsize);
238 0 : dlp->d_sbsize = swap32(dlp->d_sbsize);
239 :
240 0 : for (i = 0; i < MAXPARTITIONS; i++) {
241 0 : pp = &dlp->d_partitions[i];
242 0 : pp->p_size = swap32(pp->p_size);
243 0 : pp->p_offset = swap32(pp->p_offset);
244 0 : if (dlp->d_version == 0) {
245 0 : v0pp = (struct __partitionv0 *)pp;
246 0 : v0pp->p_fsize = swap32(v0pp->p_fsize);
247 0 : } else {
248 0 : pp->p_offseth = swap16(pp->p_offseth);
249 0 : pp->p_sizeh = swap16(pp->p_sizeh);
250 : }
251 0 : pp->p_cpg = swap16(pp->p_cpg);
252 : }
253 :
254 0 : dlp->d_checksum = 0;
255 0 : dlp->d_checksum = dkcksum(dlp);
256 : error = 0;
257 0 : }
258 :
259 : /* XXX should verify lots of other fields and whine a lot */
260 :
261 : /* Initial passed in lp contains the real disk size. */
262 0 : disksize = DL_GETDSIZE(lp);
263 :
264 0 : if (lp != dlp)
265 0 : *lp = *dlp;
266 :
267 0 : if (lp->d_version == 0) {
268 0 : lp->d_version = 1;
269 0 : lp->d_secperunith = 0;
270 :
271 0 : v0pp = (struct __partitionv0 *)lp->d_partitions;
272 : pp = lp->d_partitions;
273 0 : for (i = 0; i < lp->d_npartitions; i++, pp++, v0pp++) {
274 0 : pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(v0pp->
275 : p_fsize, v0pp->p_frag);
276 0 : pp->p_offseth = 0;
277 0 : pp->p_sizeh = 0;
278 : }
279 : }
280 :
281 : #ifdef DEBUG
282 : if (DL_GETDSIZE(lp) != disksize)
283 : printf("on-disk disklabel has incorrect disksize (%llu)\n",
284 : DL_GETDSIZE(lp));
285 : if (DL_GETPSIZE(&lp->d_partitions[RAW_PART]) != disksize)
286 : printf("on-disk disklabel RAW_PART has incorrect size (%llu)\n",
287 : DL_GETPSIZE(&lp->d_partitions[RAW_PART]));
288 : if (DL_GETPOFFSET(&lp->d_partitions[RAW_PART]) != 0)
289 : printf("on-disk disklabel RAW_PART offset != 0 (%llu)\n",
290 : DL_GETPOFFSET(&lp->d_partitions[RAW_PART]));
291 : #endif
292 0 : DL_SETDSIZE(lp, disksize);
293 0 : DL_SETPSIZE(&lp->d_partitions[RAW_PART], disksize);
294 0 : DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0);
295 0 : DL_SETBSTART(lp, boundstart);
296 0 : DL_SETBEND(lp, boundend < DL_GETDSIZE(lp) ? boundend : DL_GETDSIZE(lp));
297 :
298 0 : lp->d_checksum = 0;
299 0 : lp->d_checksum = dkcksum(lp);
300 0 : return (0);
301 0 : }
302 :
303 : /*
304 : * Read a disk sector.
305 : */
306 : int
307 0 : readdisksector(struct buf *bp, void (*strat)(struct buf *),
308 : struct disklabel *lp, u_int64_t sector)
309 : {
310 0 : bp->b_blkno = DL_SECTOBLK(lp, sector);
311 0 : bp->b_bcount = lp->d_secsize;
312 0 : bp->b_error = 0;
313 0 : CLR(bp->b_flags, B_READ | B_WRITE | B_DONE | B_ERROR);
314 0 : SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
315 :
316 0 : (*strat)(bp);
317 :
318 0 : return (biowait(bp));
319 : }
320 :
321 : /*
322 : * If dos partition table requested, attempt to load it and
323 : * find disklabel inside a DOS partition. Return buffer
324 : * for use in signalling errors if requested.
325 : *
326 : * We would like to check if each MBR has a valid BOOT_MAGIC, but
327 : * we cannot because it doesn't always exist. So.. we assume the
328 : * MBR is valid.
329 : */
330 : int
331 0 : readdoslabel(struct buf *bp, void (*strat)(struct buf *),
332 : struct disklabel *lp, daddr_t *partoffp, int spoofonly)
333 : {
334 : struct disklabel *gptlp;
335 0 : u_int64_t dospartoff = 0, dospartend = DL_GETBEND(lp);
336 : int i, ourpart = -1, wander = 1, n = 0, loop = 0, offset;
337 0 : struct dos_partition dp[NDOSPART], *dp2;
338 : u_int64_t sector = DOSBBSECTOR;
339 : u_int32_t extoff = 0;
340 : int error;
341 :
342 0 : if (lp->d_secpercyl == 0)
343 0 : return (EINVAL); /* invalid label */
344 0 : if (lp->d_secsize == 0)
345 0 : return (ENOSPC); /* disk too small */
346 :
347 : /* do DOS partitions in the process of getting disklabel? */
348 :
349 : /*
350 : * Read dos partition table, follow extended partitions.
351 : * Map the partitions to disklabel entries i-p
352 : */
353 0 : while (wander && loop < DOS_MAXEBR) {
354 0 : loop++;
355 : wander = 0;
356 0 : if (sector < extoff)
357 0 : sector = extoff;
358 :
359 : /* read MBR/EBR */
360 0 : error = readdisksector(bp, strat, lp, sector);
361 0 : if (error) {
362 0 : /*wrong*/ if (partoffp)
363 0 : /*wrong*/ *partoffp = -1;
364 0 : return (error);
365 : }
366 :
367 0 : bcopy(bp->b_data + DOSPARTOFF, dp, sizeof(dp));
368 :
369 0 : if (n == 0 && sector == DOSBBSECTOR) {
370 : u_int16_t mbrtest;
371 :
372 : /* Check the end of sector marker. */
373 0 : mbrtest = ((bp->b_data[510] << 8) & 0xff00) |
374 0 : (bp->b_data[511] & 0xff);
375 0 : if (mbrtest != 0x55aa)
376 0 : goto notmbr;
377 :
378 0 : if (gpt_chk_mbr(dp, DL_GETDSIZE(lp)) != 0)
379 0 : goto notgpt;
380 :
381 0 : gptlp = malloc(sizeof(struct disklabel), M_DEVBUF,
382 : M_NOWAIT);
383 0 : if (gptlp == NULL)
384 0 : return (ENOMEM);
385 0 : *gptlp = *lp;
386 0 : error = spoofgptlabel(bp, strat, gptlp);
387 0 : if (error == 0) {
388 0 : dospartoff = DL_GETBSTART(gptlp);
389 0 : dospartend = DL_GETBEND(gptlp);
390 0 : if (partoffp == 0)
391 0 : *lp = *gptlp;
392 0 : free(gptlp, M_DEVBUF,
393 : sizeof(struct disklabel));
394 0 : if (partoffp && dospartoff == 0)
395 0 : return (ENXIO);
396 0 : goto notfat;
397 : } else {
398 0 : free(gptlp, M_DEVBUF,
399 : sizeof(struct disklabel));
400 0 : goto notmbr;
401 : }
402 : }
403 :
404 : notgpt:
405 0 : if (ourpart == -1) {
406 : /* Search for our MBR partition */
407 0 : for (dp2=dp, i=0; i < NDOSPART && ourpart == -1;
408 0 : i++, dp2++)
409 0 : if (letoh32(dp2->dp_size) &&
410 0 : dp2->dp_typ == DOSPTYP_OPENBSD)
411 0 : ourpart = i;
412 0 : if (ourpart == -1)
413 : goto donot;
414 : /*
415 : * This is our MBR partition. need sector
416 : * address for SCSI/IDE, cylinder for
417 : * ESDI/ST506/RLL
418 : */
419 0 : dp2 = &dp[ourpart];
420 0 : dospartoff = letoh32(dp2->dp_start) + sector;
421 0 : dospartend = dospartoff + letoh32(dp2->dp_size);
422 :
423 : /*
424 : * Record the OpenBSD partition's placement (in
425 : * 512-byte blocks!) for the caller. No need to
426 : * finish spoofing.
427 : */
428 0 : if (partoffp) {
429 0 : *partoffp = DL_SECTOBLK(lp, dospartoff);
430 0 : return (0);
431 : }
432 :
433 0 : if (lp->d_ntracks == 0)
434 0 : lp->d_ntracks = dp2->dp_ehd + 1;
435 0 : if (lp->d_nsectors == 0)
436 0 : lp->d_nsectors = DPSECT(dp2->dp_esect);
437 0 : if (lp->d_secpercyl == 0)
438 0 : lp->d_secpercyl = lp->d_ntracks *
439 0 : lp->d_nsectors;
440 : }
441 : donot:
442 : /*
443 : * In case the disklabel read below fails, we want to
444 : * provide a fake label in i-p.
445 : */
446 0 : for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
447 : struct partition *pp;
448 : u_int8_t fstype;
449 :
450 0 : if (dp2->dp_typ == DOSPTYP_OPENBSD ||
451 0 : dp2->dp_typ == DOSPTYP_EFI)
452 0 : continue;
453 0 : if (letoh32(dp2->dp_size) > DL_GETDSIZE(lp))
454 0 : continue;
455 0 : if (letoh32(dp2->dp_start) > DL_GETDSIZE(lp))
456 0 : continue;
457 0 : if (letoh32(dp2->dp_size) == 0)
458 0 : continue;
459 :
460 0 : switch (dp2->dp_typ) {
461 : case DOSPTYP_UNUSED:
462 : fstype = FS_UNUSED;
463 0 : break;
464 :
465 : case DOSPTYP_LINUX:
466 : fstype = FS_EXT2FS;
467 0 : break;
468 :
469 : case DOSPTYP_NTFS:
470 : fstype = FS_NTFS;
471 0 : break;
472 :
473 : case DOSPTYP_EFISYS:
474 : case DOSPTYP_FAT12:
475 : case DOSPTYP_FAT16S:
476 : case DOSPTYP_FAT16B:
477 : case DOSPTYP_FAT16L:
478 : case DOSPTYP_FAT32:
479 : case DOSPTYP_FAT32L:
480 : fstype = FS_MSDOS;
481 0 : break;
482 : case DOSPTYP_EXTEND:
483 : case DOSPTYP_EXTENDL:
484 0 : sector = letoh32(dp2->dp_start) + extoff;
485 0 : if (!extoff) {
486 : extoff = letoh32(dp2->dp_start);
487 : sector = 0;
488 0 : }
489 : wander = 1;
490 0 : continue;
491 : break;
492 : default:
493 : fstype = FS_OTHER;
494 0 : break;
495 : }
496 :
497 : /*
498 : * Don't set fstype/offset/size when just looking for
499 : * the offset of the OpenBSD partition. It would
500 : * invalidate the disklabel checksum!
501 : *
502 : * Don't try to spoof more than 8 partitions, i.e.
503 : * 'i' -'p'.
504 : */
505 0 : if (partoffp || n >= 8)
506 0 : continue;
507 :
508 0 : pp = &lp->d_partitions[8+n];
509 0 : n++;
510 0 : pp->p_fstype = fstype;
511 0 : if (letoh32(dp2->dp_start))
512 0 : DL_SETPOFFSET(pp,
513 : letoh32(dp2->dp_start) + sector);
514 0 : DL_SETPSIZE(pp, letoh32(dp2->dp_size));
515 0 : }
516 : }
517 :
518 : notmbr:
519 0 : if (n == 0 && sector == DOSBBSECTOR && ourpart == -1) {
520 : u_int16_t fattest;
521 :
522 : /* Check for a valid initial jmp instruction. */
523 0 : switch ((u_int8_t)bp->b_data[0]) {
524 : case 0xeb:
525 : /*
526 : * Two-byte jmp instruction. The 2nd byte is the number
527 : * of bytes to jmp and the 3rd byte must be a NOP.
528 : */
529 0 : if ((u_int8_t)bp->b_data[2] != 0x90)
530 0 : goto notfat;
531 : break;
532 : case 0xe9:
533 : /*
534 : * Three-byte jmp instruction. The next two bytes are a
535 : * little-endian 16 bit value.
536 : */
537 : break;
538 : default:
539 0 : goto notfat;
540 : break;
541 : }
542 :
543 : /* Check for a valid bytes per sector value. */
544 0 : fattest = ((bp->b_data[12] << 8) & 0xff00) |
545 0 : (bp->b_data[11] & 0xff);
546 0 : if (fattest < 512 || fattest > 4096 || (fattest % 512 != 0))
547 0 : goto notfat;
548 :
549 0 : if (partoffp)
550 0 : return (ENXIO); /* No place for disklabel on FAT! */
551 :
552 0 : DL_SETPSIZE(&lp->d_partitions['i' - 'a'],
553 : DL_GETPSIZE(&lp->d_partitions[RAW_PART]));
554 0 : DL_SETPOFFSET(&lp->d_partitions['i' - 'a'], 0);
555 0 : lp->d_partitions['i' - 'a'].p_fstype = FS_MSDOS;
556 :
557 : spoofonly = 1; /* No disklabel to read from disk. */
558 0 : }
559 :
560 : notfat:
561 : /* record the OpenBSD partition's placement for the caller */
562 0 : if (partoffp)
563 0 : *partoffp = DL_SECTOBLK(lp, dospartoff);
564 : else {
565 0 : DL_SETBSTART(lp, dospartoff);
566 0 : DL_SETBEND(lp, (dospartend < DL_GETDSIZE(lp)) ? dospartend :
567 : DL_GETDSIZE(lp));
568 : }
569 :
570 : /* don't read the on-disk label if we are in spoofed-only mode */
571 0 : if (spoofonly)
572 0 : return (0);
573 :
574 0 : error = readdisksector(bp, strat, lp, dospartoff +
575 0 : DL_BLKTOSEC(lp, DOS_LABELSECTOR));
576 0 : if (error)
577 0 : return (bp->b_error);
578 :
579 0 : offset = DL_BLKOFFSET(lp, DOS_LABELSECTOR);
580 0 : error = checkdisklabel(bp->b_data + offset, lp,
581 0 : DL_GETBSTART((struct disklabel*)(bp->b_data+offset)),
582 0 : DL_GETBEND((struct disklabel *)(bp->b_data+offset)));
583 :
584 0 : return (error);
585 0 : }
586 :
587 : /*
588 : * Returns 0 if the MBR with the provided partition array is a GPT protective
589 : * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
590 : * one MBR partition, an EFI partition that either covers the whole disk or as
591 : * much of it as is possible with a 32bit size field.
592 : *
593 : * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
594 : */
595 : int
596 0 : gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
597 : {
598 : struct dos_partition *dp2;
599 : int efi, found, i;
600 : u_int32_t psize;
601 :
602 : found = efi = 0;
603 0 : for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
604 0 : if (dp2->dp_typ == DOSPTYP_UNUSED)
605 : continue;
606 0 : found++;
607 0 : if (dp2->dp_typ != DOSPTYP_EFI)
608 : continue;
609 0 : psize = letoh32(dp2->dp_size);
610 0 : if (psize == (dsize - 1) ||
611 0 : psize == UINT32_MAX) {
612 0 : if (letoh32(dp2->dp_start) == 1)
613 0 : efi++;
614 : }
615 : }
616 0 : if (found == 1 && efi == 1)
617 0 : return (0);
618 :
619 0 : return (1);
620 0 : }
621 :
622 : int
623 0 : gpt_chk_hdr(struct gpt_header *gh, struct disklabel *lp)
624 : {
625 : uint64_t ghpartlba;
626 : uint64_t ghlbaend, ghlbastart;
627 : uint32_t orig_gh_csum;
628 : uint32_t ghsize, ghpartsize, ghpartspersec;
629 :
630 0 : if (letoh64(gh->gh_sig) != GPTSIGNATURE)
631 0 : return (EINVAL);
632 :
633 0 : if (letoh32(gh->gh_rev) != GPTREVISION)
634 0 : return (EINVAL);
635 :
636 0 : ghsize = letoh32(gh->gh_size);
637 0 : ghpartsize = letoh32(gh->gh_part_size);
638 0 : ghpartspersec = lp->d_secsize / ghpartsize;
639 0 : ghpartlba = letoh64(gh->gh_part_lba);
640 0 : ghlbaend = letoh64(gh->gh_lba_end);
641 0 : ghlbastart = letoh64(gh->gh_lba_start);
642 :
643 0 : if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header))
644 0 : return (EINVAL);
645 :
646 0 : orig_gh_csum = gh->gh_csum;
647 0 : gh->gh_csum = 0;
648 0 : gh->gh_csum = crc32(0, (unsigned char *)gh, ghsize);
649 :
650 0 : if (orig_gh_csum != gh->gh_csum)
651 0 : return (EINVAL);
652 :
653 0 : if (ghlbastart >= DL_GETDSIZE(lp) ||
654 0 : ghlbaend >= DL_GETDSIZE(lp) ||
655 0 : ghpartlba >= DL_GETDSIZE(lp))
656 0 : return (EINVAL);
657 :
658 : /*
659 : * Size per partition entry shall be 128*(2**n) with n >= 0.
660 : * We don't support partition entries larger than block size.
661 : */
662 0 : if (ghpartsize % GPTMINPARTSIZE || ghpartsize > lp->d_secsize
663 0 : || ghpartspersec == 0) {
664 : DPRINTF("invalid partition size\n");
665 0 : return (EINVAL);
666 : }
667 :
668 : /* XXX: we don't support multiples of GPTMINPARTSIZE yet */
669 0 : if (ghpartsize != GPTMINPARTSIZE) {
670 : DPRINTF("partition sizes larger than %d bytes are not "
671 : "supported", GPTMINPARTSIZE);
672 0 : return (EINVAL);
673 : }
674 :
675 0 : if (letoh64(gh->gh_lba_alt) >= DL_GETDSIZE(lp)) {
676 : DPRINTF("alternate header's position is bogus\n");
677 0 : return (EINVAL);
678 : }
679 :
680 0 : return 0;
681 0 : }
682 :
683 : int
684 0 : gpt_chk_parts(struct gpt_header *gh, struct gpt_partition *gp)
685 : {
686 : u_int32_t checksum;
687 0 : checksum = crc32(0, (unsigned char *)gp,
688 0 : letoh32(gh->gh_part_num) * letoh32(gh->gh_part_size));
689 :
690 0 : if (checksum != gh->gh_part_csum)
691 0 : return (EINVAL);
692 :
693 0 : return 0;
694 0 : }
695 :
696 : int
697 0 : gpt_get_fstype(struct uuid *uuid_part)
698 : {
699 : static int init = 0;
700 : static struct uuid uuid_openbsd, uuid_msdos, uuid_chromefs,
701 : uuid_linux, uuid_hfs, uuid_unused, uuid_efi_system;
702 : static const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD;
703 : static const uint8_t gpt_uuid_msdos[] = GPT_UUID_MSDOS;
704 : static const uint8_t gpt_uuid_chromerootfs[] = GPT_UUID_CHROMEROOTFS;
705 : static const uint8_t gpt_uuid_linux[] = GPT_UUID_LINUX;
706 : static const uint8_t gpt_uuid_hfs[] = GPT_UUID_APPLE_HFS;
707 : static const uint8_t gpt_uuid_unused[] = GPT_UUID_UNUSED;
708 : static const uint8_t gpt_uuid_efi_system[] = GPT_UUID_EFI_SYSTEM;
709 :
710 0 : if (init == 0) {
711 0 : uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd);
712 0 : uuid_dec_be(gpt_uuid_msdos, &uuid_msdos);
713 0 : uuid_dec_be(gpt_uuid_chromerootfs, &uuid_chromefs);
714 0 : uuid_dec_be(gpt_uuid_linux, &uuid_linux);
715 0 : uuid_dec_be(gpt_uuid_hfs, &uuid_hfs);
716 0 : uuid_dec_be(gpt_uuid_unused, &uuid_unused);
717 0 : uuid_dec_be(gpt_uuid_efi_system, &uuid_efi_system);
718 0 : init = 1;
719 0 : }
720 :
721 0 : if (!memcmp(uuid_part, &uuid_unused, sizeof(struct uuid)))
722 0 : return FS_UNUSED;
723 0 : else if (!memcmp(uuid_part, &uuid_openbsd, sizeof(struct uuid)))
724 0 : return FS_BSDFFS;
725 0 : else if (!memcmp(uuid_part, &uuid_msdos, sizeof(struct uuid)))
726 0 : return FS_MSDOS;
727 0 : else if (!memcmp(uuid_part, &uuid_chromefs, sizeof(struct uuid)))
728 0 : return FS_EXT2FS;
729 0 : else if (!memcmp(uuid_part, &uuid_linux, sizeof(struct uuid)))
730 0 : return FS_EXT2FS;
731 0 : else if (!memcmp(uuid_part, &uuid_hfs, sizeof(struct uuid)))
732 0 : return FS_HFS;
733 0 : else if (!memcmp(uuid_part, &uuid_efi_system, sizeof(struct uuid)))
734 0 : return FS_MSDOS;
735 : else
736 0 : return FS_OTHER;
737 0 : }
738 :
739 : /*
740 : * Spoof a disklabel based on the GPT information on the disk.
741 : */
742 : int
743 0 : spoofgptlabel(struct buf *bp, void (*strat)(struct buf *),
744 : struct disklabel *lp)
745 : {
746 : static const u_int8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD;
747 0 : struct gpt_header gh;
748 0 : struct uuid uuid_part, uuid_openbsd;
749 : struct gpt_partition *gp, *gp_tmp;
750 : struct partition *pp;
751 : size_t gpsz;
752 : u_int64_t ghlbaend, ghlbastart, gptpartoff, gptpartend, sector;
753 : u_int64_t start, end;
754 : int i, altheader = 0, error, n;
755 : uint32_t ghpartnum;
756 :
757 0 : uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd);
758 :
759 0 : for (sector = GPTSECTOR; ; sector = DL_GETDSIZE(lp)-1, altheader = 1) {
760 : uint64_t ghpartlba;
761 : uint32_t ghpartsize;
762 : uint32_t ghpartspersec;
763 :
764 0 : error = readdisksector(bp, strat, lp, sector);
765 0 : if (error) {
766 : DPRINTF("error reading from disk\n");
767 0 : return (error);
768 : }
769 :
770 0 : bcopy(bp->b_data, &gh, sizeof(gh));
771 :
772 0 : if (gpt_chk_hdr(&gh, lp)) {
773 0 : if (altheader) {
774 : DPRINTF("alternate header also broken\n");
775 0 : return (EINVAL);
776 : }
777 0 : continue;
778 : }
779 :
780 0 : ghpartsize = letoh32(gh.gh_part_size);
781 0 : ghpartspersec = lp->d_secsize / ghpartsize;
782 0 : ghpartnum = letoh32(gh.gh_part_num);
783 0 : ghpartlba = letoh64(gh.gh_part_lba);
784 0 : ghlbaend = letoh64(gh.gh_lba_end);
785 0 : ghlbastart = letoh64(gh.gh_lba_start);
786 :
787 : /* read GPT partition entry array */
788 0 : gp = mallocarray(ghpartnum, sizeof(struct gpt_partition),
789 : M_DEVBUF, M_NOWAIT|M_ZERO);
790 0 : if (gp == NULL)
791 0 : return (ENOMEM);
792 0 : gpsz = ghpartnum * sizeof(struct gpt_partition);
793 :
794 : /*
795 : * XXX: Fails if # of partition entries is not a multiple of
796 : * ghpartspersec.
797 : */
798 : sector = ghpartlba;
799 0 : for (i = 0; i < ghpartnum / ghpartspersec; i++, sector++) {
800 0 : error = readdisksector(bp, strat, lp, sector);
801 0 : if (error) {
802 0 : free(gp, M_DEVBUF, gpsz);
803 0 : return (error);
804 : }
805 :
806 0 : bcopy(bp->b_data, gp + i * ghpartspersec,
807 0 : ghpartspersec * sizeof(struct gpt_partition));
808 : }
809 :
810 0 : if (gpt_chk_parts(&gh, gp)) {
811 0 : free(gp, M_DEVBUF, gpsz);
812 0 : if (altheader) {
813 : DPRINTF("alternate partition entries are also "
814 : "broken\n");
815 0 : return (EINVAL);
816 : }
817 0 : continue;
818 : }
819 0 : break;
820 : }
821 :
822 : /* Find OpenBSD partition and spoof others along the way. */
823 : n = 0;
824 : gptpartoff = 0;
825 0 : gptpartend = DL_GETBEND(lp);
826 0 : for (gp_tmp = gp, i = 0; i < ghpartnum; gp_tmp++, i++) {
827 0 : start = letoh64(gp_tmp->gp_lba_start);
828 0 : end = letoh64(gp_tmp->gp_lba_end);
829 0 : if (start > end || start < ghlbastart || end > ghlbaend)
830 : continue; /* entry invalid */
831 :
832 0 : uuid_dec_le(&gp_tmp->gp_type, &uuid_part);
833 0 : if (!memcmp(&uuid_part, &uuid_openbsd, sizeof(struct uuid))) {
834 0 : if (gptpartoff == 0) {
835 : gptpartoff = start;
836 0 : gptpartend = end + 1;
837 0 : }
838 : continue; /* Do *NOT* spoof OpenBSD partitions! */
839 : }
840 :
841 : /*
842 : * Don't try to spoof more than 8 partitions, i.e.
843 : * 'i' -'p'.
844 : */
845 0 : if (n >= 8)
846 : continue;
847 :
848 0 : pp = &lp->d_partitions[8+n];
849 0 : n++;
850 0 : pp->p_fstype = gpt_get_fstype(&uuid_part);
851 0 : DL_SETPOFFSET(pp, start);
852 0 : DL_SETPSIZE(pp, end - start + 1);
853 0 : }
854 :
855 0 : free(gp, M_DEVBUF, gpsz);
856 :
857 0 : DL_SETBSTART(lp, gptpartoff);
858 0 : DL_SETBEND(lp, (gptpartend < DL_GETDSIZE(lp)) ? gptpartend :
859 : DL_GETDSIZE(lp));
860 :
861 0 : return (0);
862 0 : }
863 :
864 : /*
865 : * Check new disk label for sensibility before setting it.
866 : */
867 : int
868 0 : setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_int openmask)
869 : {
870 : struct partition *opp, *npp;
871 : struct disk *dk;
872 : int i;
873 :
874 : /* sanity clause */
875 0 : if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 ||
876 0 : (nlp->d_secsize % DEV_BSIZE) != 0)
877 0 : return (EINVAL);
878 :
879 : /* special case to allow disklabel to be invalidated */
880 0 : if (nlp->d_magic == 0xffffffff) {
881 0 : *olp = *nlp;
882 0 : return (0);
883 : }
884 :
885 0 : if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
886 0 : dkcksum(nlp) != 0)
887 0 : return (EINVAL);
888 :
889 : /* XXX missing check if other dos partitions will be overwritten */
890 :
891 0 : for (i = 0; i < MAXPARTITIONS; i++) {
892 0 : opp = &olp->d_partitions[i];
893 0 : npp = &nlp->d_partitions[i];
894 0 : if ((openmask & (1 << i)) &&
895 0 : (DL_GETPOFFSET(npp) != DL_GETPOFFSET(opp) ||
896 0 : DL_GETPSIZE(npp) < DL_GETPSIZE(opp)))
897 0 : return (EBUSY);
898 : /*
899 : * Copy internally-set partition information
900 : * if new label doesn't include it. XXX
901 : */
902 0 : if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
903 0 : npp->p_fragblock = opp->p_fragblock;
904 0 : npp->p_cpg = opp->p_cpg;
905 0 : }
906 : }
907 :
908 : /* Generate a UID if the disklabel does not already have one. */
909 0 : if (duid_iszero(nlp->d_uid)) {
910 0 : do {
911 0 : arc4random_buf(nlp->d_uid, sizeof(nlp->d_uid));
912 0 : TAILQ_FOREACH(dk, &disklist, dk_link)
913 0 : if (dk->dk_label &&
914 0 : duid_equal(dk->dk_label->d_uid, nlp->d_uid))
915 : break;
916 0 : } while (dk != NULL || duid_iszero(nlp->d_uid));
917 : }
918 :
919 : /* Preserve the disk size and RAW_PART values. */
920 0 : DL_SETDSIZE(nlp, DL_GETDSIZE(olp));
921 0 : npp = &nlp->d_partitions[RAW_PART];
922 0 : DL_SETPOFFSET(npp, 0);
923 0 : DL_SETPSIZE(npp, DL_GETDSIZE(nlp));
924 :
925 0 : nlp->d_checksum = 0;
926 0 : nlp->d_checksum = dkcksum(nlp);
927 0 : *olp = *nlp;
928 :
929 0 : disk_change = 1;
930 :
931 0 : return (0);
932 0 : }
933 :
934 : /*
935 : * Determine the size of the transfer, and make sure it is within the
936 : * boundaries of the partition. Adjust transfer if needed, and signal errors or
937 : * early completion.
938 : */
939 : int
940 0 : bounds_check_with_label(struct buf *bp, struct disklabel *lp)
941 : {
942 0 : struct partition *p = &lp->d_partitions[DISKPART(bp->b_dev)];
943 : daddr_t partblocks, sz;
944 :
945 : /* Avoid division by zero, negative offsets, and negative sizes. */
946 0 : if (lp->d_secpercyl == 0 || bp->b_blkno < 0 || bp->b_bcount < 0)
947 : goto bad;
948 :
949 : /* Ensure transfer is a whole number of aligned sectors. */
950 0 : if ((bp->b_blkno % DL_BLKSPERSEC(lp)) != 0 ||
951 0 : (bp->b_bcount % lp->d_secsize) != 0)
952 : goto bad;
953 :
954 : /* Ensure transfer starts within partition boundary. */
955 0 : partblocks = DL_SECTOBLK(lp, DL_GETPSIZE(p));
956 0 : if (bp->b_blkno > partblocks)
957 : goto bad;
958 :
959 : /* If exactly at end of partition or null transfer, return EOF. */
960 0 : if (bp->b_blkno == partblocks || bp->b_bcount == 0)
961 : goto done;
962 :
963 : /* Truncate request if it extends past the end of the partition. */
964 0 : sz = bp->b_bcount >> DEV_BSHIFT;
965 0 : if (sz > partblocks - bp->b_blkno) {
966 : sz = partblocks - bp->b_blkno;
967 0 : bp->b_bcount = sz << DEV_BSHIFT;
968 0 : }
969 :
970 0 : return (0);
971 :
972 : bad:
973 0 : bp->b_error = EINVAL;
974 0 : bp->b_flags |= B_ERROR;
975 : done:
976 0 : bp->b_resid = bp->b_bcount;
977 0 : return (-1);
978 0 : }
979 :
980 : /*
981 : * Disk error is the preface to plaintive error messages
982 : * about failing disk transfers. It prints messages of the form
983 :
984 : hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
985 :
986 : * if the offset of the error in the transfer and a disk label
987 : * are both available. blkdone should be -1 if the position of the error
988 : * is unknown; the disklabel pointer may be null from drivers that have not
989 : * been converted to use them. The message is printed with printf
990 : * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
991 : * The message should be completed (with at least a newline) with printf
992 : * or addlog, respectively. There is no trailing space.
993 : */
994 : void
995 0 : diskerr(struct buf *bp, char *dname, char *what, int pri, int blkdone,
996 : struct disklabel *lp)
997 : {
998 0 : int unit = DISKUNIT(bp->b_dev), part = DISKPART(bp->b_dev);
999 : int (*pr)(const char *, ...) __attribute__((__format__(__kprintf__,1,2)));
1000 0 : char partname = 'a' + part;
1001 : daddr_t sn;
1002 :
1003 0 : if (pri != LOG_PRINTF) {
1004 0 : log(pri, "%s", "");
1005 : pr = addlog;
1006 0 : } else
1007 : pr = printf;
1008 0 : (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
1009 0 : bp->b_flags & B_READ ? "read" : "writ");
1010 0 : sn = bp->b_blkno;
1011 0 : if (bp->b_bcount <= DEV_BSIZE)
1012 0 : (*pr)("%lld", (long long)sn);
1013 : else {
1014 0 : if (blkdone >= 0) {
1015 0 : sn += blkdone;
1016 0 : (*pr)("%lld of ", (long long)sn);
1017 0 : }
1018 0 : (*pr)("%lld-%lld", (long long)bp->b_blkno,
1019 0 : (long long)(bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE));
1020 : }
1021 0 : if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
1022 0 : sn += DL_SECTOBLK(lp, DL_GETPOFFSET(&lp->d_partitions[part]));
1023 0 : (*pr)(" (%s%d bn %lld; cn %lld", dname, unit, (long long)sn,
1024 0 : (long long)(sn / DL_SECTOBLK(lp, lp->d_secpercyl)));
1025 0 : sn %= DL_SECTOBLK(lp, lp->d_secpercyl);
1026 0 : (*pr)(" tn %lld sn %lld)",
1027 0 : (long long)(sn / DL_SECTOBLK(lp, lp->d_nsectors)),
1028 0 : (long long)(sn % DL_SECTOBLK(lp, lp->d_nsectors)));
1029 0 : }
1030 0 : }
1031 :
1032 : /*
1033 : * Initialize the disklist. Called by main() before autoconfiguration.
1034 : */
1035 : void
1036 0 : disk_init(void)
1037 : {
1038 :
1039 0 : TAILQ_INIT(&disklist);
1040 0 : disk_count = disk_change = 0;
1041 0 : }
1042 :
1043 : int
1044 0 : disk_construct(struct disk *diskp)
1045 : {
1046 0 : rw_init_flags(&diskp->dk_lock, "dklk", RWL_IS_VNODE);
1047 0 : mtx_init(&diskp->dk_mtx, IPL_BIO);
1048 :
1049 0 : diskp->dk_flags |= DKF_CONSTRUCTED;
1050 :
1051 0 : return (0);
1052 : }
1053 :
1054 : /*
1055 : * Attach a disk.
1056 : */
1057 : void
1058 0 : disk_attach(struct device *dv, struct disk *diskp)
1059 : {
1060 : int majdev;
1061 :
1062 0 : if (!ISSET(diskp->dk_flags, DKF_CONSTRUCTED))
1063 0 : disk_construct(diskp);
1064 :
1065 : /*
1066 : * Allocate and initialize the disklabel structures. Note that
1067 : * it's not safe to sleep here, since we're probably going to be
1068 : * called during autoconfiguration.
1069 : */
1070 0 : diskp->dk_label = malloc(sizeof(struct disklabel), M_DEVBUF,
1071 : M_NOWAIT|M_ZERO);
1072 0 : if (diskp->dk_label == NULL)
1073 0 : panic("disk_attach: can't allocate storage for disklabel");
1074 :
1075 : /*
1076 : * Set the attached timestamp.
1077 : */
1078 0 : microuptime(&diskp->dk_attachtime);
1079 :
1080 : /*
1081 : * Link into the disklist.
1082 : */
1083 0 : TAILQ_INSERT_TAIL(&disklist, diskp, dk_link);
1084 0 : ++disk_count;
1085 0 : disk_change = 1;
1086 :
1087 : /*
1088 : * Store device structure and number for later use.
1089 : */
1090 0 : diskp->dk_device = dv;
1091 0 : diskp->dk_devno = NODEV;
1092 0 : if (dv != NULL) {
1093 0 : majdev = findblkmajor(dv);
1094 0 : if (majdev >= 0)
1095 0 : diskp->dk_devno =
1096 0 : MAKEDISKDEV(majdev, dv->dv_unit, RAW_PART);
1097 :
1098 0 : if (diskp->dk_devno != NODEV) {
1099 : struct disk_attach_task *dat;
1100 :
1101 0 : dat = malloc(sizeof(*dat), M_TEMP, M_WAITOK);
1102 :
1103 : /* XXX: Assumes dk is part of the device softc. */
1104 0 : device_ref(dv);
1105 0 : dat->dk = diskp;
1106 :
1107 0 : task_set(&dat->task, disk_attach_callback, dat);
1108 0 : task_add(systq, &dat->task);
1109 0 : }
1110 : }
1111 :
1112 0 : if (softraid_disk_attach)
1113 0 : softraid_disk_attach(diskp, 1);
1114 0 : }
1115 :
1116 : void
1117 0 : disk_attach_callback(void *xdat)
1118 : {
1119 0 : struct disk_attach_task *dat = xdat;
1120 0 : struct disk *dk = dat->dk;
1121 0 : struct disklabel dl;
1122 0 : char errbuf[100];
1123 :
1124 0 : free(dat, M_TEMP, sizeof(*dat));
1125 :
1126 0 : if (dk->dk_flags & (DKF_OPENED | DKF_NOLABELREAD))
1127 : goto done;
1128 :
1129 : /* Read disklabel. */
1130 0 : if (disk_readlabel(&dl, dk->dk_devno, errbuf, sizeof(errbuf)) == NULL) {
1131 0 : enqueue_randomness(dl.d_checksum);
1132 0 : dk->dk_flags |= DKF_LABELVALID;
1133 0 : }
1134 :
1135 : done:
1136 0 : dk->dk_flags |= DKF_OPENED;
1137 0 : device_unref(dk->dk_device);
1138 0 : wakeup(dk);
1139 0 : }
1140 :
1141 : /*
1142 : * Detach a disk.
1143 : */
1144 : void
1145 0 : disk_detach(struct disk *diskp)
1146 : {
1147 :
1148 0 : if (softraid_disk_attach)
1149 0 : softraid_disk_attach(diskp, -1);
1150 :
1151 : /*
1152 : * Free the space used by the disklabel structures.
1153 : */
1154 0 : free(diskp->dk_label, M_DEVBUF, sizeof(*diskp->dk_label));
1155 :
1156 : /*
1157 : * Remove from the disklist.
1158 : */
1159 0 : TAILQ_REMOVE(&disklist, diskp, dk_link);
1160 0 : disk_change = 1;
1161 0 : if (--disk_count < 0)
1162 0 : panic("disk_detach: disk_count < 0");
1163 0 : }
1164 :
1165 : int
1166 0 : disk_openpart(struct disk *dk, int part, int fmt, int haslabel)
1167 : {
1168 0 : KASSERT(part >= 0 && part < MAXPARTITIONS);
1169 :
1170 : /* Unless opening the raw partition, check that the partition exists. */
1171 0 : if (part != RAW_PART && (!haslabel ||
1172 0 : part >= dk->dk_label->d_npartitions ||
1173 0 : dk->dk_label->d_partitions[part].p_fstype == FS_UNUSED))
1174 0 : return (ENXIO);
1175 :
1176 : /* Ensure the partition doesn't get changed under our feet. */
1177 0 : switch (fmt) {
1178 : case S_IFCHR:
1179 0 : dk->dk_copenmask |= (1 << part);
1180 0 : break;
1181 : case S_IFBLK:
1182 0 : dk->dk_bopenmask |= (1 << part);
1183 0 : break;
1184 : }
1185 0 : dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
1186 :
1187 0 : return (0);
1188 0 : }
1189 :
1190 : void
1191 0 : disk_closepart(struct disk *dk, int part, int fmt)
1192 : {
1193 0 : KASSERT(part >= 0 && part < MAXPARTITIONS);
1194 :
1195 0 : switch (fmt) {
1196 : case S_IFCHR:
1197 0 : dk->dk_copenmask &= ~(1 << part);
1198 0 : break;
1199 : case S_IFBLK:
1200 0 : dk->dk_bopenmask &= ~(1 << part);
1201 0 : break;
1202 : }
1203 0 : dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
1204 0 : }
1205 :
1206 : void
1207 0 : disk_gone(int (*open)(dev_t, int, int, struct proc *), int unit)
1208 : {
1209 : int bmaj, cmaj, mn;
1210 :
1211 : /* Locate the lowest minor number to be detached. */
1212 0 : mn = DISKMINOR(unit, 0);
1213 :
1214 0 : for (bmaj = 0; bmaj < nblkdev; bmaj++)
1215 0 : if (bdevsw[bmaj].d_open == open)
1216 0 : vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
1217 0 : for (cmaj = 0; cmaj < nchrdev; cmaj++)
1218 0 : if (cdevsw[cmaj].d_open == open)
1219 0 : vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
1220 0 : }
1221 :
1222 : /*
1223 : * Increment a disk's busy counter. If the counter is going from
1224 : * 0 to 1, set the timestamp.
1225 : */
1226 : void
1227 0 : disk_busy(struct disk *diskp)
1228 : {
1229 :
1230 : /*
1231 : * XXX We'd like to use something as accurate as microtime(),
1232 : * but that doesn't depend on the system TOD clock.
1233 : */
1234 0 : mtx_enter(&diskp->dk_mtx);
1235 0 : if (diskp->dk_busy++ == 0)
1236 0 : microuptime(&diskp->dk_timestamp);
1237 0 : mtx_leave(&diskp->dk_mtx);
1238 0 : }
1239 :
1240 : /*
1241 : * Decrement a disk's busy counter, increment the byte count, total busy
1242 : * time, and reset the timestamp.
1243 : */
1244 : void
1245 0 : disk_unbusy(struct disk *diskp, long bcount, daddr_t blkno, int read)
1246 : {
1247 0 : struct timeval dv_time, diff_time;
1248 :
1249 0 : mtx_enter(&diskp->dk_mtx);
1250 :
1251 0 : if (diskp->dk_busy-- == 0)
1252 0 : printf("disk_unbusy: %s: dk_busy < 0\n", diskp->dk_name);
1253 :
1254 0 : microuptime(&dv_time);
1255 :
1256 0 : timersub(&dv_time, &diskp->dk_timestamp, &diff_time);
1257 0 : timeradd(&diskp->dk_time, &diff_time, &diskp->dk_time);
1258 :
1259 0 : diskp->dk_timestamp = dv_time;
1260 0 : if (bcount > 0) {
1261 0 : if (read) {
1262 0 : diskp->dk_rbytes += bcount;
1263 0 : diskp->dk_rxfer++;
1264 0 : } else {
1265 0 : diskp->dk_wbytes += bcount;
1266 0 : diskp->dk_wxfer++;
1267 : }
1268 : } else
1269 0 : diskp->dk_seek++;
1270 :
1271 0 : mtx_leave(&diskp->dk_mtx);
1272 :
1273 0 : enqueue_randomness(bcount ^ diff_time.tv_usec ^
1274 0 : (blkno >> 32) ^ (blkno & 0xffffffff));
1275 0 : }
1276 :
1277 : int
1278 0 : disk_lock(struct disk *dk)
1279 : {
1280 0 : return (rw_enter(&dk->dk_lock, RW_WRITE|RW_INTR));
1281 : }
1282 :
1283 : void
1284 0 : disk_lock_nointr(struct disk *dk)
1285 : {
1286 0 : rw_enter_write(&dk->dk_lock);
1287 0 : }
1288 :
1289 : void
1290 0 : disk_unlock(struct disk *dk)
1291 : {
1292 0 : rw_exit_write(&dk->dk_lock);
1293 0 : }
1294 :
1295 : int
1296 0 : dk_mountroot(void)
1297 : {
1298 0 : char errbuf[100];
1299 0 : int part = DISKPART(rootdev);
1300 : int (*mountrootfn)(void);
1301 0 : struct disklabel dl;
1302 : char *error;
1303 :
1304 0 : error = disk_readlabel(&dl, rootdev, errbuf, sizeof(errbuf));
1305 0 : if (error)
1306 0 : panic("%s", error);
1307 :
1308 0 : if (DL_GETPSIZE(&dl.d_partitions[part]) == 0)
1309 0 : panic("root filesystem has size 0");
1310 0 : switch (dl.d_partitions[part].p_fstype) {
1311 : #ifdef EXT2FS
1312 : case FS_EXT2FS:
1313 : {
1314 : extern int ext2fs_mountroot(void);
1315 : mountrootfn = ext2fs_mountroot;
1316 : }
1317 0 : break;
1318 : #endif
1319 : #ifdef FFS
1320 : case FS_BSDFFS:
1321 : {
1322 : extern int ffs_mountroot(void);
1323 : mountrootfn = ffs_mountroot;
1324 : }
1325 0 : break;
1326 : #endif
1327 : #ifdef CD9660
1328 : case FS_ISO9660:
1329 : {
1330 : extern int cd9660_mountroot(void);
1331 : mountrootfn = cd9660_mountroot;
1332 : }
1333 0 : break;
1334 : #endif
1335 : default:
1336 : #ifdef FFS
1337 : {
1338 : extern int ffs_mountroot(void);
1339 :
1340 0 : printf("filesystem type %d not known.. assuming ffs\n",
1341 : dl.d_partitions[part].p_fstype);
1342 : mountrootfn = ffs_mountroot;
1343 : }
1344 : #else
1345 : panic("disk 0x%x filesystem type %d not known",
1346 : rootdev, dl.d_partitions[part].p_fstype);
1347 : #endif
1348 0 : }
1349 0 : return (*mountrootfn)();
1350 0 : }
1351 :
1352 : struct device *
1353 0 : getdisk(char *str, int len, int defpart, dev_t *devp)
1354 : {
1355 : struct device *dv;
1356 :
1357 0 : if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
1358 0 : printf("use one of: exit");
1359 0 : TAILQ_FOREACH(dv, &alldevs, dv_list) {
1360 0 : if (dv->dv_class == DV_DISK)
1361 0 : printf(" %s[a-p]", dv->dv_xname);
1362 : #if defined(NFSCLIENT)
1363 0 : if (dv->dv_class == DV_IFNET)
1364 0 : printf(" %s", dv->dv_xname);
1365 : #endif
1366 : }
1367 0 : printf("\n");
1368 0 : }
1369 0 : return (dv);
1370 : }
1371 :
1372 : struct device *
1373 0 : parsedisk(char *str, int len, int defpart, dev_t *devp)
1374 : {
1375 : struct device *dv;
1376 : int majdev, part = defpart;
1377 : char c;
1378 :
1379 0 : if (len == 0)
1380 0 : return (NULL);
1381 0 : c = str[len-1];
1382 0 : if (c >= 'a' && (c - 'a') < MAXPARTITIONS) {
1383 : part = c - 'a';
1384 : len -= 1;
1385 0 : }
1386 :
1387 0 : TAILQ_FOREACH(dv, &alldevs, dv_list) {
1388 0 : if (dv->dv_class == DV_DISK &&
1389 0 : strncmp(str, dv->dv_xname, len) == 0 &&
1390 0 : dv->dv_xname[len] == '\0') {
1391 0 : majdev = findblkmajor(dv);
1392 0 : if (majdev < 0)
1393 0 : return NULL;
1394 0 : *devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
1395 0 : break;
1396 : }
1397 : #if defined(NFSCLIENT)
1398 0 : if (dv->dv_class == DV_IFNET &&
1399 0 : strncmp(str, dv->dv_xname, len) == 0 &&
1400 0 : dv->dv_xname[len] == '\0') {
1401 0 : *devp = NODEV;
1402 0 : break;
1403 : }
1404 : #endif
1405 : }
1406 :
1407 0 : return (dv);
1408 0 : }
1409 :
1410 : void
1411 0 : setroot(struct device *bootdv, int part, int exitflags)
1412 : {
1413 : int majdev, unit, len, s, slept = 0;
1414 : struct swdevt *swp;
1415 : struct device *rootdv, *dv;
1416 0 : dev_t nrootdev, nswapdev = NODEV, temp = NODEV;
1417 : struct ifnet *ifp = NULL;
1418 : struct disk *dk;
1419 0 : char buf[128];
1420 : #if defined(NFSCLIENT)
1421 : extern char *nfsbootdevname;
1422 : #endif
1423 :
1424 : /* Ensure that all disk attach callbacks have completed. */
1425 0 : do {
1426 0 : TAILQ_FOREACH(dk, &disklist, dk_link) {
1427 0 : if (dk->dk_devno != NODEV &&
1428 0 : (dk->dk_flags & DKF_OPENED) == 0) {
1429 0 : tsleep(dk, 0, "dkopen", hz);
1430 0 : slept++;
1431 0 : break;
1432 : }
1433 : }
1434 0 : } while (dk != NULL && slept < 5);
1435 :
1436 0 : if (slept == 5) {
1437 0 : printf("disklabels not read:");
1438 0 : TAILQ_FOREACH(dk, &disklist, dk_link)
1439 0 : if (dk->dk_devno != NODEV &&
1440 0 : (dk->dk_flags & DKF_OPENED) == 0)
1441 0 : printf(" %s", dk->dk_name);
1442 0 : printf("\n");
1443 0 : }
1444 :
1445 0 : if (duid_iszero(bootduid)) {
1446 : /* Locate DUID for boot disk since it was not provided. */
1447 0 : TAILQ_FOREACH(dk, &disklist, dk_link)
1448 0 : if (dk->dk_device == bootdv)
1449 : break;
1450 0 : if (dk && (dk->dk_flags & DKF_LABELVALID))
1451 0 : bcopy(dk->dk_label->d_uid, bootduid, sizeof(bootduid));
1452 0 : } else if (bootdv == NULL) {
1453 : /* Locate boot disk based on the provided DUID. */
1454 0 : TAILQ_FOREACH(dk, &disklist, dk_link)
1455 0 : if (duid_equal(dk->dk_label->d_uid, bootduid))
1456 : break;
1457 0 : if (dk && (dk->dk_flags & DKF_LABELVALID))
1458 0 : bootdv = dk->dk_device;
1459 : }
1460 0 : bcopy(bootduid, rootduid, sizeof(rootduid));
1461 :
1462 : #if NSOFTRAID > 0
1463 0 : sr_map_root();
1464 : #endif
1465 :
1466 : /*
1467 : * If `swap generic' and we couldn't determine boot device,
1468 : * ask the user.
1469 : */
1470 : dk = NULL;
1471 0 : if (mountroot == NULL && bootdv == NULL)
1472 0 : boothowto |= RB_ASKNAME;
1473 0 : if (boothowto & RB_ASKNAME) {
1474 0 : while (1) {
1475 0 : printf("root device");
1476 0 : if (bootdv != NULL) {
1477 0 : printf(" (default %s", bootdv->dv_xname);
1478 0 : if (bootdv->dv_class == DV_DISK)
1479 0 : printf("%c", 'a' + part);
1480 0 : printf(")");
1481 0 : }
1482 0 : printf(": ");
1483 0 : s = splhigh();
1484 0 : cnpollc(1);
1485 0 : len = getsn(buf, sizeof(buf));
1486 0 : cnpollc(0);
1487 0 : splx(s);
1488 0 : if (strcmp(buf, "exit") == 0)
1489 0 : reboot(exitflags);
1490 0 : if (len == 0 && bootdv != NULL) {
1491 0 : strlcpy(buf, bootdv->dv_xname, sizeof buf);
1492 0 : len = strlen(buf);
1493 0 : }
1494 0 : if (len > 0 && buf[len - 1] == '*') {
1495 0 : buf[--len] = '\0';
1496 0 : dv = getdisk(buf, len, part, &nrootdev);
1497 0 : if (dv != NULL) {
1498 : rootdv = dv;
1499 0 : nswapdev = nrootdev;
1500 0 : goto gotswap;
1501 : }
1502 : }
1503 0 : dv = getdisk(buf, len, part, &nrootdev);
1504 0 : if (dv != NULL) {
1505 : rootdv = dv;
1506 : break;
1507 : }
1508 : }
1509 :
1510 0 : if (rootdv->dv_class == DV_IFNET)
1511 : goto gotswap;
1512 :
1513 : /* try to build swap device out of new root device */
1514 0 : while (1) {
1515 0 : printf("swap device");
1516 0 : if (rootdv != NULL)
1517 0 : printf(" (default %s%s)", rootdv->dv_xname,
1518 0 : rootdv->dv_class == DV_DISK ? "b" : "");
1519 0 : printf(": ");
1520 0 : s = splhigh();
1521 0 : cnpollc(1);
1522 0 : len = getsn(buf, sizeof(buf));
1523 0 : cnpollc(0);
1524 0 : splx(s);
1525 0 : if (strcmp(buf, "exit") == 0)
1526 0 : reboot(exitflags);
1527 0 : if (len == 0 && rootdv != NULL) {
1528 0 : switch (rootdv->dv_class) {
1529 : case DV_IFNET:
1530 0 : nswapdev = NODEV;
1531 0 : break;
1532 : case DV_DISK:
1533 0 : nswapdev = MAKEDISKDEV(major(nrootdev),
1534 : DISKUNIT(nrootdev), 1);
1535 0 : if (nswapdev == nrootdev)
1536 0 : continue;
1537 : break;
1538 : default:
1539 : break;
1540 : }
1541 : break;
1542 : }
1543 0 : dv = getdisk(buf, len, 1, &nswapdev);
1544 0 : if (dv) {
1545 0 : if (dv->dv_class == DV_IFNET)
1546 0 : nswapdev = NODEV;
1547 0 : if (nswapdev == nrootdev)
1548 0 : continue;
1549 : break;
1550 : }
1551 : }
1552 : gotswap:
1553 0 : rootdev = nrootdev;
1554 0 : dumpdev = nswapdev;
1555 0 : swdevt[0].sw_dev = nswapdev;
1556 0 : swdevt[1].sw_dev = NODEV;
1557 : #if defined(NFSCLIENT)
1558 0 : } else if (mountroot == nfs_mountroot) {
1559 : rootdv = bootdv;
1560 0 : rootdev = dumpdev = swapdev = NODEV;
1561 : #endif
1562 0 : } else if (mountroot == NULL && rootdev == NODEV) {
1563 : /*
1564 : * `swap generic'
1565 : */
1566 : rootdv = bootdv;
1567 :
1568 0 : if (bootdv->dv_class == DV_DISK) {
1569 0 : if (!duid_iszero(rootduid)) {
1570 0 : TAILQ_FOREACH(dk, &disklist, dk_link)
1571 0 : if ((dk->dk_flags & DKF_LABELVALID) &&
1572 0 : dk->dk_label && duid_equal(
1573 0 : dk->dk_label->d_uid, rootduid))
1574 : break;
1575 0 : if (dk == NULL)
1576 0 : panic("root device (%s) not found",
1577 0 : duid_format(rootduid));
1578 0 : rootdv = dk->dk_device;
1579 0 : }
1580 : }
1581 :
1582 0 : majdev = findblkmajor(rootdv);
1583 0 : if (majdev >= 0) {
1584 : /*
1585 : * Root and swap are on the disk.
1586 : * Assume swap is on partition b.
1587 : */
1588 0 : rootdev = MAKEDISKDEV(majdev, rootdv->dv_unit, part);
1589 0 : nswapdev = MAKEDISKDEV(majdev, rootdv->dv_unit, 1);
1590 0 : } else {
1591 : /*
1592 : * Root and swap are on a net.
1593 : */
1594 0 : nswapdev = NODEV;
1595 : }
1596 0 : dumpdev = nswapdev;
1597 0 : swdevt[0].sw_dev = nswapdev;
1598 : /* swdevt[1].sw_dev = NODEV; */
1599 0 : } else {
1600 : /* Completely pre-configured, but we want rootdv .. */
1601 0 : majdev = major(rootdev);
1602 0 : if (findblkname(majdev) == NULL)
1603 0 : return;
1604 0 : unit = DISKUNIT(rootdev);
1605 0 : part = DISKPART(rootdev);
1606 0 : snprintf(buf, sizeof buf, "%s%d%c",
1607 0 : findblkname(majdev), unit, 'a' + part);
1608 0 : rootdv = parsedisk(buf, strlen(buf), 0, &nrootdev);
1609 0 : if (rootdv == NULL)
1610 0 : panic("root device (%s) not found", buf);
1611 : }
1612 :
1613 0 : if (rootdv && rootdv == bootdv && rootdv->dv_class == DV_IFNET)
1614 0 : ifp = ifunit(rootdv->dv_xname);
1615 0 : else if (bootdv && bootdv->dv_class == DV_IFNET)
1616 0 : ifp = ifunit(bootdv->dv_xname);
1617 :
1618 0 : if (ifp)
1619 0 : if_addgroup(ifp, "netboot");
1620 :
1621 0 : switch (rootdv->dv_class) {
1622 : #if defined(NFSCLIENT)
1623 : case DV_IFNET:
1624 0 : mountroot = nfs_mountroot;
1625 0 : nfsbootdevname = rootdv->dv_xname;
1626 0 : return;
1627 : #endif
1628 : case DV_DISK:
1629 0 : mountroot = dk_mountroot;
1630 0 : part = DISKPART(rootdev);
1631 : break;
1632 : default:
1633 0 : printf("can't figure root, hope your kernel is right\n");
1634 0 : return;
1635 : }
1636 :
1637 0 : printf("root on %s%c", rootdv->dv_xname, 'a' + part);
1638 :
1639 0 : if (dk && dk->dk_device == rootdv)
1640 0 : printf(" (%s.%c)", duid_format(rootduid), 'a' + part);
1641 :
1642 : /*
1643 : * Make the swap partition on the root drive the primary swap.
1644 : */
1645 0 : for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
1646 0 : if (major(rootdev) == major(swp->sw_dev) &&
1647 0 : DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) {
1648 0 : temp = swdevt[0].sw_dev;
1649 0 : swdevt[0].sw_dev = swp->sw_dev;
1650 0 : swp->sw_dev = temp;
1651 0 : break;
1652 : }
1653 : }
1654 0 : if (swp->sw_dev != NODEV) {
1655 : /*
1656 : * If dumpdev was the same as the old primary swap device,
1657 : * move it to the new primary swap device.
1658 : */
1659 0 : if (temp == dumpdev)
1660 0 : dumpdev = swdevt[0].sw_dev;
1661 : }
1662 0 : if (swdevt[0].sw_dev != NODEV)
1663 0 : printf(" swap on %s%d%c", findblkname(major(swdevt[0].sw_dev)),
1664 0 : DISKUNIT(swdevt[0].sw_dev),
1665 0 : 'a' + DISKPART(swdevt[0].sw_dev));
1666 0 : if (dumpdev != NODEV)
1667 0 : printf(" dump on %s%d%c", findblkname(major(dumpdev)),
1668 0 : DISKUNIT(dumpdev), 'a' + DISKPART(dumpdev));
1669 0 : printf("\n");
1670 0 : }
1671 :
1672 : extern struct nam2blk nam2blk[];
1673 :
1674 : int
1675 0 : findblkmajor(struct device *dv)
1676 : {
1677 0 : char buf[16], *p;
1678 : int i;
1679 :
1680 0 : if (strlcpy(buf, dv->dv_xname, sizeof buf) >= sizeof buf)
1681 0 : return (-1);
1682 0 : for (p = buf; *p; p++)
1683 0 : if (*p >= '0' && *p <= '9')
1684 0 : *p = '\0';
1685 :
1686 0 : for (i = 0; nam2blk[i].name; i++)
1687 0 : if (!strcmp(buf, nam2blk[i].name))
1688 0 : return (nam2blk[i].maj);
1689 0 : return (-1);
1690 0 : }
1691 :
1692 : char *
1693 0 : findblkname(int maj)
1694 : {
1695 : int i;
1696 :
1697 0 : for (i = 0; nam2blk[i].name; i++)
1698 0 : if (nam2blk[i].maj == maj)
1699 0 : return (nam2blk[i].name);
1700 0 : return (NULL);
1701 0 : }
1702 :
1703 : char *
1704 0 : disk_readlabel(struct disklabel *dl, dev_t dev, char *errbuf, size_t errsize)
1705 : {
1706 0 : struct vnode *vn;
1707 : dev_t chrdev, rawdev;
1708 : int error;
1709 :
1710 0 : chrdev = blktochr(dev);
1711 0 : rawdev = MAKEDISKDEV(major(chrdev), DISKUNIT(chrdev), RAW_PART);
1712 :
1713 : #ifdef DEBUG
1714 : printf("dev=0x%x chrdev=0x%x rawdev=0x%x\n", dev, chrdev, rawdev);
1715 : #endif
1716 :
1717 0 : if (cdevvp(rawdev, &vn)) {
1718 0 : snprintf(errbuf, errsize,
1719 : "cannot obtain vnode for 0x%x/0x%x", dev, rawdev);
1720 0 : return (errbuf);
1721 : }
1722 :
1723 0 : error = VOP_OPEN(vn, FREAD, NOCRED, curproc);
1724 0 : if (error) {
1725 0 : snprintf(errbuf, errsize,
1726 : "cannot open disk, 0x%x/0x%x, error %d",
1727 : dev, rawdev, error);
1728 0 : goto done;
1729 : }
1730 :
1731 0 : error = VOP_IOCTL(vn, DIOCGDINFO, (caddr_t)dl, FREAD, NOCRED, curproc);
1732 0 : if (error) {
1733 0 : snprintf(errbuf, errsize,
1734 : "cannot read disk label, 0x%x/0x%x, error %d",
1735 : dev, rawdev, error);
1736 0 : }
1737 : done:
1738 0 : VOP_CLOSE(vn, FREAD, NOCRED, curproc);
1739 0 : vput(vn);
1740 0 : if (error)
1741 0 : return (errbuf);
1742 0 : return (NULL);
1743 0 : }
1744 :
1745 : int
1746 0 : disk_map(char *path, char *mappath, int size, int flags)
1747 : {
1748 : struct disk *dk, *mdk;
1749 0 : u_char uid[8];
1750 : char c, part;
1751 : int i;
1752 :
1753 : /*
1754 : * Attempt to map a request for a disklabel UID to the correct device.
1755 : * We should be supplied with a disklabel UID which has the following
1756 : * format:
1757 : *
1758 : * [disklabel uid] . [partition]
1759 : *
1760 : * Alternatively, if the DM_OPENPART flag is set the disklabel UID can
1761 : * based passed on its own.
1762 : */
1763 :
1764 0 : if (strchr(path, '/') != NULL)
1765 0 : return -1;
1766 :
1767 : /* Verify that the device name is properly formed. */
1768 0 : if (!((strlen(path) == 16 && (flags & DM_OPENPART)) ||
1769 0 : (strlen(path) == 18 && path[16] == '.')))
1770 0 : return -1;
1771 :
1772 : /* Get partition. */
1773 0 : if (flags & DM_OPENPART)
1774 0 : part = 'a' + RAW_PART;
1775 : else
1776 0 : part = path[17];
1777 :
1778 0 : if (part < 'a' || part >= 'a' + MAXPARTITIONS)
1779 0 : return -1;
1780 :
1781 : /* Derive label UID. */
1782 0 : memset(uid, 0, sizeof(uid));
1783 0 : for (i = 0; i < 16; i++) {
1784 0 : c = path[i];
1785 0 : if (c >= '0' && c <= '9')
1786 0 : c -= '0';
1787 0 : else if (c >= 'a' && c <= 'f')
1788 0 : c -= ('a' - 10);
1789 : else
1790 0 : return -1;
1791 :
1792 0 : uid[i / 2] <<= 4;
1793 0 : uid[i / 2] |= c & 0xf;
1794 : }
1795 :
1796 : mdk = NULL;
1797 0 : TAILQ_FOREACH(dk, &disklist, dk_link) {
1798 0 : if ((dk->dk_flags & DKF_LABELVALID) && dk->dk_label &&
1799 0 : memcmp(dk->dk_label->d_uid, uid,
1800 0 : sizeof(dk->dk_label->d_uid)) == 0) {
1801 : /* Fail if there are duplicate UIDs! */
1802 0 : if (mdk != NULL)
1803 0 : return -1;
1804 : mdk = dk;
1805 0 : }
1806 : }
1807 :
1808 0 : if (mdk == NULL || mdk->dk_name == NULL)
1809 0 : return -1;
1810 :
1811 0 : snprintf(mappath, size, "/dev/%s%s%c",
1812 0 : (flags & DM_OPENBLCK) ? "" : "r", mdk->dk_name, part);
1813 :
1814 0 : return 0;
1815 0 : }
1816 :
1817 : /*
1818 : * Lookup a disk device and verify that it has completed attaching.
1819 : */
1820 : struct device *
1821 0 : disk_lookup(struct cfdriver *cd, int unit)
1822 : {
1823 : struct device *dv;
1824 : struct disk *dk;
1825 :
1826 0 : dv = device_lookup(cd, unit);
1827 0 : if (dv == NULL)
1828 0 : return (NULL);
1829 :
1830 0 : TAILQ_FOREACH(dk, &disklist, dk_link)
1831 0 : if (dk->dk_device == dv)
1832 : break;
1833 :
1834 0 : if (dk == NULL) {
1835 0 : device_unref(dv);
1836 0 : return (NULL);
1837 : }
1838 :
1839 0 : return (dv);
1840 0 : }
1841 :
1842 : int
1843 0 : duid_equal(u_char *duid1, u_char *duid2)
1844 : {
1845 0 : return (memcmp(duid1, duid2, DUID_SIZE) == 0);
1846 : }
1847 :
1848 : int
1849 0 : duid_iszero(u_char *duid)
1850 : {
1851 0 : u_char zeroduid[DUID_SIZE];
1852 :
1853 0 : memset(zeroduid, 0, sizeof(zeroduid));
1854 :
1855 0 : return (duid_equal(duid, zeroduid));
1856 0 : }
1857 :
1858 : const char *
1859 0 : duid_format(u_char *duid)
1860 : {
1861 : static char duid_str[17];
1862 :
1863 0 : snprintf(duid_str, sizeof(duid_str),
1864 : "%02x%02x%02x%02x%02x%02x%02x%02x",
1865 0 : duid[0], duid[1], duid[2], duid[3],
1866 0 : duid[4], duid[5], duid[6], duid[7]);
1867 :
1868 0 : return (duid_str);
1869 : }
|