1 /*	$NetBSD: disklabel.c,v 1.2 1998/07/22 12:49:42 leo Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Waldi Ravens
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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by Waldi Ravens.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <ufs/ufs/dinode.h>
36 #include <ufs/ffs/fs.h>
37 #include <sys/disklabel.h>
38 #include <machine/ahdilabel.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <err.h>
44 
45 #if (BBSIZE < MINBBSIZE)
46 #error BBSIZE is smaller than MINBBSIZE
47 #endif
48 
49 struct ahdilabel {
50 	u_int		 nsecs;
51 	daddr_t		 bslst;
52 	daddr_t		 bslend;
53 	u_int		 nroots;
54 	daddr_t		 *roots;
55 	u_int		 nparts;
56 	struct ahdi_part *parts;
57 };
58 
59 u_int	dkcksum __P((struct disklabel *));
60 daddr_t	readdisklabel __P((char *, struct disklabel *));
61 
62 static int  bsd_label __P((int, off_t, struct disklabel *));
63 static int  ahdi_label __P((int, daddr_t *, struct disklabel *));
64 static int  ahdi_getparts __P((int, daddr_t, daddr_t, struct ahdilabel *));
65 
66 u_int
67 dkcksum (dl)
68 	struct disklabel *dl;
69 {
70 	u_int16_t sum  = 0,
71 		  *st  = (u_int16_t *)dl,
72 		  *end = (u_int16_t *)&dl->d_partitions[dl->d_npartitions];
73 
74 	while (st < end)
75 		sum ^= *st++;
76 	return(sum);
77 }
78 
79 daddr_t
80 readdisklabel (fn, dl)
81 	char		 *fn;
82 	struct disklabel *dl;
83 {
84 	int		 fd, e;
85 	daddr_t		 bbsec;
86 
87 	memset(dl, 0, sizeof *dl);
88 
89 	if ((fd = open(fn, O_RDONLY)) < 0)
90 		err(EXIT_FAILURE, "%s", fn);
91 
92 	/* Try NetBSD/Atari format first */
93 	if ((e = bsd_label(fd, (off_t)0, dl)) < 0)
94 		err(EXIT_FAILURE, "%s", fn);
95 	if (!e)
96 		return(0);
97 
98 	/* Try unprotected AHDI format last */
99 	if ((e = ahdi_label(fd, &bbsec, dl)) < 0)
100 		err(EXIT_FAILURE, "%s", fn);
101 	if (!e)
102 		return(bbsec);
103 
104 	warnx("%s: Unknown disk label format.", fn);
105 	return(NO_BOOT_BLOCK);
106 }
107 
108 static int
109 bsd_label (fd, offs, label)
110 	int		 fd;
111 	off_t		 offs;
112 	struct disklabel *label;
113 {
114 	struct bootblock bb;
115 	struct disklabel *p;
116 
117 	if (lseek(fd, offs, SEEK_SET) != offs)
118 		return(-1);
119 	if (read(fd, &bb, sizeof(bb)) != sizeof(bb))
120 		return(-1);
121 
122 	p = (struct disklabel *)bb.bb_label;
123 	if (  (offs == 0 && bb.bb_magic != NBDAMAGIC)
124 	   || (offs != 0 && bb.bb_magic != AHDIMAGIC)
125 	   || p->d_npartitions > MAXPARTITIONS
126 	   || p->d_magic2 != DISKMAGIC
127 	   || p->d_magic  != DISKMAGIC
128 	   || dkcksum(p)  != 0
129 	   )	{
130 		return(1);
131 	}
132 
133 	*label = *p;
134 	return(0);
135 }
136 
137 static int
138 ahdi_label (fd, bbsec, label)
139 	int		 fd;
140 	daddr_t		 *bbsec;
141 	struct disklabel *label;
142 {
143 	struct ahdilabel al;
144 	u_int		 i, j;
145 	int		 e;
146 
147 	memset(&al, 0, sizeof(al));
148 	if ((e = ahdi_getparts(fd, AHDI_BBLOCK, AHDI_BBLOCK, &al)))
149 		return(e);
150 
151 	/*
152 	 * Perform sanity checks.
153 	 */
154 	if (al.bslst == 0 || al.bslend == 0)
155 		return(1);
156 	if (al.nsecs == 0 || al.nparts == 0)
157 		return(1);
158 	if (al.nparts > AHDI_MAXPARTS)
159 		warnx("Too many AHDI partitions (%u).", al.nparts);
160 	for (i = 0; i < al.nparts; ++i) {
161 		struct ahdi_part *p1 = &al.parts[i];
162 		for (j = 0; j < al.nroots; ++j) {
163 			daddr_t	aux = al.roots[j];
164 			if (aux >= p1->ap_st && aux <= p1->ap_end)
165 				return(1);
166 		}
167 		for (j = i + 1; j < al.nparts; ++j) {
168 			struct ahdi_part *p2 = &al.parts[j];
169 			if (p1->ap_st >= p2->ap_st && p1->ap_st <= p2->ap_end)
170 				return(1);
171 			if (p2->ap_st >= p1->ap_st && p2->ap_st <= p1->ap_end)
172 				return(1);
173 		}
174 		if (p1->ap_st >= al.bslst && p1->ap_st <= al.bslend)
175 			return(1);
176 		if (al.bslst >= p1->ap_st && al.bslst <= p1->ap_end)
177 			return(1);
178 	}
179 
180 	/*
181 	 * Search for a NetBSD boot block
182 	 */
183 	for (i = 0; i < al.nparts; ++i) {
184 		struct ahdi_part *pd = &al.parts[i];
185 		u_int id = *((u_int32_t *)&pd->ap_flg);
186 
187 		if (id == AHDI_PID_NBD || id == AHDI_PID_RAW) {
188 			off_t	offs = pd->ap_st * AHDI_BSIZE;
189 			if ((e = bsd_label(fd, offs, label)) < 0)
190 				return(e);
191 			if (!e) {
192 				*bbsec = pd->ap_st;	/* got it */
193 				return(0);
194 			}
195 		}
196 	}
197 	*bbsec = NO_BOOT_BLOCK;	/* AHDI label, no NetBSD boot block */
198 	return(0);
199 }
200 
201 static int
202 ahdi_getparts(fd, rsec, esec, alab)
203 	int		 fd;
204 	daddr_t		 rsec,
205 			 esec;
206 	struct ahdilabel *alab;
207 {
208 	struct ahdi_part *part, *end;
209 	struct ahdi_root root;
210 	off_t		 ro;
211 
212 	ro = rsec * AHDI_BSIZE;
213 	if (lseek(fd, ro, SEEK_SET) != ro) {
214 		off_t	mend = lseek(fd, 0, SEEK_END);
215 		if (mend == -1 || mend > ro)
216 			return(-1);
217 		return(1);
218 	}
219 	if (read(fd, &root, sizeof(root)) != sizeof(root))
220 		return(-1);
221 
222 	if (rsec == AHDI_BBLOCK)
223 		end = &root.ar_parts[AHDI_MAXRPD];
224 	else end = &root.ar_parts[AHDI_MAXARPD];
225 	for (part = root.ar_parts; part < end; ++part) {
226 		u_int	id = *((u_int32_t *)&part->ap_flg);
227 		if (!(id & 0x01000000))
228 			continue;
229 		if ((id &= 0x00ffffff) == AHDI_PID_XGM) {
230 			int	e;
231 			daddr_t	aux = part->ap_st + esec;
232 			alab->roots = realloc(alab->roots,
233 					(alab->nroots + 1) * sizeof(*alab->roots));
234 			alab->roots[alab->nroots++] = aux;
235 			e = ahdi_getparts(fd, aux,
236 					   esec == AHDI_BBLOCK ? aux : esec, alab);
237 			if (e)
238 				return(e);
239 		} else {
240 			struct ahdi_part *p;
241 			alab->parts = realloc(alab->parts,
242 					(alab->nparts + 1) * sizeof(*alab->parts));
243 			p = &alab->parts[alab->nparts++];
244 			*((u_int32_t *)&p->ap_flg) = id;
245 			p->ap_st = part->ap_st + rsec;
246 			p->ap_end  = p->ap_st + part->ap_size - 1;
247 		}
248 	}
249 	alab->nsecs  = root.ar_hdsize;
250 	alab->bslst  = root.ar_bslst;
251 	alab->bslend = root.ar_bslst + root.ar_bslsize - 1;
252 	return(0);
253 }
254