part.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. ulong mbroffset;
  136. Dospart *dp;
  137. ulong start, end;
  138. ulong epart, outer, inner;
  139. int havedos, i, nplan9;
  140. char name[10];
  141. if(tsdbio(unit, &unit->part[0], mbrbuf, 0, 1) < 0)
  142. return -1;
  143. mbroffset = 0;
  144. dp = (Dospart*)&mbrbuf[0x1BE];
  145. for(i=0; i<4; i++, dp++)
  146. if(dp->type == DMDDO) {
  147. mbroffset = 63*512;
  148. if(trace)
  149. print("DMDDO partition found\n");
  150. if(tsdbio(unit, &unit->part[0], mbrbuf, mbroffset, 1) < 0)
  151. return -1;
  152. i = -1; /* start over */
  153. }
  154. nplan9 = 0;
  155. havedos = 0;
  156. epart = 0;
  157. dp = (Dospart*)&mbrbuf[0x1BE];
  158. if(trace)
  159. print("%s mbr ", unit->name);
  160. for(i=0; i<4; i++, dp++) {
  161. if(trace)
  162. print("dp %d...", dp->type);
  163. start = mbroffset/512+GLONG(dp->start);
  164. end = start+GLONG(dp->len);
  165. if(dp->type == PLAN9) {
  166. if(nplan9 == 0)
  167. strcpy(name, "plan9");
  168. else
  169. sprint(name, "plan9.%d", nplan9);
  170. sdaddpart(unit, name, start, end);
  171. p9part(unit, name);
  172. nplan9++;
  173. }
  174. /*
  175. * We used to take the active partition (and then the first
  176. * when none are active). We have to take the first here,
  177. * so that the partition we call ``dos'' agrees with the
  178. * partition disk/fdisk calls ``dos''.
  179. */
  180. if(havedos==0 && isdos(dp->type)){
  181. havedos = 1;
  182. sdaddpart(unit, "dos", start, end);
  183. }
  184. if(isextend(dp->type)){
  185. epart = start;
  186. if(trace)
  187. print("link %lud...", epart);
  188. }
  189. }
  190. if(trace)
  191. print("\n");
  192. /*
  193. * Search through the chain of extended partition tables.
  194. */
  195. outer = epart;
  196. while(epart != 0) {
  197. if(trace)
  198. print("%s ext %lud ", unit->name, epart);
  199. if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)epart*unit->secsize, 1) < 0)
  200. break;
  201. inner = epart;
  202. epart = 0;
  203. dp = (Dospart*)&mbrbuf[0x1BE];
  204. for(i=0; i<4; i++, dp++) {
  205. if(trace)
  206. print("dp %d...", dp->type);
  207. start = GLONG(dp->start);
  208. if(dp->type == PLAN9){
  209. start += inner;
  210. end = start+GLONG(dp->len);
  211. if(nplan9 == 0)
  212. strcpy(name, "plan9");
  213. else
  214. sprint(name, "plan9.%d", nplan9);
  215. sdaddpart(unit, name, start, end);
  216. p9part(unit, name);
  217. nplan9++;
  218. }
  219. if(havedos==0 && isdos(dp->type)){
  220. start += inner;
  221. end = start+GLONG(dp->len);
  222. havedos = 1;
  223. sdaddpart(unit, "dos", start, end);
  224. }
  225. if(isextend(dp->type)){
  226. epart = start + outer;
  227. if(trace)
  228. print("link %lud...", epart);
  229. }
  230. }
  231. if(trace)
  232. print("\n");
  233. }
  234. return nplan9 ? 0 : -1;
  235. }
  236. /*
  237. * To facilitate booting from CDs, we create a partition for
  238. * the boot floppy image embedded in a bootable CD.
  239. */
  240. static int
  241. part9660(SDunit *unit)
  242. {
  243. uchar buf[2048];
  244. ulong a, n;
  245. uchar *p;
  246. if(unit->secsize != 2048)
  247. return -1;
  248. if(sdbio(unit, &unit->part[0], buf, 2048, 17*2048) < 0)
  249. return -1;
  250. if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
  251. return -1;
  252. p = buf+0x47;
  253. a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
  254. if(sdbio(unit, &unit->part[0], buf, 2048, a*2048) < 0)
  255. return -1;
  256. if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
  257. || memcmp(buf+30, "\x55\xAA", 2) != 0
  258. || buf[0x20] != 0x88)
  259. return -1;
  260. p = buf+0x28;
  261. a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
  262. switch(buf[0x21]){
  263. case 0x01:
  264. n = 1200*1024;
  265. break;
  266. case 0x02:
  267. n = 1440*1024;
  268. break;
  269. case 0x03:
  270. n = 2880*1024;
  271. break;
  272. default:
  273. return -1;
  274. }
  275. n /= 2048;
  276. print("found partition %s!cdboot; %lud+%lud\n", unit->name, a, n);
  277. sdaddpart(unit, "cdboot", a, a+n);
  278. return 0;
  279. }
  280. enum {
  281. NEW = 1<<0,
  282. OLD = 1<<1
  283. };
  284. void
  285. partition(SDunit *unit)
  286. {
  287. int type;
  288. char *p;
  289. if(unit->part == 0)
  290. return;
  291. if(part9660(unit) == 0)
  292. return;
  293. p = getconf("partition");
  294. if(p == nil)
  295. p = defaultpartition;
  296. if(p != nil && strncmp(p, "new", 3) == 0)
  297. type = NEW;
  298. else if(p != nil && strncmp(p, "old", 3) == 0)
  299. type = OLD;
  300. else
  301. type = NEW|OLD;
  302. if(nbuf < unit->secsize) {
  303. free(mbrbuf);
  304. free(partbuf);
  305. mbrbuf = malloc(unit->secsize);
  306. partbuf = malloc(unit->secsize);
  307. if(mbrbuf==nil || partbuf==nil) {
  308. free(mbrbuf);
  309. free(partbuf);
  310. partbuf = mbrbuf = nil;
  311. nbuf = 0;
  312. return;
  313. }
  314. nbuf = unit->secsize;
  315. }
  316. if((type & NEW) && mbrpart(unit) >= 0){
  317. /* nothing to do */;
  318. }
  319. else if(type & OLD)
  320. oldp9part(unit);
  321. }