part.c 7.4 KB

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