fs.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. * ``Exec'' network device. Mounted on net, provides /net/exec.
  3. *
  4. * exec protocol directory
  5. * n connection directory
  6. * ctl control messages (like connect)
  7. * data data
  8. * err errors
  9. * local local address (pid of command)
  10. * remote remote address (command)
  11. * status status
  12. */
  13. #include <u.h>
  14. #include <libc.h>
  15. #include <fcall.h>
  16. #include <thread.h>
  17. #include <9p.h>
  18. #include "dat.h"
  19. int fsdebug;
  20. enum
  21. {
  22. Qroot,
  23. Qexec,
  24. Qclone,
  25. Qn,
  26. Qctl,
  27. Qdata,
  28. Qlocal,
  29. Qremote,
  30. Qstatus,
  31. };
  32. #define PATH(type, n) ((type)|((n)<<8))
  33. #define TYPE(path) ((int)(path) & 0xFF)
  34. #define NUM(path) ((uint)(path)>>8)
  35. typedef struct Tab Tab;
  36. struct Tab
  37. {
  38. char *name;
  39. ulong mode;
  40. };
  41. Tab tab[] =
  42. {
  43. "/", DMDIR|0555,
  44. "exec", DMDIR|0555,
  45. "clone", 0666,
  46. nil, DMDIR|0555,
  47. "ctl", 0666,
  48. "data", 0666,
  49. "local", 0444,
  50. "remote", 0444,
  51. "status", 0444,
  52. };
  53. void
  54. setexecname(char *s)
  55. {
  56. tab[Qexec].name = s;
  57. }
  58. ulong time0;
  59. static void
  60. fillstat(Dir *d, ulong path)
  61. {
  62. Tab *t;
  63. int type;
  64. char buf[32];
  65. memset(d, 0, sizeof(*d));
  66. d->uid = estrdup("exec");
  67. d->gid = estrdup("exec");
  68. d->qid.path = path;
  69. d->atime = d->mtime = time0;
  70. d->length = 0;
  71. type = TYPE(path);
  72. t = &tab[type];
  73. if(t->name)
  74. d->name = estrdup(t->name);
  75. else{
  76. snprint(buf, sizeof buf, "%ud", NUM(path));
  77. d->name = estrdup(buf);
  78. }
  79. d->qid.type = t->mode>>24;
  80. d->mode = t->mode;
  81. }
  82. static void
  83. fsstat(Req *r)
  84. {
  85. fillstat(&r->d, r->fid->qid.path);
  86. respond(r, nil);
  87. }
  88. static int
  89. rootgen(int i, Dir *d, void*)
  90. {
  91. if(i < 1){
  92. fillstat(d, PATH(Qexec, 0));
  93. return 0;
  94. }
  95. return -1;
  96. }
  97. static int
  98. execgen(int i, Dir *d, void*)
  99. {
  100. if(i < 1){
  101. fillstat(d, PATH(Qclone, 0));
  102. return 0;
  103. }
  104. i -= 1;
  105. if(i < nclient){
  106. fillstat(d, PATH(Qn, i));
  107. return 0;
  108. }
  109. return -1;
  110. }
  111. static int
  112. conngen(int i, Dir *d, void *aux)
  113. {
  114. Client *c;
  115. c = aux;
  116. i += Qn+1;
  117. if(i <= Qstatus){
  118. fillstat(d, PATH(i, c->num));
  119. return 0;
  120. }
  121. return -1;
  122. }
  123. char *statusstr[] =
  124. {
  125. "Closed",
  126. "Exec",
  127. "Established",
  128. "Hangup",
  129. };
  130. static void
  131. fsread(Req *r)
  132. {
  133. char e[ERRMAX], *s;
  134. ulong path;
  135. path = r->fid->qid.path;
  136. switch(TYPE(path)){
  137. default:
  138. snprint(e, sizeof e, "bug in execnet path=%lux", path);
  139. respond(r, e);
  140. break;
  141. case Qroot:
  142. dirread9p(r, rootgen, nil);
  143. respond(r, nil);
  144. break;
  145. case Qexec:
  146. dirread9p(r, execgen, nil);
  147. respond(r, nil);
  148. break;
  149. case Qn:
  150. dirread9p(r, conngen, client[NUM(path)]);
  151. respond(r, nil);
  152. break;
  153. case Qctl:
  154. snprint(e, sizeof e, "%ud", NUM(path));
  155. readstr(r, e);
  156. respond(r, nil);
  157. break;
  158. case Qdata:
  159. dataread(r, client[NUM(path)]);
  160. break;
  161. case Qlocal:
  162. snprint(e, sizeof e, "%d", client[NUM(path)]->pid);
  163. readstr(r, e);
  164. respond(r, nil);
  165. break;
  166. case Qremote:
  167. s = client[NUM(path)]->cmd;
  168. if(strlen(s) >= 5) /* "exec " */
  169. readstr(r, s+5);
  170. else
  171. readstr(r, s);
  172. respond(r, nil);
  173. break;
  174. case Qstatus:
  175. readstr(r, statusstr[client[NUM(path)]->status]);
  176. respond(r, nil);
  177. break;
  178. }
  179. }
  180. static void
  181. fswrite(Req *r)
  182. {
  183. char e[ERRMAX];
  184. ulong path;
  185. path = r->fid->qid.path;
  186. switch(TYPE(path)){
  187. default:
  188. snprint(e, sizeof e, "bug in execnet path=%lux", path);
  189. respond(r, e);
  190. break;
  191. case Qctl:
  192. ctlwrite(r, client[NUM(path)]);
  193. break;
  194. case Qdata:
  195. datawrite(r, client[NUM(path)]);
  196. break;
  197. }
  198. }
  199. static void
  200. fsflush(Req *r)
  201. {
  202. ulong path;
  203. Req *or;
  204. for(or=r; or->ifcall.type==Tflush; or=or->oldreq)
  205. ;
  206. if(or->ifcall.type != Tread && or->ifcall.type != Twrite)
  207. abort();
  208. path = or->fid->qid.path;
  209. if(TYPE(path) != Qdata)
  210. abort();
  211. clientflush(or, client[NUM(path)]);
  212. respond(r, nil);
  213. }
  214. static void
  215. fsattach(Req *r)
  216. {
  217. if(r->ifcall.aname && r->ifcall.aname[0]){
  218. respond(r, "invalid attach specifier");
  219. return;
  220. }
  221. r->fid->qid.path = PATH(Qroot, 0);
  222. r->fid->qid.type = QTDIR;
  223. r->fid->qid.vers = 0;
  224. r->ofcall.qid = r->fid->qid;
  225. respond(r, nil);
  226. }
  227. static char*
  228. fswalk1(Fid *fid, char *name, Qid *qid)
  229. {
  230. char buf[32];
  231. int i, n;
  232. ulong path;
  233. if(!(fid->qid.type&QTDIR))
  234. return "walk in non-directory";
  235. path = fid->qid.path;
  236. if(strcmp(name, "..") == 0){
  237. switch(TYPE(path)){
  238. case Qn:
  239. qid->path = PATH(Qexec, 0);
  240. qid->type = QTDIR;
  241. return nil;
  242. case Qroot:
  243. case Qexec:
  244. qid->path = PATH(Qroot, 0);
  245. qid->type = QTDIR;
  246. return nil;
  247. default:
  248. return "bug in fswalk1";
  249. }
  250. }
  251. i = TYPE(path)+1;
  252. for(; i<nelem(tab); i++){
  253. if(i==Qn){
  254. n = atoi(name);
  255. snprint(buf, sizeof buf, "%d", n);
  256. if(n < nclient && strcmp(buf, name) == 0){
  257. qid->path = PATH(Qn, n);
  258. qid->type = QTDIR;
  259. return nil;
  260. }
  261. break;
  262. }
  263. if(strcmp(tab[i].name, name) == 0){
  264. qid->path = PATH(i, NUM(path));
  265. qid->type = tab[i].mode>>24;
  266. return nil;
  267. }
  268. if(tab[i].mode&DMDIR)
  269. break;
  270. }
  271. return "directory entry not found";
  272. }
  273. static void
  274. fsopen(Req *r)
  275. {
  276. static int need[4] = { 4, 2, 6, 1 };
  277. ulong path;
  278. int n;
  279. Tab *t;
  280. /*
  281. * lib9p already handles the blatantly obvious.
  282. * we just have to enforce the permissions we have set.
  283. */
  284. path = r->fid->qid.path;
  285. t = &tab[TYPE(path)];
  286. n = need[r->ifcall.mode&3];
  287. if((n&t->mode) != n){
  288. respond(r, "permission denied");
  289. return;
  290. }
  291. switch(TYPE(path)){
  292. case Qclone:
  293. n = newclient();
  294. path = PATH(Qctl, n);
  295. r->fid->qid.path = path;
  296. r->ofcall.qid.path = path;
  297. if(fsdebug)
  298. fprint(2, "open clone => path=%lux\n", path);
  299. t = &tab[Qctl];
  300. /* fall through */
  301. default:
  302. if(t-tab >= Qn)
  303. client[NUM(path)]->ref++;
  304. respond(r, nil);
  305. break;
  306. }
  307. }
  308. Channel *cclunk;
  309. Channel *cclunkwait;
  310. Channel *creq;
  311. Channel *creqwait;
  312. static void
  313. fsthread(void*)
  314. {
  315. ulong path;
  316. Alt a[3];
  317. Fid *fid;
  318. Req *r;
  319. threadsetname("fsthread");
  320. a[0].op = CHANRCV;
  321. a[0].c = cclunk;
  322. a[0].v = &fid;
  323. a[1].op = CHANRCV;
  324. a[1].c = creq;
  325. a[1].v = &r;
  326. a[2].op = CHANEND;
  327. for(;;){
  328. switch(alt(a)){
  329. case 0:
  330. path = fid->qid.path;
  331. if(fid->omode != -1 && TYPE(path) >= Qn)
  332. closeclient(client[NUM(path)]);
  333. sendp(cclunkwait, nil);
  334. break;
  335. case 1:
  336. switch(r->ifcall.type){
  337. case Tattach:
  338. fsattach(r);
  339. break;
  340. case Topen:
  341. fsopen(r);
  342. break;
  343. case Tread:
  344. fsread(r);
  345. break;
  346. case Twrite:
  347. fswrite(r);
  348. break;
  349. case Tstat:
  350. fsstat(r);
  351. break;
  352. case Tflush:
  353. fsflush(r);
  354. break;
  355. default:
  356. respond(r, "bug in fsthread");
  357. break;
  358. }
  359. sendp(creqwait, 0);
  360. break;
  361. }
  362. }
  363. }
  364. static void
  365. fsdestroyfid(Fid *fid)
  366. {
  367. sendp(cclunk, fid);
  368. recvp(cclunkwait);
  369. }
  370. static void
  371. fssend(Req *r)
  372. {
  373. sendp(creq, r);
  374. recvp(creqwait); /* avoids need to deal with spurious flushes */
  375. }
  376. void
  377. initfs(void)
  378. {
  379. time0 = time(0);
  380. creq = chancreate(sizeof(void*), 0);
  381. creqwait = chancreate(sizeof(void*), 0);
  382. cclunk = chancreate(sizeof(void*), 0);
  383. cclunkwait = chancreate(sizeof(void*), 0);
  384. procrfork(fsthread, nil, STACK, RFNAMEG);
  385. }
  386. Srv fs =
  387. {
  388. .attach= fssend,
  389. .destroyfid= fsdestroyfid,
  390. .walk1= fswalk1,
  391. .open= fssend,
  392. .read= fssend,
  393. .write= fssend,
  394. .stat= fssend,
  395. .flush= fssend,
  396. };