xref: /openbsd-src/sys/arch/macppc/macppc/disksubr.c (revision 6db064f3b5beb8c471ae4f814748d5fb5c802dad)
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