prep.c 9.9 KB

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