prep.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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 vlong memsize(void);
  26. static Part *mkpart(char*, vlong, vlong, int);
  27. static void rdpart(Edit*);
  28. static void wrpart(Edit*);
  29. static void checkfat(Disk*);
  30. static void cmdsum(Edit*, Part*, vlong, vlong);
  31. static char *cmdadd(Edit*, char*, vlong, vlong);
  32. static char *cmddel(Edit*, Part*);
  33. static char *cmdokname(Edit*, char*);
  34. static char *cmdwrite(Edit*);
  35. static char *cmdctlprint(Edit*, int, char**);
  36. Edit edit = {
  37. .add= cmdadd,
  38. .del= cmddel,
  39. .okname=cmdokname,
  40. .sum= cmdsum,
  41. .write= cmdwrite,
  42. .unit= "sector",
  43. };
  44. typedef struct Auto Auto;
  45. struct Auto
  46. {
  47. char *name;
  48. uvlong min;
  49. uvlong max;
  50. uint weight;
  51. uchar alloc;
  52. uvlong size;
  53. };
  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*GB){
  183. suf = "GB";
  184. div = GB;
  185. }else if(sz >= 1*MB){
  186. suf = "MB";
  187. div = MB;
  188. }else if(sz >= 1*KB){
  189. suf = "KB";
  190. div = KB;
  191. }else{
  192. suf = "B ";
  193. div = 1;
  194. }
  195. if(div == 1)
  196. print("%c %-12s %*lld %-*lld (%lld sectors, %lld %s)\n", c, name,
  197. edit->disk->width, a, edit->disk->width, b, b-a, sz, suf);
  198. else
  199. print("%c %-12s %*lld %-*lld (%lld sectors, %lld.%.2d %s)\n", c, name,
  200. edit->disk->width, a, edit->disk->width, b, b-a,
  201. sz/div, (int)(((sz%div)*100)/div), suf);
  202. }
  203. static char*
  204. cmdadd(Edit *edit, char *name, vlong start, vlong end)
  205. {
  206. if(start < 2 && strcmp(name, "9fat") != 0)
  207. return "overlaps with the pbs and/or the partition table";
  208. return addpart(edit, mkpart(name, start, end, 1));
  209. }
  210. static char*
  211. cmddel(Edit *edit, Part *p)
  212. {
  213. return delpart(edit, p);
  214. }
  215. static char*
  216. cmdwrite(Edit *edit)
  217. {
  218. wrpart(edit);
  219. return nil;
  220. }
  221. static char isfrog[256]={
  222. /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1,
  223. /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1,
  224. /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1,
  225. /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1,
  226. [' '] 1,
  227. ['/'] 1,
  228. [0x7f] 1,
  229. };
  230. static char*
  231. cmdokname(Edit*, char *elem)
  232. {
  233. for(; *elem; elem++)
  234. if(isfrog[*(uchar*)elem])
  235. return "bad character in name";
  236. return nil;
  237. }
  238. /*
  239. * return memory size in bytes
  240. */
  241. static vlong
  242. memsize(void)
  243. {
  244. int fd, n, by2pg;
  245. char *p;
  246. char buf[128];
  247. vlong mem;
  248. p = getenv("cputype");
  249. if(p && (strcmp(p, "68020") == 0 || strcmp(p, "alpha") == 0))
  250. by2pg = 8*1024;
  251. else
  252. by2pg = 4*1024;
  253. mem = 64*1024*1024;
  254. fd = open("/dev/swap", OREAD);
  255. if(fd < 0)
  256. return mem;
  257. n = read(fd, buf, sizeof(buf)-1);
  258. close(fd);
  259. if(n <= 0)
  260. return mem;
  261. buf[n] = 0;
  262. p = strchr(buf, '/');
  263. if(p)
  264. mem = strtoul(p+1, 0, 0) * (vlong)by2pg;
  265. return mem;
  266. }
  267. static Part*
  268. mkpart(char *name, vlong start, vlong end, int changed)
  269. {
  270. Part *p;
  271. p = emalloc(sizeof(*p));
  272. p->name = estrdup(name);
  273. p->ctlname = estrdup(name);
  274. p->start = start;
  275. p->end = end;
  276. p->changed = changed;
  277. return p;
  278. }
  279. /* plan9 partition is first sector of the disk */
  280. static void
  281. rdpart(Edit *edit)
  282. {
  283. int i, nline, nf, waserr;
  284. char *line[128];
  285. vlong a, b;
  286. char *f[5];
  287. char *err;
  288. Disk *disk;
  289. disk = edit->disk;
  290. seek(disk->fd, disk->secsize, 0);
  291. if(readn(disk->fd, osecbuf, disk->secsize) != disk->secsize)
  292. return;
  293. osecbuf[disk->secsize] = '\0';
  294. memmove(secbuf, osecbuf, disk->secsize+1);
  295. if(strncmp(secbuf, "part", 4) != 0){
  296. fprint(2, "no plan9 partition table found\n");
  297. return;
  298. }
  299. waserr = 0;
  300. nline = getfields(secbuf, line, nelem(line), 1, "\n");
  301. for(i=0; i<nline; i++){
  302. if(strncmp(line[i], "part", 4) != 0) {
  303. Error:
  304. if(waserr == 0)
  305. fprint(2, "syntax error reading partition\n");
  306. waserr = 1;
  307. continue;
  308. }
  309. nf = getfields(line[i], f, nelem(f), 1, " \t\r");
  310. if(nf != 4 || strcmp(f[0], "part") != 0)
  311. goto Error;
  312. a = strtoll(f[2], 0, 0);
  313. b = strtoll(f[3], 0, 0);
  314. if(a >= b)
  315. goto Error;
  316. if(err = addpart(edit, mkpart(f[1], a, b, 0))) {
  317. fprint(2, "?%s: not continuing\n", err);
  318. exits("partition");
  319. }
  320. }
  321. }
  322. static vlong
  323. min(vlong a, vlong b)
  324. {
  325. if(a < b)
  326. return a;
  327. return b;
  328. }
  329. static void
  330. autoxpart(Edit *edit)
  331. {
  332. int i, totw, futz;
  333. vlong secs, secsize, s;
  334. char *err;
  335. if(edit->npart > 0) {
  336. if(doautox)
  337. fprint(2, "partitions already exist; not repartitioning\n");
  338. return;
  339. }
  340. secs = edit->disk->secs;
  341. secsize = edit->disk->secsize;
  342. for(;;){
  343. /* compute total weights */
  344. totw = 0;
  345. for(i=0; i<nelem(autox); i++){
  346. if(autox[i].alloc==0 || autox[i].size)
  347. continue;
  348. totw += autox[i].weight;
  349. }
  350. if(totw == 0)
  351. break;
  352. if(secs <= 0){
  353. fprint(2, "ran out of disk space during autoxpartition.\n");
  354. return;
  355. }
  356. /* assign any minimums for small disks */
  357. futz = 0;
  358. for(i=0; i<nelem(autox); i++){
  359. if(autox[i].alloc==0 || autox[i].size)
  360. continue;
  361. s = (secs*autox[i].weight)/totw;
  362. if(s < autox[i].min/secsize){
  363. autox[i].size = autox[i].min/secsize;
  364. secs -= autox[i].size;
  365. futz = 1;
  366. break;
  367. }
  368. }
  369. if(futz)
  370. continue;
  371. /* assign any maximums for big disks */
  372. futz = 0;
  373. for(i=0; i<nelem(autox); i++){
  374. if(autox[i].alloc==0 || autox[i].size)
  375. continue;
  376. s = (secs*autox[i].weight)/totw;
  377. if(autox[i].max && s > autox[i].max/secsize){
  378. autox[i].size = autox[i].max/secsize;
  379. secs -= autox[i].size;
  380. futz = 1;
  381. break;
  382. }
  383. }
  384. if(futz)
  385. continue;
  386. /* finally, assign partition sizes according to weights */
  387. for(i=0; i<nelem(autox); i++){
  388. if(autox[i].alloc==0 || autox[i].size)
  389. continue;
  390. s = (secs*autox[i].weight)/totw;
  391. autox[i].size = s;
  392. /* use entire disk even in face of rounding errors */
  393. secs -= autox[i].size;
  394. totw -= autox[i].weight;
  395. }
  396. }
  397. for(i=0; i<nelem(autox); i++)
  398. if(autox[i].alloc)
  399. print("%s %llud\n", autox[i].name, autox[i].size);
  400. s = 0;
  401. for(i=0; i<nelem(autox); i++){
  402. if(autox[i].alloc == 0)
  403. continue;
  404. if(err = addpart(edit, mkpart(autox[i].name, s, s+autox[i].size, 1)))
  405. fprint(2, "addpart %s: %s\n", autox[i].name, err);
  406. s += autox[i].size;
  407. }
  408. }
  409. static void
  410. restore(Edit *edit, int ctlfd)
  411. {
  412. int i;
  413. vlong offset;
  414. offset = edit->disk->offset;
  415. fprint(2, "attempting to restore partitions to previous state\n");
  416. if(seek(edit->disk->wfd, edit->disk->secsize, 0) != 0){
  417. fprint(2, "cannot restore: error seeking on disk\n");
  418. exits("inconsistent");
  419. }
  420. if(write(edit->disk->wfd, osecbuf, edit->disk->secsize) != edit->disk->secsize){
  421. fprint(2, "cannot restore: couldn't write old partition table to disk\n");
  422. exits("inconsistent");
  423. }
  424. if(ctlfd >= 0){
  425. for(i=0; i<edit->npart; i++)
  426. fprint(ctlfd, "delpart %s", edit->part[i]->name);
  427. for(i=0; i<nopart; i++){
  428. if(fprint(ctlfd, "part %s %lld %lld", opart[i]->name, opart[i]->start+offset, opart[i]->end+offset) < 0){
  429. fprint(2, "restored disk partition table but not kernel; reboot\n");
  430. exits("inconsistent");
  431. }
  432. }
  433. }
  434. exits("restored");
  435. }
  436. static void
  437. wrpart(Edit *edit)
  438. {
  439. int i, n;
  440. Disk *disk;
  441. disk = edit->disk;
  442. memset(secbuf, 0, disk->secsize);
  443. n = 0;
  444. for(i=0; i<edit->npart; i++)
  445. n += snprint(secbuf+n, disk->secsize-n, "part %s %lld %lld\n",
  446. edit->part[i]->name, edit->part[i]->start, edit->part[i]->end);
  447. if(seek(disk->wfd, disk->secsize, 0) != disk->secsize){
  448. fprint(2, "error seeking %d %lld on disk: %r\n", disk->wfd, disk->secsize);
  449. exits("seek");
  450. }
  451. if(write(disk->wfd, secbuf, disk->secsize) != disk->secsize){
  452. fprint(2, "error writing partition table to disk\n");
  453. restore(edit, -1);
  454. }
  455. if(ctldiff(edit, disk->ctlfd) < 0)
  456. fprint(2, "?warning: partitions could not be updated in devsd\n");
  457. }
  458. /*
  459. * Look for a boot sector in sector 1, as would be
  460. * the case if editing /dev/sdC0/data when that
  461. * was really a bootable disk.
  462. */
  463. static void
  464. checkfat(Disk *disk)
  465. {
  466. uchar buf[32];
  467. if(seek(disk->fd, disk->secsize, 0) < 0
  468. || read(disk->fd, buf, sizeof(buf)) < sizeof(buf))
  469. return;
  470. if(buf[0] != 0xEB || buf[1] != 0x3C || buf[2] != 0x90)
  471. return;
  472. fprint(2,
  473. "there's a fat partition where the\n"
  474. "plan9 partition table would go.\n"
  475. "if you really want to overwrite it, zero\n"
  476. "the second sector of the disk and try again\n");
  477. exits("fat partition");
  478. }