partfs.c 9.5 KB

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