partfs.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  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. * partfs - serve an underlying file, with devsd-style partitions
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <auth.h>
  15. #include <fcall.h>
  16. #include <thread.h>
  17. #include <9p.h>
  18. typedef struct Part Part;
  19. struct Part
  20. {
  21. int inuse;
  22. int vers;
  23. uint32_t mode;
  24. char *name;
  25. int64_t offset; /* in sectors */
  26. int64_t length; /* in sectors */
  27. };
  28. enum
  29. {
  30. Qroot = 0,
  31. Qdir,
  32. Qctl,
  33. Qpart,
  34. };
  35. int fd = -1, ctlfd = -1;
  36. int rdonly;
  37. uint32_t ctlmode = 0666;
  38. uint32_t time0;
  39. int64_t nsect, sectsize;
  40. char *inquiry = "partfs hard drive";
  41. char *sdname = "sdXX";
  42. Part tab[64];
  43. char*
  44. ctlstring(void)
  45. {
  46. Part *p;
  47. Fmt fmt;
  48. fmtstrinit(&fmt);
  49. fmtprint(&fmt, "inquiry %s\n", inquiry);
  50. fmtprint(&fmt, "geometry %lld %lld\n", nsect, sectsize);
  51. for (p = tab; p < tab + nelem(tab); p++)
  52. if (p->inuse)
  53. fmtprint(&fmt, "part %s %lld %lld\n",
  54. p->name, p->offset, p->length);
  55. return fmtstrflush(&fmt);
  56. }
  57. int
  58. addpart(char *name, int64_t start, int64_t end)
  59. {
  60. Part *p;
  61. if(start < 0 || start > end || end > nsect){
  62. werrstr("bad partition boundaries");
  63. return -1;
  64. }
  65. if (strcmp(name, "ctl") == 0 || strcmp(name, "data") == 0) {
  66. werrstr("partition name already in use");
  67. return -1;
  68. }
  69. for (p = tab; p < tab + nelem(tab) && p->inuse; p++)
  70. if (strcmp(p->name, name) == 0) {
  71. werrstr("partition name already in use");
  72. return -1;
  73. }
  74. if(p == tab + nelem(tab)){
  75. werrstr("no free partition slots");
  76. return -1;
  77. }
  78. p->inuse = 1;
  79. free(p->name);
  80. p->name = estrdup9p(name);
  81. p->offset = start;
  82. p->length = end - start;
  83. p->mode = ctlmode;
  84. p->vers++;
  85. return 0;
  86. }
  87. int
  88. delpart(char *s)
  89. {
  90. Part *p;
  91. for (p = tab; p < tab + nelem(tab); p++)
  92. if(p->inuse && strcmp(p->name, s) == 0)
  93. break;
  94. if(p == tab + nelem(tab)){
  95. werrstr("partition not found");
  96. return -1;
  97. }
  98. p->inuse = 0;
  99. free(p->name);
  100. p->name = nil;
  101. return 0;
  102. }
  103. static void
  104. addparts(char *buf)
  105. {
  106. char *f[4], *p, *q;
  107. /*
  108. * Use partitions passed from boot program,
  109. * e.g.
  110. * sdC0part=dos 63 123123/plan9 123123 456456
  111. * This happens before /boot sets hostname so the
  112. * partitions will have the null-string for user.
  113. */
  114. for(p = buf; p != nil; p = q){
  115. if(q = strchr(p, '/'))
  116. *q++ = '\0';
  117. if(tokenize(p, f, nelem(f)) >= 3 &&
  118. addpart(f[0], strtoull(f[1], 0, 0), strtoull(f[2], 0, 0)) < 0)
  119. fprint(2, "%s: addpart %s: %r\n", argv0, f[0]);
  120. }
  121. }
  122. static void
  123. ctlwrite0(Req *r, char *msg, Cmdbuf *cb)
  124. {
  125. int64_t start, end;
  126. Part *p;
  127. r->ofcall.count = r->ifcall.count;
  128. if(cb->nf < 1){
  129. respond(r, "empty control message");
  130. return;
  131. }
  132. if(strcmp(cb->f[0], "part") == 0){
  133. if(cb->nf != 4){
  134. respondcmderror(r, cb, "part takes 3 args");
  135. return;
  136. }
  137. start = strtoll(cb->f[2], 0, 0);
  138. end = strtoll(cb->f[3], 0, 0);
  139. if(addpart(cb->f[1], start, end) < 0){
  140. respondcmderror(r, cb, "%r");
  141. return;
  142. }
  143. }
  144. else if(strcmp(cb->f[0], "delpart") == 0){
  145. if(cb->nf != 2){
  146. respondcmderror(r, cb, "delpart takes 1 arg");
  147. return;
  148. }
  149. if(delpart(cb->f[1]) < 0){
  150. respondcmderror(r, cb, "%r");
  151. return;
  152. }
  153. }
  154. else if(strcmp(cb->f[0], "inquiry") == 0){
  155. if(cb->nf != 2){
  156. respondcmderror(r, cb, "inquiry takes 1 arg");
  157. return;
  158. }
  159. free(inquiry);
  160. inquiry = estrdup9p(cb->f[1]);
  161. }
  162. else if(strcmp(cb->f[0], "geometry") == 0){
  163. if(cb->nf != 3){
  164. respondcmderror(r, cb, "geometry takes 2 args");
  165. return;
  166. }
  167. nsect = strtoll(cb->f[1], 0, 0);
  168. sectsize = strtoll(cb->f[2], 0, 0);
  169. if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 &&
  170. tab[0].vers == 0){
  171. tab[0].offset = 0;
  172. tab[0].length = nsect;
  173. }
  174. for(p = tab; p < tab + nelem(tab); p++)
  175. if(p->inuse && p->offset + p->length > nsect){
  176. p->inuse = 0;
  177. free(p->name);
  178. p->name = nil;
  179. }
  180. } else
  181. /* pass through to underlying ctl file, if any */
  182. if (write(ctlfd, msg, r->ifcall.count) != r->ifcall.count) {
  183. respondcmderror(r, cb, "%r");
  184. return;
  185. }
  186. respond(r, nil);
  187. }
  188. void
  189. ctlwrite(Req *r)
  190. {
  191. char *msg;
  192. Cmdbuf *cb;
  193. r->ofcall.count = r->ifcall.count;
  194. msg = emalloc9p(r->ifcall.count+1);
  195. memmove(msg, r->ifcall.data, r->ifcall.count);
  196. msg[r->ifcall.count] = '\0';
  197. cb = parsecmd(r->ifcall.data, r->ifcall.count);
  198. ctlwrite0(r, msg, cb);
  199. free(cb);
  200. free(msg);
  201. }
  202. int
  203. rootgen(int off, Dir *d, void *v)
  204. {
  205. memset(d, 0, sizeof *d);
  206. d->atime = time0;
  207. d->mtime = time0;
  208. if(off == 0){
  209. d->name = estrdup9p(sdname);
  210. d->mode = DMDIR|0777;
  211. d->qid.path = Qdir;
  212. d->qid.type = QTDIR;
  213. d->uid = estrdup9p("partfs");
  214. d->gid = estrdup9p("partfs");
  215. d->muid = estrdup9p("");
  216. return 0;
  217. }
  218. return -1;
  219. }
  220. int
  221. dirgen(int off, Dir *d, void *v)
  222. {
  223. int n;
  224. Part *p;
  225. memset(d, 0, sizeof *d);
  226. d->atime = time0;
  227. d->mtime = time0;
  228. if(off == 0){
  229. d->name = estrdup9p("ctl");
  230. d->mode = ctlmode;
  231. d->qid.path = Qctl;
  232. goto Have;
  233. }
  234. off--;
  235. n = 0;
  236. for(p = tab; p < tab + nelem(tab); p++, n++){
  237. if(!p->inuse)
  238. continue;
  239. if(n == off){
  240. d->name = estrdup9p(p->name);
  241. d->length = p->length*sectsize;
  242. d->mode = p->mode;
  243. d->qid.path = Qpart + p - tab;
  244. d->qid.vers = p->vers;
  245. goto Have;
  246. }
  247. }
  248. return -1;
  249. Have:
  250. d->uid = estrdup9p("partfs");
  251. d->gid = estrdup9p("partfs");
  252. d->muid = estrdup9p("");
  253. return 0;
  254. }
  255. int
  256. rdwrpart(Req *r)
  257. {
  258. int q;
  259. int32_t count, tot;
  260. int64_t offset;
  261. uint8_t *dat;
  262. Part *p;
  263. q = r->fid->qid.path - Qpart;
  264. if(q < 0 || q > nelem(tab) || !tab[q].inuse ||
  265. tab[q].vers != r->fid->qid.vers){
  266. respond(r, "unknown partition");
  267. return -1;
  268. }
  269. p = &tab[q];
  270. offset = r->ifcall.offset;
  271. count = r->ifcall.count;
  272. if(offset < 0){
  273. respond(r, "negative offset");
  274. return -1;
  275. }
  276. if(count < 0){
  277. respond(r, "negative count");
  278. return -1;
  279. }
  280. if(offset > p->length*sectsize){
  281. respond(r, "offset past end of partition");
  282. return -1;
  283. }
  284. if(offset+count > p->length*sectsize)
  285. count = p->length*sectsize - offset;
  286. offset += p->offset*sectsize;
  287. if(r->ifcall.type == Tread)
  288. dat = (uint8_t*)r->ofcall.data;
  289. else
  290. dat = (uint8_t*)r->ifcall.data;
  291. /* pass i/o through to underlying file */
  292. seek(fd, offset, 0);
  293. if (r->ifcall.type == Twrite) {
  294. tot = write(fd, dat, count);
  295. if (tot != count) {
  296. respond(r, "%r");
  297. return -1;
  298. }
  299. } else {
  300. tot = read(fd, dat, count);
  301. if (tot < 0) {
  302. respond(r, "%r");
  303. return -1;
  304. }
  305. }
  306. r->ofcall.count = tot;
  307. respond(r, nil);
  308. return 0;
  309. }
  310. void
  311. fsread(Req *r)
  312. {
  313. char *s;
  314. switch((int)r->fid->qid.path){
  315. case Qroot:
  316. dirread9p(r, rootgen, nil);
  317. break;
  318. case Qdir:
  319. dirread9p(r, dirgen, nil);
  320. break;
  321. case Qctl:
  322. s = ctlstring();
  323. readstr(r, s);
  324. free(s);
  325. break;
  326. default:
  327. rdwrpart(r);
  328. return;
  329. }
  330. respond(r, nil);
  331. }
  332. void
  333. fswrite(Req *r)
  334. {
  335. switch((int)r->fid->qid.path){
  336. case Qroot:
  337. case Qdir:
  338. respond(r, "write to a directory?");
  339. break;
  340. case Qctl:
  341. ctlwrite(r);
  342. break;
  343. default:
  344. rdwrpart(r);
  345. break;
  346. }
  347. }
  348. void
  349. fsopen(Req *r)
  350. {
  351. if(r->ifcall.mode&ORCLOSE)
  352. respond(r, "cannot open ORCLOSE");
  353. switch((int)r->fid->qid.path){
  354. case Qroot:
  355. case Qdir:
  356. if(r->ifcall.mode != OREAD){
  357. respond(r, "bad mode for directory open");
  358. return;
  359. }
  360. }
  361. respond(r, nil);
  362. }
  363. void
  364. fsstat(Req *r)
  365. {
  366. int q;
  367. Dir *d;
  368. Part *p;
  369. d = &r->d;
  370. memset(d, 0, sizeof *d);
  371. d->qid = r->fid->qid;
  372. d->atime = d->mtime = time0;
  373. q = r->fid->qid.path;
  374. switch(q){
  375. case Qroot:
  376. d->name = estrdup9p("/");
  377. d->mode = DMDIR|0777;
  378. break;
  379. case Qdir:
  380. d->name = estrdup9p(sdname);
  381. d->mode = DMDIR|0777;
  382. break;
  383. case Qctl:
  384. d->name = estrdup9p("ctl");
  385. d->mode = 0666;
  386. break;
  387. default:
  388. q -= Qpart;
  389. if(q < 0 || q > nelem(tab) || tab[q].inuse == 0 ||
  390. r->fid->qid.vers != tab[q].vers){
  391. respond(r, "partition no longer exists");
  392. return;
  393. }
  394. p = &tab[q];
  395. d->name = estrdup9p(p->name);
  396. d->length = p->length * sectsize;
  397. d->mode = p->mode;
  398. break;
  399. }
  400. d->uid = estrdup9p("partfs");
  401. d->gid = estrdup9p("partfs");
  402. d->muid = estrdup9p("");
  403. respond(r, nil);
  404. }
  405. void
  406. fsattach(Req *r)
  407. {
  408. char *spec;
  409. spec = r->ifcall.aname;
  410. if(spec && spec[0]){
  411. respond(r, "invalid attach specifier");
  412. return;
  413. }
  414. r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
  415. r->fid->qid = r->ofcall.qid;
  416. respond(r, nil);
  417. }
  418. char*
  419. fswalk1(Fid *fid, char *name, Qid *qid)
  420. {
  421. Part *p;
  422. switch((int)fid->qid.path){
  423. case Qroot:
  424. if(strcmp(name, sdname) == 0){
  425. fid->qid.path = Qdir;
  426. fid->qid.type = QTDIR;
  427. *qid = fid->qid;
  428. return nil;
  429. }
  430. break;
  431. case Qdir:
  432. if(strcmp(name, "ctl") == 0){
  433. fid->qid.path = Qctl;
  434. fid->qid.vers = 0;
  435. fid->qid.type = 0;
  436. *qid = fid->qid;
  437. return nil;
  438. }
  439. for(p = tab; p < tab + nelem(tab); p++)
  440. if(p->inuse && strcmp(p->name, name) == 0){
  441. fid->qid.path = p - tab + Qpart;
  442. fid->qid.vers = p->vers;
  443. fid->qid.type = 0;
  444. *qid = fid->qid;
  445. return nil;
  446. }
  447. break;
  448. }
  449. return "file not found";
  450. }
  451. Srv fs = {
  452. .attach=fsattach,
  453. .open= fsopen,
  454. .read= fsread,
  455. .write= fswrite,
  456. .stat= fsstat,
  457. .walk1= fswalk1,
  458. };
  459. char *mtpt = "/dev";
  460. char *srvname;
  461. void
  462. usage(void)
  463. {
  464. fprint(2, "usage: %s [-Dr] [-d sdname] [-m mtpt] [-p 9parts] "
  465. "[-s srvname] diskimage\n", argv0);
  466. fprint(2, "\tdefault mtpt is /dev\n");
  467. exits("usage");
  468. }
  469. void
  470. main(int argc, char **argv)
  471. {
  472. int isdir;
  473. char *file, *cname, *parts;
  474. Dir *dir;
  475. quotefmtinstall();
  476. time0 = time(0);
  477. parts = nil;
  478. ARGBEGIN{
  479. case 'D':
  480. chatty9p++;
  481. break;
  482. case 'd':
  483. sdname = EARGF(usage());
  484. break;
  485. case 'm':
  486. mtpt = EARGF(usage());
  487. break;
  488. case 'p':
  489. parts = EARGF(usage());
  490. break;
  491. case 'r':
  492. rdonly = 1;
  493. break;
  494. case 's':
  495. srvname = EARGF(usage());
  496. break;
  497. default:
  498. usage();
  499. }ARGEND
  500. if(argc != 1)
  501. usage();
  502. file = argv[0];
  503. dir = dirstat(file);
  504. if(!dir)
  505. sysfatal("%s: %r", file);
  506. isdir = (dir->mode & DMDIR) != 0;
  507. free(dir);
  508. if (isdir) {
  509. cname = smprint("%s/ctl", file);
  510. if ((ctlfd = open(cname, ORDWR)) < 0)
  511. sysfatal("open %s: %r", cname);
  512. file = smprint("%s/data", file);
  513. }
  514. if((fd = open(file, rdonly? OREAD: ORDWR)) < 0)
  515. sysfatal("open %s: %r", file);
  516. sectsize = 512; /* conventional */
  517. dir = dirfstat(fd);
  518. if (dir)
  519. nsect = dir->length / sectsize;
  520. free(dir);
  521. inquiry = estrdup9p(inquiry);
  522. tab[0].inuse = 1;
  523. tab[0].name = estrdup9p("data");
  524. tab[0].mode = 0666;
  525. tab[0].length = nsect;
  526. /*
  527. * hack for booting from usb: add 9load partitions.
  528. */
  529. if(parts != nil)
  530. addparts(parts);
  531. postmountsrv(&fs, srvname, mtpt, MBEFORE);
  532. exits(nil);
  533. }