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