1 /* $OpenBSD: disksubr.c,v 1.83 2022/10/11 23:39:08 krw Exp $ */
2 /* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */
3
4 /*
5 * Copyright (c) 1996 Theo de Raadt
6 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/buf.h>
37 #include <sys/disklabel.h>
38 #include <sys/disk.h>
39
40 int readdpmelabel(struct buf *, void (*)(struct buf *),
41 struct disklabel *, daddr_t *, int);
42
43 /*
44 * Attempt to read a disk label from a device
45 * using the indicated strategy routine.
46 * The label must be partly set up before this:
47 * secpercyl, secsize and anything required for a block i/o read
48 * operation in the driver's strategy/start routines
49 * must be filled in before calling us.
50 *
51 * If dos partition table requested, attempt to load it and
52 * find disklabel inside a DOS partition.
53 *
54 * We would like to check if each MBR has a valid DOSMBR_SIGNATURE, but
55 * we cannot because it doesn't always exist. So.. we assume the
56 * MBR is valid.
57 */
58 int
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,int spoofonly)59 readdisklabel(dev_t dev, void (*strat)(struct buf *),
60 struct disklabel *lp, int spoofonly)
61 {
62 struct buf *bp = NULL;
63 int error;
64
65 if ((error = initdisklabel(lp)))
66 goto done;
67
68 /* get a buffer and initialize it */
69 bp = geteblk(lp->d_secsize);
70 bp->b_dev = dev;
71
72 error = readdpmelabel(bp, strat, lp, NULL, spoofonly);
73 if (error == 0)
74 goto done;
75
76 error = readdoslabel(bp, strat, lp, NULL, spoofonly);
77 if (error == 0)
78 goto done;
79
80 #if defined(CD9660)
81 error = iso_disklabelspoof(dev, strat, lp);
82 if (error == 0)
83 goto done;
84 #endif
85 #if defined(UDF)
86 error = udf_disklabelspoof(dev, strat, lp);
87 if (error == 0)
88 goto done;
89 #endif
90
91 done:
92 if (bp) {
93 bp->b_flags |= B_INVAL;
94 brelse(bp);
95 }
96 disk_change = 1;
97 return (error);
98 }
99
100 int
readdpmelabel(struct buf * bp,void (* strat)(struct buf *),struct disklabel * lp,daddr_t * partoffp,int spoofonly)101 readdpmelabel(struct buf *bp, void (*strat)(struct buf *),
102 struct disklabel *lp, daddr_t *partoffp, int spoofonly)
103 {
104 int error, i, part_cnt, n, hfspartoff = -1;
105 long long hfspartend = DL_GETDSIZE(lp);
106 struct part_map_entry *part;
107
108 /* First check for a DPME (HFS) disklabel */
109 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, LABELSECTOR));
110 if (error)
111 return (error);
112
113 /* if successful, wander through DPME partition table */
114 part = (struct part_map_entry *)bp->b_data;
115 /* if first partition is not valid, assume not HFS/DPME partitioned */
116 if (part->pmSig != PART_ENTRY_MAGIC)
117 return (EINVAL); /* not a DPME partition */
118 part_cnt = part->pmMapBlkCnt;
119 n = 8;
120 for (i = 0; i < part_cnt; i++) {
121 struct partition *pp;
122 char *s;
123
124 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
125 LABELSECTOR + i));
126 if (error)
127 return (error);
128
129 part = (struct part_map_entry *)bp->b_data;
130 /* toupper the string, in case caps are different... */
131 for (s = part->pmPartType; *s; s++)
132 if ((*s >= 'a') && (*s <= 'z'))
133 *s = (*s - 'a' + 'A');
134
135 if (strcmp(part->pmPartType, PART_TYPE_OPENBSD) == 0) {
136 hfspartoff = part->pmPyPartStart;
137 hfspartend = hfspartoff + part->pmPartBlkCnt;
138 if (partoffp) {
139 *partoffp = hfspartoff;
140 return (0);
141 } else {
142 DL_SETBSTART(lp, hfspartoff);
143 DL_SETBEND(lp,
144 hfspartend < DL_GETDSIZE(lp) ? hfspartend :
145 DL_GETDSIZE(lp));
146 }
147 continue;
148 }
149
150 if (n >= MAXPARTITIONS || partoffp)
151 continue;
152
153 /* Currently we spoof HFS partitions only. */
154 if (strcmp(part->pmPartType, PART_TYPE_MAC) == 0) {
155 pp = &lp->d_partitions[n];
156 DL_SETPOFFSET(pp, part->pmPyPartStart);
157 DL_SETPSIZE(pp, part->pmPartBlkCnt);
158 pp->p_fstype = FS_HFS;
159 n++;
160 }
161
162 }
163
164 if (hfspartoff == -1)
165 return (EINVAL); /* no OpenBSD partition inside DPME label */
166
167 if (spoofonly)
168 return (0);
169
170 /* next, dig out disk label */
171 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, hfspartoff));
172 if (error)
173 return (error);
174
175 error = checkdisklabel(bp->b_dev, bp->b_data + LABELOFFSET, lp,
176 hfspartoff, hfspartend);
177
178 return (error);
179 }
180
181 /*
182 * Write disk label back to device after modification.
183 */
184 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp)185 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
186 {
187 daddr_t partoff = -1;
188 int error = EIO;
189 int offset;
190 struct disklabel *dlp;
191 struct buf *bp = NULL;
192
193 /* get a buffer and initialize it */
194 bp = geteblk(lp->d_secsize);
195 bp->b_dev = dev;
196
197 /* Read it in, slap the new label in, and write it back out */
198 if (readdpmelabel(bp, strat, lp, &partoff, 1) == 0) {
199 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, partoff));
200 offset = 0;
201 } else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) {
202 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
203 partoff + DOS_LABELSECTOR));
204 offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR);
205 } else
206 goto done;
207
208 if (error)
209 goto done;
210
211 dlp = (struct disklabel *)(bp->b_data + offset);
212 *dlp = *lp;
213 CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
214 SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
215 (*strat)(bp);
216 error = biowait(bp);
217
218 done:
219 if (bp) {
220 bp->b_flags |= B_INVAL;
221 brelse(bp);
222 }
223 disk_change = 1;
224 return (error);
225 }
226