part.c (7226B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 7 #include "sd.h" 8 #include "fs.h" 9 10 enum { 11 Npart = 32 12 }; 13 14 uchar *mbrbuf, *partbuf; 15 int nbuf; 16 #define trace 0 17 18 int 19 tsdbio(SDunit *unit, SDpart *part, void *a, vlong off, int mbr) 20 { 21 uchar *b; 22 23 if(unit->dev->ifc->bio(unit, 0, 0, a, 1, (off/unit->secsize) + part->start) != unit->secsize){ 24 if(trace) 25 print("%s: read %lud at %lld failed\n", unit->dev->name, 26 unit->secsize, (vlong)part->start*unit->secsize+off); 27 return -1; 28 } 29 b = a; 30 if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){ 31 if(trace) 32 print("%s: bad magic %.2ux %.2ux at %lld\n", 33 unit->dev->name, b[0x1FE], b[0x1FF], 34 (vlong)part->start*unit->secsize+off); 35 return -1; 36 } 37 return 0; 38 } 39 40 /* 41 * read partition table. The partition table is just ascii strings. 42 */ 43 #define MAGIC "plan9 partitions" 44 static void 45 oldp9part(SDunit *unit) 46 { 47 SDpart *pp; 48 char *field[3], *line[Npart+1]; 49 ulong n, start, end; 50 int i; 51 52 /* 53 * We have some partitions already. 54 */ 55 pp = &unit->part[unit->npart]; 56 57 /* 58 * We prefer partition tables on the second to last sector, 59 * but some old disks use the last sector instead. 60 */ 61 pp->start = unit->sectors - 2; 62 pp->end = unit->sectors - 1; 63 64 if(tsdbio(unit, pp, partbuf, 0, 0) < 0) 65 return; 66 67 if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) { 68 /* not found on 2nd last sector; look on last sector */ 69 pp->start++; 70 pp->end++; 71 if(tsdbio(unit, pp, partbuf, 0, 0) < 0) 72 return; 73 if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) 74 return; 75 print("%s: using old plan9 partition table on last sector\n", unit->dev->name); 76 }else 77 print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->dev->name); 78 79 /* we found a partition table, so add a partition partition */ 80 unit->npart++; 81 partbuf[unit->secsize-1] = '\0'; 82 83 /* 84 * parse partition table 85 */ 86 n = getfields((char*)partbuf, line, Npart+1, 0, "\n"); 87 if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){ 88 for(i = 1; i < n && unit->npart < SDnpart; i++){ 89 if(getfields(line[i], field, 3, 0, " ") != 3) 90 break; 91 start = strtoull(field[1], 0, 0); 92 end = strtoull(field[2], 0, 0); 93 if(start >= end || end > unit->sectors) 94 break; 95 sdaddpart(unit, field[0], start, end); 96 } 97 } 98 } 99 100 static void 101 p9part(SDunit *unit, char *name) 102 { 103 SDpart *p; 104 char *field[4], *line[Npart+1]; 105 uvlong start, end; 106 int i, n; 107 108 p = sdfindpart(unit, name); 109 if(p == nil) 110 return; 111 112 if(tsdbio(unit, p, partbuf, unit->secsize, 0) < 0) 113 return; 114 partbuf[unit->secsize-1] = '\0'; 115 116 if(strncmp((char*)partbuf, "part ", 5) != 0) 117 return; 118 119 n = getfields((char*)partbuf, line, Npart+1, 0, "\n"); 120 if(n == 0) 121 return; 122 for(i = 0; i < n /* && unit->npart < SDnpart */; i++){ 123 if(strncmp(line[i], "part ", 5) != 0) 124 break; 125 if(getfields(line[i], field, 4, 0, " ") != 4) 126 break; 127 start = strtoull(field[2], 0, 0); 128 end = strtoull(field[3], 0, 0); 129 if(start >= end || end > unit->sectors) 130 break; 131 sdaddpart(unit, field[1], p->start+start, p->start+end); 132 } 133 } 134 135 int 136 isdos(int t) 137 { 138 return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X; 139 } 140 141 int 142 isextend(int t) 143 { 144 return t==EXTEND || t==EXTHUGE || t==LEXTEND; 145 } 146 147 /* 148 * Fetch the first dos and all plan9 partitions out of the MBR partition table. 149 * We return -1 if we did not find a plan9 partition. 150 */ 151 static int 152 mbrpart(SDunit *unit) 153 { 154 Dospart *dp; 155 ulong taboffset, start, end; 156 ulong firstxpart, nxtxpart; 157 int havedos, i, nplan9; 158 char name[10]; 159 160 taboffset = 0; 161 dp = (Dospart*)&mbrbuf[0x1BE]; 162 if(1) { 163 /* get the MBR (allowing for DMDDO) */ 164 if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0) 165 return -1; 166 for(i=0; i<4; i++) 167 if(dp[i].type == DMDDO) { 168 if(trace) 169 print("DMDDO partition found\n"); 170 taboffset = 63; 171 if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0) 172 return -1; 173 i = -1; /* start over */ 174 } 175 } 176 177 /* 178 * Read the partitions, first from the MBR and then 179 * from successive extended partition tables. 180 */ 181 nplan9 = 0; 182 havedos = 0; 183 firstxpart = 0; 184 for(;;) { 185 if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0) 186 return -1; 187 if(trace) { 188 if(firstxpart) 189 print("%s ext %lud ", unit->dev->name, taboffset); 190 else 191 print("%s mbr ", unit->dev->name); 192 } 193 nxtxpart = 0; 194 for(i=0; i<4; i++) { 195 if(trace) 196 print("dp %d...", dp[i].type); 197 start = taboffset+GLONG(dp[i].start); 198 end = start+GLONG(dp[i].len); 199 200 if(dp[i].type == PLAN9) { 201 if(nplan9 == 0) 202 strcpy(name, "plan9"); 203 else 204 sprint(name, "plan9.%d", nplan9); 205 sdaddpart(unit, name, start, end); 206 p9part(unit, name); 207 nplan9++; 208 } 209 210 /* 211 * We used to take the active partition (and then the first 212 * when none are active). We have to take the first here, 213 * so that the partition we call ``dos'' agrees with the 214 * partition disk/fdisk calls ``dos''. 215 */ 216 if(havedos==0 && isdos(dp[i].type)){ 217 havedos = 1; 218 sdaddpart(unit, "dos", start, end); 219 } 220 221 /* nxtxpart is relative to firstxpart (or 0), not taboffset */ 222 if(isextend(dp[i].type)){ 223 nxtxpart = start-taboffset+firstxpart; 224 if(trace) 225 print("link %lud...", nxtxpart); 226 } 227 } 228 if(trace) 229 print("\n"); 230 231 if(!nxtxpart) 232 break; 233 if(!firstxpart) 234 firstxpart = nxtxpart; 235 taboffset = nxtxpart; 236 } 237 return nplan9 ? 0 : -1; 238 } 239 240 /* 241 * To facilitate booting from CDs, we create a partition for 242 * the boot floppy image embedded in a bootable CD. 243 */ 244 static int 245 part9660(SDunit *unit) 246 { 247 uchar buf[2048]; 248 ulong a, n; 249 uchar *p; 250 251 if(unit->secsize != 2048) 252 return -1; 253 254 if(unit->dev->ifc->bio(unit, 0, 0, buf, 2048/unit->secsize, (17*2048)/unit->secsize) < 0) 255 return -1; 256 257 if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0) 258 return -1; 259 260 261 p = buf+0x47; 262 a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); 263 264 if(unit->dev->ifc->bio(unit, 0, 0, buf, 2048/unit->secsize, (a*2048)/unit->secsize) < 0) 265 return -1; 266 267 if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0 268 || memcmp(buf+30, "\x55\xAA", 2) != 0 269 || buf[0x20] != 0x88) 270 return -1; 271 272 p = buf+0x28; 273 a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); 274 275 switch(buf[0x21]){ 276 case 0x01: 277 n = 1200*1024; 278 break; 279 case 0x02: 280 n = 1440*1024; 281 break; 282 case 0x03: 283 n = 2880*1024; 284 break; 285 default: 286 return -1; 287 } 288 n /= 2048; 289 290 print("found partition %s!cdboot; %lud+%lud\n", unit->dev->name, a, n); 291 sdaddpart(unit, "cdboot", a, a+n); 292 return 0; 293 } 294 295 enum { 296 NEW = 1<<0, 297 OLD = 1<<1 298 }; 299 300 void 301 partition(SDunit *unit) 302 { 303 int type; 304 char *p; 305 306 if(unit->part == 0) 307 return; 308 309 if(part9660(unit) == 0) 310 return; 311 312 p = "new"; 313 314 if(p != nil && strncmp(p, "new", 3) == 0) 315 type = NEW; 316 else if(p != nil && strncmp(p, "old", 3) == 0) 317 type = OLD; 318 else 319 type = NEW|OLD; 320 321 if(nbuf < unit->secsize) { 322 free(mbrbuf); 323 free(partbuf); 324 mbrbuf = malloc(unit->secsize); 325 partbuf = malloc(unit->secsize); 326 if(mbrbuf==nil || partbuf==nil) { 327 free(mbrbuf); 328 free(partbuf); 329 partbuf = mbrbuf = nil; 330 nbuf = 0; 331 return; 332 } 333 nbuf = unit->secsize; 334 } 335 336 if((type & NEW) && mbrpart(unit) >= 0){ 337 /* nothing to do */; 338 } 339 else if(type & OLD) 340 oldp9part(unit); 341 }