prep.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  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. /*
  10. * prep - prepare plan9 disk partition
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <bio.h>
  15. #include <disk.h>
  16. #include "edit.h"
  17. enum {
  18. Maxpath = 128,
  19. };
  20. static int blank;
  21. static int file;
  22. static int doautox;
  23. static int printflag;
  24. static Part **opart;
  25. static int nopart;
  26. static char *osecbuf;
  27. static char *secbuf;
  28. static int rdonly;
  29. static int dowrite;
  30. static int docache;
  31. static int donvram;
  32. static void autoxpart(Edit*);
  33. static Part *mkpart(char*, int64_t, int64_t, int);
  34. static void rdpart(Edit*);
  35. static void wrpart(Edit*);
  36. static void checkfat(Disk*);
  37. static void cmdsum(Edit*, Part*, int64_t, int64_t);
  38. static char *cmdadd(Edit*, char*, int64_t, int64_t);
  39. static char *cmddel(Edit*, Part*);
  40. static char *cmdokname(Edit*, char*);
  41. static char *cmdwrite(Edit*);
  42. Edit edit = {
  43. .add= cmdadd,
  44. .del= cmddel,
  45. .okname=cmdokname,
  46. .sum= cmdsum,
  47. .write= cmdwrite,
  48. .unit= "sector",
  49. };
  50. typedef struct Auto Auto;
  51. struct Auto
  52. {
  53. char *name;
  54. uint64_t min;
  55. uint64_t max;
  56. uint weight;
  57. uint8_t alloc;
  58. uint64_t size;
  59. };
  60. #define TB (1024LL*GB)
  61. #define GB (1024*1024*1024)
  62. #define MB (1024*1024)
  63. #define KB (1024)
  64. /*
  65. * Order matters -- this is the layout order on disk.
  66. */
  67. Auto autox[] =
  68. {
  69. { "9fat", 10*MB, 100*MB, 10, },
  70. { "nvram", 512, 512, 1, },
  71. { "fscfg", 1024, 8192, 1, },
  72. { "fs", 200*MB, 0, 10, },
  73. { "fossil", 200*MB, 0, 4, },
  74. { "arenas", 500*MB, 0, 20, },
  75. { "isect", 25*MB, 0, 1, },
  76. { "bloom", 4*MB, 512*MB, 1, },
  77. { "other", 200*MB, 0, 4, },
  78. { "swap", 100*MB, 512*MB, 1, },
  79. { "cache", 50*MB, 1*GB, 2, },
  80. };
  81. void
  82. usage(void)
  83. {
  84. fprint(2, "usage: disk/prep [-bcfprw] [-a partname]... [-s sectorsize] /dev/sdC0/plan9\n");
  85. exits("usage");
  86. }
  87. void
  88. main(int argc, char **argv)
  89. {
  90. int i;
  91. char *p;
  92. Disk *disk;
  93. int64_t secsize;
  94. secsize = 0;
  95. ARGBEGIN{
  96. case 'a':
  97. p = EARGF(usage());
  98. for(i=0; i<nelem(autox); i++){
  99. if(strcmp(p, autox[i].name) == 0){
  100. if(autox[i].alloc){
  101. fprint(2, "you said -a %s more than once.\n", p);
  102. usage();
  103. }
  104. autox[i].alloc = 1;
  105. break;
  106. }
  107. }
  108. if(i == nelem(autox)){
  109. fprint(2, "don't know how to create automatic partition %s\n", p);
  110. usage();
  111. }
  112. doautox = 1;
  113. break;
  114. case 'b':
  115. blank++;
  116. break;
  117. case 'c':
  118. docache++;
  119. break;
  120. case 'f':
  121. file++;
  122. break;
  123. case 'n':
  124. donvram++;
  125. break;
  126. case 'p':
  127. printflag++;
  128. rdonly++;
  129. break;
  130. case 'r':
  131. rdonly++;
  132. break;
  133. case 's':
  134. secsize = atoi(ARGF());
  135. break;
  136. case 'w':
  137. dowrite++;
  138. break;
  139. default:
  140. usage();
  141. }ARGEND;
  142. if(argc != 1)
  143. usage();
  144. disk = opendisk(argv[0], rdonly, file);
  145. if(disk == nil)
  146. sysfatal("cannot open disk: %r");
  147. if(secsize != 0) {
  148. disk->secsize = secsize;
  149. disk->secs = disk->size / secsize;
  150. }
  151. edit.end = disk->secs;
  152. checkfat(disk);
  153. secbuf = emalloc(disk->secsize+1);
  154. osecbuf = emalloc(disk->secsize+1);
  155. edit.disk = disk;
  156. if(blank == 0)
  157. rdpart(&edit);
  158. opart = emalloc(edit.npart*sizeof(opart[0]));
  159. /* save old partition table */
  160. for(i=0; i<edit.npart; i++)
  161. opart[i] = edit.part[i];
  162. nopart = edit.npart;
  163. if(printflag) {
  164. runcmd(&edit, (char[]){"P"});
  165. exits(0);
  166. }
  167. if(doautox)
  168. autoxpart(&edit);
  169. if(dowrite) {
  170. runcmd(&edit, (char[]){"w"});
  171. exits(0);
  172. }
  173. runcmd(&edit, (char[]){"p"});
  174. for(;;) {
  175. fprint(2, ">>> ");
  176. runcmd(&edit, getline(&edit));
  177. }
  178. }
  179. static void
  180. cmdsum(Edit *edit, Part *p, int64_t a, int64_t b)
  181. {
  182. int64_t sz, div;
  183. char *suf, *name;
  184. char c;
  185. c = p && p->changed ? '\'' : ' ';
  186. name = p ? p->name : "empty";
  187. sz = (b-a)*edit->disk->secsize;
  188. if(sz >= 1*TB){
  189. suf = "TB";
  190. div = TB;
  191. }else if(sz >= 1*GB){
  192. suf = "GB";
  193. div = GB;
  194. }else if(sz >= 1*MB){
  195. suf = "MB";
  196. div = MB;
  197. }else if(sz >= 1*KB){
  198. suf = "KB";
  199. div = KB;
  200. }else{
  201. if (sz < 0)
  202. fprint(2, "%s: negative size!\n", argv0);
  203. suf = "B ";
  204. div = 1;
  205. }
  206. if(div == 1)
  207. print("%c %-12s %*lld %-*lld (%lld sectors, %lld %s)\n", c, name,
  208. edit->disk->width, a, edit->disk->width, b, b-a, sz, suf);
  209. else
  210. print("%c %-12s %*lld %-*lld (%lld sectors, %lld.%.2d %s)\n", c, name,
  211. edit->disk->width, a, edit->disk->width, b, b-a,
  212. sz/div, (int)(((sz%div)*100)/div), suf);
  213. }
  214. static char*
  215. cmdadd(Edit *edit, char *name, int64_t start, int64_t end)
  216. {
  217. if(start < 2 && strcmp(name, "9fat") != 0)
  218. return "overlaps with the pbs and/or the partition table";
  219. return addpart(edit, mkpart(name, start, end, 1));
  220. }
  221. static char*
  222. cmddel(Edit *edit, Part *p)
  223. {
  224. return delpart(edit, p);
  225. }
  226. static char*
  227. cmdwrite(Edit *edit)
  228. {
  229. wrpart(edit);
  230. return nil;
  231. }
  232. static char isfrog[256]={
  233. /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
  234. /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
  235. /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
  236. /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
  237. [' '] 1,
  238. ['/'] 1,
  239. [0x7f] 1,
  240. };
  241. static char*
  242. cmdokname(Edit *e, char *elem)
  243. {
  244. for(; *elem; elem++)
  245. if(isfrog[*(uint8_t*)elem])
  246. return "bad character in name";
  247. return nil;
  248. }
  249. static Part*
  250. mkpart(char *name, int64_t start, int64_t end, int changed)
  251. {
  252. Part *p;
  253. p = emalloc(sizeof(*p));
  254. p->name = estrdup(name);
  255. p->ctlname = estrdup(name);
  256. p->start = start;
  257. p->end = end;
  258. p->changed = changed;
  259. return p;
  260. }
  261. /* plan9 partition is first sector of the disk */
  262. static void
  263. rdpart(Edit *edit)
  264. {
  265. int i, nline, nf, waserr;
  266. int64_t a, b;
  267. char *line[128];
  268. char *f[5];
  269. char *err;
  270. Disk *disk;
  271. disk = edit->disk;
  272. seek(disk->fd, disk->secsize, 0);
  273. if(readn(disk->fd, osecbuf, disk->secsize) != disk->secsize)
  274. return;
  275. osecbuf[disk->secsize] = '\0';
  276. memmove(secbuf, osecbuf, disk->secsize+1);
  277. if(strncmp(secbuf, "part", 4) != 0){
  278. fprint(2, "no plan9 partition table found\n");
  279. return;
  280. }
  281. waserr = 0;
  282. nline = getfields(secbuf, line, nelem(line), 1, "\n");
  283. for(i=0; i<nline; i++){
  284. if(strncmp(line[i], "part", 4) != 0) {
  285. Error:
  286. if(waserr == 0)
  287. fprint(2, "syntax error reading partition\n");
  288. waserr = 1;
  289. continue;
  290. }
  291. nf = getfields(line[i], f, nelem(f), 1, " \t\r");
  292. if(nf != 4 || strcmp(f[0], "part") != 0)
  293. goto Error;
  294. a = strtoll(f[2], 0, 0);
  295. b = strtoll(f[3], 0, 0);
  296. if(a >= b)
  297. goto Error;
  298. if(err = addpart(edit, mkpart(f[1], a, b, 0))) {
  299. fprint(2, "?%s: not continuing\n", err);
  300. exits("partition");
  301. }
  302. }
  303. }
  304. static void
  305. autoxpart(Edit *edit)
  306. {
  307. int i, totw, futz;
  308. int64_t secs, secsize, s;
  309. char *err;
  310. if(edit->npart > 0) {
  311. if(doautox)
  312. fprint(2, "partitions already exist; not repartitioning\n");
  313. return;
  314. }
  315. secs = edit->disk->secs;
  316. secsize = edit->disk->secsize;
  317. for(;;){
  318. /* compute total weights */
  319. totw = 0;
  320. for(i=0; i<nelem(autox); i++){
  321. if(autox[i].alloc==0 || autox[i].size)
  322. continue;
  323. totw += autox[i].weight;
  324. }
  325. if(totw == 0)
  326. break;
  327. if(secs <= 0){
  328. fprint(2, "ran out of disk space during autoxpartition.\n");
  329. return;
  330. }
  331. /* assign any minimums for small disks */
  332. futz = 0;
  333. for(i=0; i<nelem(autox); i++){
  334. if(autox[i].alloc==0 || autox[i].size)
  335. continue;
  336. s = (secs*autox[i].weight)/totw;
  337. if(s < autox[i].min/secsize){
  338. autox[i].size = autox[i].min/secsize;
  339. secs -= autox[i].size;
  340. futz = 1;
  341. break;
  342. }
  343. }
  344. if(futz)
  345. continue;
  346. /* assign any maximums for big disks */
  347. futz = 0;
  348. for(i=0; i<nelem(autox); i++){
  349. if(autox[i].alloc==0 || autox[i].size)
  350. continue;
  351. s = (secs*autox[i].weight)/totw;
  352. if(autox[i].max && s > autox[i].max/secsize){
  353. autox[i].size = autox[i].max/secsize;
  354. secs -= autox[i].size;
  355. futz = 1;
  356. break;
  357. }
  358. }
  359. if(futz)
  360. continue;
  361. /* finally, assign partition sizes according to weights */
  362. for(i=0; i<nelem(autox); i++){
  363. if(autox[i].alloc==0 || autox[i].size)
  364. continue;
  365. s = (secs*autox[i].weight)/totw;
  366. autox[i].size = s;
  367. /* use entire disk even in face of rounding errors */
  368. secs -= autox[i].size;
  369. totw -= autox[i].weight;
  370. }
  371. }
  372. for(i=0; i<nelem(autox); i++)
  373. if(autox[i].alloc)
  374. print("%s %llud\n", autox[i].name, autox[i].size);
  375. s = 0;
  376. for(i=0; i<nelem(autox); i++){
  377. if(autox[i].alloc == 0)
  378. continue;
  379. if(err = addpart(edit, mkpart(autox[i].name, s, s+autox[i].size, 1)))
  380. fprint(2, "addpart %s: %s\n", autox[i].name, err);
  381. s += autox[i].size;
  382. }
  383. }
  384. static void
  385. restore(Edit *edit, int ctlfd)
  386. {
  387. int i;
  388. int64_t offset;
  389. offset = edit->disk->offset;
  390. fprint(2, "attempting to restore partitions to previous state\n");
  391. if(seek(edit->disk->wfd, edit->disk->secsize, 0) != 0){
  392. fprint(2, "cannot restore: error seeking on disk\n");
  393. exits("inconsistent");
  394. }
  395. if(write(edit->disk->wfd, osecbuf, edit->disk->secsize) != edit->disk->secsize){
  396. fprint(2, "cannot restore: couldn't write old partition table to disk\n");
  397. exits("inconsistent");
  398. }
  399. if(ctlfd >= 0){
  400. for(i=0; i<edit->npart; i++)
  401. fprint(ctlfd, "delpart %s", edit->part[i]->name);
  402. for(i=0; i<nopart; i++){
  403. if(fprint(ctlfd, "part %s %lld %lld", opart[i]->name, opart[i]->start+offset, opart[i]->end+offset) < 0){
  404. fprint(2, "restored disk partition table but not kernel; reboot\n");
  405. exits("inconsistent");
  406. }
  407. }
  408. }
  409. exits("restored");
  410. }
  411. static void
  412. wrpart(Edit *edit)
  413. {
  414. int i, n;
  415. Disk *disk;
  416. disk = edit->disk;
  417. memset(secbuf, 0, disk->secsize);
  418. n = 0;
  419. for(i=0; i<edit->npart; i++)
  420. n += snprint(secbuf+n, disk->secsize-n, "part %s %lld %lld\n",
  421. edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);
  422. if(seek(disk->wfd, disk->secsize, 0) != disk->secsize){
  423. fprint(2, "error seeking %d %lld on disk: %r\n", disk->wfd, disk->secsize);
  424. exits("seek");
  425. }
  426. if(write(disk->wfd, secbuf, disk->secsize) != disk->secsize){
  427. fprint(2, "error writing partition table to disk\n");
  428. restore(edit, -1);
  429. }
  430. if(ctldiff(edit, disk->ctlfd) < 0)
  431. fprint(2, "?warning: partitions could not be updated in devsd\n");
  432. }
  433. /*
  434. * Look for a boot sector in sector 1, as would be
  435. * the case if editing /dev/sdC0/data when that
  436. * was really a bootable disk.
  437. */
  438. static void
  439. checkfat(Disk *disk)
  440. {
  441. uint8_t buf[32];
  442. if(seek(disk->fd, disk->secsize, 0) < 0
  443. || read(disk->fd, buf, sizeof(buf)) < sizeof(buf))
  444. return;
  445. if(buf[0] != 0xEB || buf[1] != 0x3C || buf[2] != 0x90)
  446. return;
  447. fprint(2,
  448. "there's a fat partition where the\n"
  449. "plan9 partition table would go.\n"
  450. "if you really want to overwrite it, zero\n"
  451. "the second sector of the disk and try again\n");
  452. exits("fat partition");
  453. }