disk.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 <libc.h>
  11. #include <bio.h>
  12. #include <ctype.h>
  13. #include <disk.h>
  14. static Disk*
  15. mkwidth(Disk *disk)
  16. {
  17. char buf[40];
  18. snprint(buf, sizeof buf, "%lld", disk->size);
  19. disk->width = strlen(buf);
  20. return disk;
  21. }
  22. /*
  23. * Discover the disk geometry by various sleazeful means.
  24. *
  25. * First, if there is a partition table in sector 0,
  26. * see if all the partitions have the same end head
  27. * and sector; if so, we'll assume that that's the
  28. * right count.
  29. *
  30. * If that fails, we'll try looking at the geometry that the ATA
  31. * driver supplied, if any, and translate that as a
  32. * BIOS might.
  33. *
  34. * If that too fails, which should only happen on a SCSI
  35. * disk with no currently defined partitions, we'll try
  36. * various common (h, s) pairs used by BIOSes when faking
  37. * the geometries.
  38. */
  39. typedef struct Table Table;
  40. typedef struct Tentry Tentry;
  41. struct Tentry {
  42. uint8_t active; /* active flag */
  43. uint8_t starth; /* starting head */
  44. uint8_t starts; /* starting sector */
  45. uint8_t startc; /* starting cylinder */
  46. uint8_t type; /* partition type */
  47. uint8_t endh; /* ending head */
  48. uint8_t ends; /* ending sector */
  49. uint8_t endc; /* ending cylinder */
  50. uint8_t xlba[4]; /* starting LBA from beginning of disc */
  51. uint8_t xsize[4]; /* size in sectors */
  52. };
  53. enum {
  54. Toffset = 446, /* offset of partition table in sector */
  55. Magic0 = 0x55,
  56. Magic1 = 0xAA,
  57. NTentry = 4,
  58. };
  59. struct Table {
  60. Tentry entry[NTentry];
  61. uint8_t magic[2];
  62. };
  63. static int
  64. partitiongeometry(Disk *disk)
  65. {
  66. char *rawname;
  67. int i, h, rawfd, s;
  68. uint8_t buf[512];
  69. Table *t;
  70. if(disk->c == 0 || disk->h == 0 || disk->s == 0)
  71. return -1;
  72. t = (Table*)(buf + Toffset);
  73. /*
  74. * look for an MBR first in the /dev/sdXX/data partition, otherwise
  75. * attempt to fall back on the current partition.
  76. */
  77. rawname = malloc(strlen(disk->prefix) + 5); /* prefix + "data" + nul */
  78. if(rawname == nil)
  79. return -1;
  80. strcpy(rawname, disk->prefix);
  81. strcat(rawname, "data");
  82. rawfd = open(rawname, OREAD);
  83. free(rawname);
  84. if(rawfd >= 0
  85. && seek(rawfd, 0, 0) >= 0
  86. && readn(rawfd, buf, 512) == 512
  87. && t->magic[0] == Magic0
  88. && t->magic[1] == Magic1) {
  89. close(rawfd);
  90. } else {
  91. if(rawfd >= 0)
  92. close(rawfd);
  93. if(seek(disk->fd, 0, 0) < 0
  94. || readn(disk->fd, buf, 512) != 512
  95. || t->magic[0] != Magic0
  96. || t->magic[1] != Magic1) {
  97. return -1;
  98. }
  99. }
  100. h = s = -1;
  101. for(i=0; i<NTentry; i++) {
  102. if(t->entry[i].type == 0)
  103. continue;
  104. t->entry[i].ends &= 63;
  105. if(h == -1) {
  106. h = t->entry[i].endh;
  107. s = t->entry[i].ends;
  108. } else {
  109. /*
  110. * Only accept the partition info if every
  111. * partition is consistent.
  112. */
  113. if(h != t->entry[i].endh || s != t->entry[i].ends)
  114. return -1;
  115. }
  116. }
  117. if(h == -1)
  118. return -1;
  119. disk->h = h+1; /* heads count from 0 */
  120. disk->s = s; /* sectors count from 1 */
  121. disk->c = disk->secs / (disk->h*disk->s);
  122. disk->chssrc = Gpart;
  123. return 0;
  124. }
  125. /*
  126. * If there is ATA geometry, use it, perhaps massaged.
  127. */
  128. static int
  129. drivergeometry(Disk *disk)
  130. {
  131. int m;
  132. if(disk->c == 0 || disk->h == 0 || disk->s == 0)
  133. return -1;
  134. disk->chssrc = Gdisk;
  135. if(disk->c < 1024)
  136. return 0;
  137. switch(disk->h) {
  138. case 15:
  139. disk->h = 255;
  140. disk->c /= 17;
  141. return 0;
  142. default:
  143. for(m = 2; m*disk->h < 256; m *= 2) {
  144. if(disk->c/m < 1024) {
  145. disk->c /= m;
  146. disk->h *= m;
  147. return 0;
  148. }
  149. }
  150. /* set to 255, 63 and be done with it */
  151. disk->h = 255;
  152. disk->s = 63;
  153. disk->c = disk->secs / (disk->h * disk->s);
  154. return 0;
  155. }
  156. }
  157. /*
  158. * There's no ATA geometry and no partitions.
  159. * Our guess is as good as anyone's.
  160. */
  161. static struct {
  162. int h;
  163. int s;
  164. } guess[] = {
  165. 64, 32,
  166. 64, 63,
  167. 128, 63,
  168. 255, 63,
  169. };
  170. static int
  171. guessgeometry(Disk *disk)
  172. {
  173. int i;
  174. int32_t c;
  175. disk->chssrc = Gguess;
  176. c = 1024;
  177. for(i=0; i<nelem(guess); i++)
  178. if(c*guess[i].h*guess[i].s >= disk->secs) {
  179. disk->h = guess[i].h;
  180. disk->s = guess[i].s;
  181. disk->c = disk->secs / (disk->h * disk->s);
  182. return 0;
  183. }
  184. /* use maximum values */
  185. disk->h = 255;
  186. disk->s = 63;
  187. disk->c = disk->secs / (disk->h * disk->s);
  188. return 0;
  189. }
  190. static void
  191. findgeometry(Disk *disk)
  192. {
  193. if(partitiongeometry(disk) < 0
  194. && drivergeometry(disk) < 0
  195. && guessgeometry(disk) < 0) { /* can't happen */
  196. print("we're completely confused about your disk; sorry\n");
  197. assert(0);
  198. }
  199. }
  200. static Disk*
  201. openfile(Disk *disk)
  202. {
  203. Dir *d;
  204. if((d = dirfstat(disk->fd)) == nil){
  205. free(disk);
  206. return nil;
  207. }
  208. disk->secsize = 512;
  209. disk->size = d->length;
  210. disk->secs = disk->size / disk->secsize;
  211. disk->offset = 0;
  212. free(d);
  213. findgeometry(disk);
  214. return mkwidth(disk);
  215. }
  216. static Disk*
  217. opensd(Disk *disk)
  218. {
  219. Biobuf b;
  220. char *p, *f[10];
  221. int nf;
  222. Binit(&b, disk->ctlfd, OREAD);
  223. while(p = Brdline(&b, '\n')) {
  224. p[Blinelen(&b)-1] = '\0';
  225. nf = tokenize(p, f, nelem(f));
  226. if(nf >= 3 && strcmp(f[0], "geometry") == 0) {
  227. disk->secsize = strtoll(f[2], 0, 0);
  228. if(nf >= 6) {
  229. disk->c = strtol(f[3], 0, 0);
  230. disk->h = strtol(f[4], 0, 0);
  231. disk->s = strtol(f[5], 0, 0);
  232. }
  233. }
  234. if(nf >= 4 && strcmp(f[0], "part") == 0 && strcmp(f[1], disk->part) == 0) {
  235. disk->offset = strtoll(f[2], 0, 0);
  236. disk->secs = strtoll(f[3], 0, 0) - disk->offset;
  237. }
  238. }
  239. disk->size = disk->secs * disk->secsize;
  240. if(disk->size <= 0) {
  241. strcpy(disk->part, "");
  242. disk->type = Tfile;
  243. return openfile(disk);
  244. }
  245. findgeometry(disk);
  246. return mkwidth(disk);
  247. }
  248. Disk*
  249. opendisk(char *disk, int rdonly, int noctl)
  250. {
  251. char *p, *q;
  252. Disk *d;
  253. d = mallocz(sizeof(*d), 1);
  254. if(d == nil)
  255. return nil;
  256. d->fd = d->wfd = d->ctlfd = -1;
  257. d->rdonly = rdonly;
  258. d->fd = open(disk, OREAD);
  259. if(d->fd < 0) {
  260. werrstr("cannot open disk file");
  261. free(d);
  262. return nil;
  263. }
  264. if(rdonly == 0) {
  265. d->wfd = open(disk, OWRITE);
  266. if(d->wfd < 0)
  267. d->rdonly = 1;
  268. }
  269. if(noctl)
  270. return openfile(d);
  271. p = malloc(strlen(disk) + 4); /* 4: slop for "ctl\0" */
  272. if(p == nil) {
  273. close(d->wfd);
  274. close(d->fd);
  275. free(d);
  276. return nil;
  277. }
  278. strcpy(p, disk);
  279. /* check for floppy(3) disk */
  280. if(strlen(p) >= 7) {
  281. q = p+strlen(p)-7;
  282. if(q[0] == 'f' && q[1] == 'd' && isdigit(q[2]) && strcmp(q+3, "disk") == 0) {
  283. strcpy(q+3, "ctl");
  284. if((d->ctlfd = open(p, ORDWR)) >= 0) {
  285. *q = '\0';
  286. d->prefix = p;
  287. d->type = Tfloppy;
  288. return openfile(d);
  289. }
  290. }
  291. }
  292. /* attempt to find sd(3) disk or partition */
  293. if(q = strrchr(p, '/'))
  294. q++;
  295. else
  296. q = p;
  297. strcpy(q, "ctl");
  298. if((d->ctlfd = open(p, ORDWR)) >= 0) {
  299. *q = '\0';
  300. d->prefix = p;
  301. d->type = Tsd;
  302. d->part = strdup(disk+(q-p));
  303. if(d->part == nil){
  304. close(d->ctlfd);
  305. close(d->wfd);
  306. close(d->fd);
  307. free(p);
  308. free(d);
  309. return nil;
  310. }
  311. return opensd(d);
  312. }
  313. *q = '\0';
  314. d->prefix = p;
  315. /* assume we just have a normal file */
  316. d->type = Tfile;
  317. return openfile(d);
  318. }