disklabel.c revision 1.2 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