vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

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 }