part.c 7.0 KB

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