part.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) 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 }