prep.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * prep - prepare plan9 disk partition
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <bio.h>
  7. #include <disk.h>
  8. #include "edit.h"
  9. enum {
  10. Maxpath = 128,
  11. };
  12. static int blank;
  13. static int file;
  14. static int doautox;
  15. static int printflag;
  16. static Part **opart;
  17. static int nopart;
  18. static char *osecbuf;
  19. static char *secbuf;
  20. static int rdonly;
  21. static int dowrite;
  22. static int docache;
  23. static int donvram;
  24. static void autoxpart(Edit*);
  25. static Part *mkpart(char*, vlong, vlong, int);
  26. static void rdpart(Edit*);
  27. static void wrpart(Edit*);
  28. static void checkfat(Disk*);
  29. static void cmdsum(Edit*, Part*, vlong, vlong);
  30. static char *cmdadd(Edit*, char*, vlong, vlong);
  31. static char *cmddel(Edit*, Part*);
  32. static char *cmdokname(Edit*, char*);
  33. static char *cmdwrite(Edit*);
  34. static char *cmdctlprint(Edit*, int, char**);
  35. Edit edit = {
  36. .add= cmdadd,
  37. .del= cmddel,
  38. .okname=cmdokname,
  39. .sum= cmdsum,
  40. .write= cmdwrite,
  41. .unit= "sector",
  42. };
  43. typedef struct Auto Auto;
  44. struct Auto
  45. {
  46. char *name;
  47. uvlong min;
  48. uvlong max;
  49. uint weight;
  50. uchar alloc;
  51. uvlong size;
  52. };
  53. #define TB (1024LL*GB)
  54. #define GB (1024*1024*1024)
  55. #define MB (1024*1024)
  56. #define KB (1024)
  57. /*
  58. * Order matters -- this is the layout order on disk.
  59. */
  60. Auto autox[] =
  61. {
  62. { "9fat", 10*MB, 100*MB, 10, },
  63. { "nvram", 512, 512, 1, },
  64. { "fscfg", 512, 512, 1, },
  65. { "fs", 200*MB, 0, 10, },
  66. { "fossil", 200*MB, 0, 4, },
  67. { "arenas", 500*MB, 0, 20, },
  68. { "isect", 25*MB, 0, 1, },
  69. { "bloom", 4*MB, 512*MB, 1, },
  70. { "other", 200*MB, 0, 4, },
  71. { "swap", 100*MB, 512*MB, 1, },
  72. { "cache", 50*MB, 1*GB, 2, },
  73. };
  74. void
  75. usage(void)
  76. {
  77. fprint(2, "usage: disk/prep [bcfprw] [-a partname]... [-s sectorsize] /dev/sdC0/plan9\n");
  78. exits("usage");
  79. }
  80. void
  81. main(int argc, char **argv)
  82. {
  83. int i;
  84. char *p;
  85. Disk *disk;
  86. vlong secsize;
  87. secsize = 0;
  88. ARGBEGIN{
  89. case 'a':
  90. p = EARGF(usage());
  91. for(i=0; i<nelem(autox); i++){
  92. if(strcmp(p, autox[i].name) == 0){
  93. if(autox[i].alloc){
  94. fprint(2, "you said -a %s more than once.\n", p);
  95. usage();
  96. }
  97. autox[i].alloc = 1;
  98. break;
  99. }
  100. }
  101. if(i == nelem(autox)){
  102. fprint(2, "don't know how to create autoxmatic partition %s\n", p);
  103. usage();
  104. }
  105. doautox = 1;
  106. break;
  107. case 'b':
  108. blank++;
  109. break;
  110. case 'c':
  111. docache++;
  112. break;
  113. case 'f':
  114. file++;
  115. break;
  116. case 'n':
  117. donvram++;
  118. break;
  119. case 'p':
  120. printflag++;
  121. rdonly++;
  122. break;
  123. case 'r':
  124. rdonly++;
  125. break;
  126. case 's':
  127. secsize = atoi(ARGF());
  128. break;
  129. case 'w':
  130. dowrite++;
  131. break;
  132. default:
  133. usage();
  134. }ARGEND;
  135. if(argc != 1)
  136. usage();
  137. disk = opendisk(argv[0], rdonly, file);
  138. if(disk == nil) {
  139. fprint(2, "cannot open disk: %r\n");
  140. exits("opendisk");
  141. }
  142. if(secsize != 0) {
  143. disk->secsize = secsize;
  144. disk->secs = disk->size / secsize;
  145. }
  146. edit.end = disk->secs;
  147. checkfat(disk);
  148. secbuf = emalloc(disk->secsize+1);
  149. osecbuf = emalloc(disk->secsize+1);
  150. edit.disk = disk;
  151. if(blank == 0)
  152. rdpart(&edit);
  153. opart = emalloc(edit.npart*sizeof(opart[0]));
  154. /* save old partition table */
  155. for(i=0; i<edit.npart; i++)
  156. opart[i] = edit.part[i];
  157. nopart = edit.npart;
  158. if(printflag) {
  159. runcmd(&edit, "P");
  160. exits(0);
  161. }
  162. if(doautox)
  163. autoxpart(&edit);
  164. if(dowrite) {
  165. runcmd(&edit, "w");
  166. exits(0);
  167. }
  168. runcmd(&edit, "p");
  169. for(;;) {
  170. fprint(2, ">>> ");
  171. runcmd(&edit, getline(&edit));
  172. }
  173. }
  174. static void
  175. cmdsum(Edit *edit, Part *p, vlong a, vlong b)
  176. {
  177. vlong sz, div;
  178. char *suf, *name;
  179. char c;
  180. c = p && p->changed ? '\'' : ' ';
  181. name = p ? p->name : "empty";
  182. sz = (b-a)*edit->disk->secsize;
  183. if(sz >= 1*TB){
  184. suf = "TB";
  185. div = TB;
  186. }else if(sz >= 1*GB){
  187. suf = "GB";
  188. div = GB;
  189. }else if(sz >= 1*MB){
  190. suf = "MB";
  191. div = MB;
  192. }else if(sz >= 1*KB){
  193. suf = "KB";
  194. div = KB;
  195. }else{
  196. suf = "B ";
  197. div = 1;
  198. }
  199. if(div == 1)
  200. print("%c %-12s %*lld %-*lld (%lld sectors, %lld %s)\n", c, name,
  201. edit->disk->width, a, edit->disk->width, b, b-a, sz, suf);
  202. else
  203. print("%c %-12s %*lld %-*lld (%lld sectors, %lld.%.2d %s)\n", c, name,
  204. edit->disk->width, a, edit->disk->width, b, b-a,
  205. sz/div, (int)(((sz%div)*100)/div), suf);
  206. }
  207. static char*
  208. cmdadd(Edit *edit, char *name, vlong start, vlong end)
  209. {
  210. if(start < 2 && strcmp(name, "9fat") != 0)
  211. return "overlaps with the pbs and/or the partition table";
  212. return addpart(edit, mkpart(name, start, end, 1));
  213. }
  214. static char*
  215. cmddel(Edit *edit, Part *p)
  216. {
  217. return delpart(edit, p);
  218. }
  219. static char*
  220. cmdwrite(Edit *edit)
  221. {
  222. wrpart(edit);
  223. return nil;
  224. }
  225. static char isfrog[256]={
  226. /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
  227. /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
  228. /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
  229. /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
  230. [' '] 1,
  231. ['/'] 1,
  232. [0x7f] 1,
  233. };
  234. static char*
  235. cmdokname(Edit*, char *elem)
  236. {
  237. for(; *elem; elem++)
  238. if(isfrog[*(uchar*)elem])
  239. return "bad character in name";
  240. return nil;
  241. }
  242. static Part*
  243. mkpart(char *name, vlong start, vlong end, int changed)
  244. {
  245. Part *p;
  246. p = emalloc(sizeof(*p));
  247. p->name = estrdup(name);
  248. p->ctlname = estrdup(name);
  249. p->start = start;
  250. p->end = end;
  251. p->changed = changed;
  252. return p;
  253. }
  254. /* plan9 partition is first sector of the disk */
  255. static void
  256. rdpart(Edit *edit)
  257. {
  258. int i, nline, nf, waserr;
  259. vlong a, b;
  260. char *line[128];
  261. char *f[5];
  262. char *err;
  263. Disk *disk;
  264. disk = edit->disk;
  265. seek(disk->fd, disk->secsize, 0);
  266. if(readn(disk->fd, osecbuf, disk->secsize) != disk->secsize)
  267. return;
  268. osecbuf[disk->secsize] = '\0';
  269. memmove(secbuf, osecbuf, disk->secsize+1);
  270. if(strncmp(secbuf, "part", 4) != 0){
  271. fprint(2, "no plan9 partition table found\n");
  272. return;
  273. }
  274. waserr = 0;
  275. nline = getfields(secbuf, line, nelem(line), 1, "\n");
  276. for(i=0; i<nline; i++){
  277. if(strncmp(line[i], "part", 4) != 0) {
  278. Error:
  279. if(waserr == 0)
  280. fprint(2, "syntax error reading partition\n");
  281. waserr = 1;
  282. continue;
  283. }
  284. nf = getfields(line[i], f, nelem(f), 1, " \t\r");
  285. if(nf != 4 || strcmp(f[0], "part") != 0)
  286. goto Error;
  287. a = strtoll(f[2], 0, 0);
  288. b = strtoll(f[3], 0, 0);
  289. if(a >= b)
  290. goto Error;
  291. if(err = addpart(edit, mkpart(f[1], a, b, 0))) {
  292. fprint(2, "?%s: not continuing\n", err);
  293. exits("partition");
  294. }
  295. }
  296. }
  297. static vlong
  298. min(vlong a, vlong b)
  299. {
  300. if(a < b)
  301. return a;
  302. return b;
  303. }
  304. static void
  305. autoxpart(Edit *edit)
  306. {
  307. int i, totw, futz;
  308. vlong 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. vlong 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. uchar 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. }