1 /* $OpenBSD: disksubr.c,v 1.91 2022/10/11 23:39:07 krw Exp $ */
2
3 /*
4 * Copyright (c) 1999 Michael Shalayeff
5 * Copyright (c) 1997 Niklas Hallqvist
6 * Copyright (c) 1996 Theo de Raadt
7 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/buf.h>
38 #include <sys/disklabel.h>
39 #include <sys/disk.h>
40
41 int readliflabel(struct buf *, void (*)(struct buf *),
42 struct disklabel *, daddr_t *, int);
43
44 /*
45 * Attempt to read a disk label from a device
46 * using the indicated strategy routine.
47 * The label must be partly set up before this:
48 * secpercyl, secsize and anything required for a block i/o read
49 * operation in the driver's strategy/start routines
50 * must be filled in before calling us.
51 */
52 int
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,int spoofonly)53 readdisklabel(dev_t dev, void (*strat)(struct buf *),
54 struct disklabel *lp, int spoofonly)
55 {
56 struct buf *bp = NULL;
57 int error;
58
59 if ((error = initdisklabel(lp)))
60 goto done;
61
62 /* get a buffer and initialize it */
63 bp = geteblk(lp->d_secsize);
64 bp->b_dev = dev;
65
66 error = readliflabel(bp, strat, lp, NULL, spoofonly);
67 if (error == 0)
68 goto done;
69
70 error = readdoslabel(bp, strat, lp, NULL, spoofonly);
71 if (error == 0)
72 goto done;
73
74 #if defined(CD9660)
75 error = iso_disklabelspoof(dev, strat, lp);
76 if (error == 0)
77 goto done;
78 #endif
79 #if defined(UDF)
80 error = udf_disklabelspoof(dev, strat, lp);
81 if (error == 0)
82 goto done;
83 #endif
84
85 done:
86 if (bp) {
87 bp->b_flags |= B_INVAL;
88 brelse(bp);
89 }
90 disk_change = 1;
91 return (error);
92 }
93
94 int
readliflabel(struct buf * bp,void (* strat)(struct buf *),struct disklabel * lp,daddr_t * partoffp,int spoofonly)95 readliflabel(struct buf *bp, void (*strat)(struct buf *),
96 struct disklabel *lp, daddr_t *partoffp, int spoofonly)
97 {
98 struct lifdir *p;
99 struct lifvol *lvp;
100 int error = 0;
101 daddr_t fsoff = 0, openbsdstart = MAXLIFSPACE;
102 int i;
103
104 /* read LIF volume header */
105 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
106 btodb(LIF_VOLSTART)));
107 if (error)
108 return (error);
109
110 lvp = (struct lifvol *)bp->b_data;
111 if (lvp->vol_id != LIF_VOL_ID) {
112 error = EINVAL; /* no LIF volume header */
113 goto done;
114 }
115
116 /* read LIF directory */
117 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
118 lifstodb(lvp->vol_addr)));
119 if (error)
120 goto done;
121
122 /* scan for LIF_DIR_FS dir entry */
123 for (i=0, p=(struct lifdir *)bp->b_data; i < LIF_NUMDIR; p++, i++) {
124 if (p->dir_type == LIF_DIR_FS || p->dir_type == LIF_DIR_HPLBL)
125 break;
126 }
127
128 if (p->dir_type == LIF_DIR_FS) {
129 fsoff = lifstodb(p->dir_addr);
130 openbsdstart = 0;
131 goto finished;
132 }
133
134 /* Only came here to find the offset... */
135 if (partoffp)
136 goto finished;
137
138 if (p->dir_type == LIF_DIR_HPLBL) {
139 struct hpux_label *hl;
140 struct partition *pp;
141 u_int8_t fstype;
142 int i;
143
144 /* read LIF directory */
145 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
146 lifstodb(p->dir_addr)));
147 if (error)
148 goto done;
149
150 hl = (struct hpux_label *)bp->b_data;
151 if (hl->hl_magic1 != hl->hl_magic2 ||
152 hl->hl_magic != HPUX_MAGIC || hl->hl_version != 1) {
153 error = EINVAL; /* HPUX label magic mismatch */
154 goto done;
155 }
156
157 for (i = 0; i < MAXPARTITIONS; i++) {
158 DL_SETPSIZE(&lp->d_partitions[i], 0);
159 DL_SETPOFFSET(&lp->d_partitions[i], 0);
160 lp->d_partitions[i].p_fstype = 0;
161 }
162
163 for (i = 0; i < HPUX_MAXPART; i++) {
164 if (!hl->hl_flags[i])
165 continue;
166 if (hl->hl_flags[i] == HPUX_PART_ROOT) {
167 pp = &lp->d_partitions[0];
168 fstype = FS_BSDFFS;
169 } else if (hl->hl_flags[i] == HPUX_PART_SWAP) {
170 pp = &lp->d_partitions[1];
171 fstype = FS_SWAP;
172 } else if (hl->hl_flags[i] == HPUX_PART_BOOT) {
173 pp = &lp->d_partitions[RAW_PART + 1];
174 fstype = FS_BSDFFS;
175 } else
176 continue;
177
178 DL_SETPSIZE(pp, hl->hl_parts[i].hlp_length * 2);
179 DL_SETPOFFSET(pp, hl->hl_parts[i].hlp_start * 2);
180 pp->p_fstype = fstype;
181 }
182
183 DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
184 DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0);
185 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
186 lp->d_npartitions = MAXPARTITIONS;
187 lp->d_magic = DISKMAGIC;
188 lp->d_magic2 = DISKMAGIC;
189 lp->d_version = 1;
190 lp->d_checksum = 0;
191 lp->d_checksum = dkcksum(lp);
192 /* drop through */
193 }
194
195 finished:
196 /* record the OpenBSD partition's placement for the caller */
197 if (partoffp)
198 *partoffp = fsoff;
199 else {
200 DL_SETBSTART(lp, DL_BLKTOSEC(lp, openbsdstart));
201 DL_SETBEND(lp, DL_GETDSIZE(lp)); /* XXX */
202 }
203
204 /* don't read the on-disk label if we are in spoofed-only mode */
205 if (spoofonly)
206 goto done;
207
208 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, fsoff +
209 LABELSECTOR));
210 if (error)
211 goto done;
212
213 error = checkdisklabel(bp->b_dev, bp->b_data, lp, openbsdstart,
214 DL_GETDSIZE(lp));
215
216 done:
217 return (error);
218 }
219
220 /*
221 * Write disk label back to device after modification.
222 */
223 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp)224 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
225 {
226 daddr_t partoff = -1;
227 int error = EIO;
228 int offset;
229 struct disklabel *dlp;
230 struct buf *bp = NULL;
231
232 /* get a buffer and initialize it */
233 bp = geteblk(lp->d_secsize);
234 bp->b_dev = dev;
235
236 /* Read it in, slap the new label in, and write it back out */
237 if (readliflabel(bp, strat, lp, &partoff, 1) == 0) {
238 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
239 partoff + LABELSECTOR));
240 offset = LABELOFFSET;
241 } else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) {
242 error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp,
243 partoff + DOS_LABELSECTOR));
244 offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR);
245 } else
246 goto done;
247
248 if (error)
249 goto done;
250
251 dlp = (struct disklabel *)(bp->b_data + offset);
252 *dlp = *lp;
253 CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
254 SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
255 (*strat)(bp);
256 error = biowait(bp);
257
258 done:
259 if (bp) {
260 bp->b_flags |= B_INVAL;
261 brelse(bp);
262 }
263 disk_change = 1;
264 return (error);
265 }
266