1 /* $NetBSD: disklabel.c,v 1.1.1.1 1996/02/29 11:35:46 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/ffs/fs.h> 36 #include <sys/disklabel.h> 37 #include <machine/ahdilabel.h> 38 #include <unistd.h> 39 #include <string.h> 40 #include <stdlib.h> 41 #include <fcntl.h> 42 #include <err.h> 43 44 #if (BBSIZE < MINBBSIZE) 45 #error BBSIZE is smaller than MINBBSIZE 46 #endif 47 48 struct ahdilabel { 49 u_int nsecs; 50 daddr_t bslst; 51 daddr_t bslend; 52 u_int nroots; 53 daddr_t *roots; 54 u_int nparts; 55 struct ahdi_part *parts; 56 }; 57 58 u_int dkcksum __P((struct disklabel *)); 59 daddr_t readdisklabel __P((char *, struct disklabel *)); 60 61 static int bsd_label __P((int, off_t, struct disklabel *)); 62 static int ahdi_label __P((int, daddr_t *, struct disklabel *)); 63 static int ahdi_getparts __P((int, daddr_t, daddr_t, struct ahdilabel *)); 64 65 u_int 66 dkcksum (dl) 67 struct disklabel *dl; 68 { 69 u_int16_t sum = 0, 70 *st = (u_int16_t *)dl, 71 *end = (u_int16_t *)&dl->d_partitions[dl->d_npartitions]; 72 73 while (st < end) 74 sum ^= *st++; 75 return(sum); 76 } 77 78 daddr_t 79 readdisklabel (fn, dl) 80 char *fn; 81 struct disklabel *dl; 82 { 83 int fd, e; 84 daddr_t bbsec; 85 86 memset(dl, 0, sizeof *dl); 87 88 if ((fd = open(fn, O_RDONLY)) < 0) 89 err(EXIT_FAILURE, "%s", fn); 90 91 /* Try NetBSD/Atari format first */ 92 if ((e = bsd_label(fd, (off_t)0, dl)) < 0) 93 err(EXIT_FAILURE, "%s", fn); 94 if (!e) 95 return(0); 96 97 /* Try unprotected AHDI format last */ 98 if ((e = ahdi_label(fd, &bbsec, dl)) < 0) 99 err(EXIT_FAILURE, "%s", fn); 100 if (!e) 101 return(bbsec); 102 103 warnx("%s: Unknown disk label format.", fn); 104 return(NO_BOOT_BLOCK); 105 } 106 107 static int 108 bsd_label (fd, offs, label) 109 int fd; 110 off_t offs; 111 struct disklabel *label; 112 { 113 struct bootblock bb; 114 struct disklabel *p; 115 116 if (lseek(fd, offs, SEEK_SET) != offs) 117 return(-1); 118 if (read(fd, &bb, sizeof(bb)) != sizeof(bb)) 119 return(-1); 120 121 p = (struct disklabel *)bb.bb_label; 122 if ( (offs == 0 && bb.bb_magic != NBDAMAGIC) 123 || (offs != 0 && bb.bb_magic != AHDIMAGIC) 124 || p->d_npartitions > MAXPARTITIONS 125 || p->d_magic2 != DISKMAGIC 126 || p->d_magic != DISKMAGIC 127 || dkcksum(p) != 0 128 ) { 129 return(1); 130 } 131 132 *label = *p; 133 return(0); 134 } 135 136 static int 137 ahdi_label (fd, bbsec, label) 138 int fd; 139 daddr_t *bbsec; 140 struct disklabel *label; 141 { 142 struct ahdilabel al; 143 u_int i, j; 144 int e; 145 146 memset(&al, 0, sizeof(al)); 147 if ((e = ahdi_getparts(fd, AHDI_BBLOCK, AHDI_BBLOCK, &al))) 148 return(e); 149 150 /* 151 * Perform sanity checks. 152 */ 153 if (al.bslst == 0 || al.bslend == 0) 154 return(1); 155 if (al.nsecs == 0 || al.nparts == 0) 156 return(1); 157 if (al.nparts > AHDI_MAXPARTS) 158 warnx("Too many AHDI partitions (%u).", al.nparts); 159 for (i = 0; i < al.nparts; ++i) { 160 struct ahdi_part *p1 = &al.parts[i]; 161 for (j = 0; j < al.nroots; ++j) { 162 daddr_t aux = al.roots[j]; 163 if (aux >= p1->ap_st && aux <= p1->ap_end) 164 return(1); 165 } 166 for (j = i + 1; j < al.nparts; ++j) { 167 struct ahdi_part *p2 = &al.parts[j]; 168 if (p1->ap_st >= p2->ap_st && p1->ap_st <= p2->ap_end) 169 return(1); 170 if (p2->ap_st >= p1->ap_st && p2->ap_st <= p1->ap_end) 171 return(1); 172 } 173 if (p1->ap_st >= al.bslst && p1->ap_st <= al.bslend) 174 return(1); 175 if (al.bslst >= p1->ap_st && al.bslst <= p1->ap_end) 176 return(1); 177 } 178 179 /* 180 * Search for a NetBSD boot block 181 */ 182 for (i = 0; i < al.nparts; ++i) { 183 struct ahdi_part *pd = &al.parts[i]; 184 u_int id = *((u_int32_t *)&pd->ap_flg); 185 186 if (id == AHDI_PID_NBD || id == AHDI_PID_RAW) { 187 off_t offs = pd->ap_st * AHDI_BSIZE; 188 if ((e = bsd_label(fd, offs, label)) < 0) 189 return(e); 190 if (!e) { 191 *bbsec = pd->ap_st; /* got it */ 192 return(0); 193 } 194 } 195 } 196 *bbsec = NO_BOOT_BLOCK; /* AHDI label, no NetBSD boot block */ 197 return(0); 198 } 199 200 static int 201 ahdi_getparts(fd, rsec, esec, alab) 202 int fd; 203 daddr_t rsec, 204 esec; 205 struct ahdilabel *alab; 206 { 207 struct ahdi_part *part, *end; 208 struct ahdi_root root; 209 off_t ro; 210 211 ro = rsec * AHDI_BSIZE; 212 if (lseek(fd, ro, SEEK_SET) != ro) { 213 off_t mend = lseek(fd, 0, SEEK_END); 214 if (mend == -1 || mend > ro) 215 return(-1); 216 return(1); 217 } 218 if (read(fd, &root, sizeof(root)) != sizeof(root)) 219 return(-1); 220 221 if (rsec == AHDI_BBLOCK) 222 end = &root.ar_parts[AHDI_MAXRPD]; 223 else end = &root.ar_parts[AHDI_MAXARPD]; 224 for (part = root.ar_parts; part < end; ++part) { 225 u_int id = *((u_int32_t *)&part->ap_flg); 226 if (!(id & 0x01000000)) 227 continue; 228 if ((id &= 0x00ffffff) == AHDI_PID_XGM) { 229 int e; 230 daddr_t aux = part->ap_st + esec; 231 alab->roots = realloc(alab->roots, 232 (alab->nroots + 1) * sizeof(*alab->roots)); 233 alab->roots[alab->nroots++] = aux; 234 e = ahdi_getparts(fd, aux, 235 esec == AHDI_BBLOCK ? aux : esec, alab); 236 if (e) 237 return(e); 238 } else { 239 struct ahdi_part *p; 240 alab->parts = realloc(alab->parts, 241 (alab->nparts + 1) * sizeof(*alab->parts)); 242 p = &alab->parts[alab->nparts++]; 243 *((u_int32_t *)&p->ap_flg) = id; 244 p->ap_st = part->ap_st + rsec; 245 p->ap_end = p->ap_st + part->ap_size - 1; 246 } 247 } 248 alab->nsecs = root.ar_hdsize; 249 alab->bslst = root.ar_bslst; 250 alab->bslend = root.ar_bslst + root.ar_bslsize - 1; 251 return(0); 252 } 253