PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/os/port/devpipe.c

https://bitbucket.org/floren/inferno/
C | 464 lines | 388 code | 55 blank | 21 comment | 65 complexity | 74a2ca63c7adeac2ed222309310392c9 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "interp.h"
  8. #define NETTYPE(x) ((ulong)(x)&0x1f)
  9. #define NETID(x) (((ulong)(x))>>5)
  10. #define NETQID(i,t) (((i)<<5)|(t))
  11. typedef struct Pipe Pipe;
  12. struct Pipe
  13. {
  14. QLock;
  15. Pipe* next;
  16. int ref;
  17. ulong path;
  18. Queue* q[2];
  19. int qref[2];
  20. Dirtab *pipedir;
  21. char* user;
  22. };
  23. static struct
  24. {
  25. Lock;
  26. ulong path;
  27. int pipeqsize;
  28. } pipealloc;
  29. enum
  30. {
  31. Qdir,
  32. Qdata0,
  33. Qdata1,
  34. };
  35. static
  36. Dirtab pipedir[] =
  37. {
  38. ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
  39. "data", {Qdata0}, 0, 0660,
  40. "data1", {Qdata1}, 0, 0660,
  41. };
  42. static void
  43. freepipe(Pipe *p)
  44. {
  45. if(p != nil){
  46. free(p->user);
  47. free(p->q[0]);
  48. free(p->q[1]);
  49. free(p->pipedir);
  50. free(p);
  51. }
  52. }
  53. static void
  54. pipeinit(void)
  55. {
  56. pipealloc.pipeqsize = 32*1024;
  57. }
  58. /*
  59. * create a pipe, no streams are created until an open
  60. */
  61. static Chan*
  62. pipeattach(char *spec)
  63. {
  64. Pipe *p;
  65. Chan *c;
  66. c = devattach('|', spec);
  67. p = malloc(sizeof(Pipe));
  68. if(p == 0)
  69. error(Enomem);
  70. if(waserror()){
  71. freepipe(p);
  72. nexterror();
  73. }
  74. p->pipedir = malloc(sizeof(pipedir));
  75. if (p->pipedir == 0)
  76. error(Enomem);
  77. memmove(p->pipedir, pipedir, sizeof(pipedir));
  78. kstrdup(&p->user, up->env->user);
  79. p->ref = 1;
  80. p->q[0] = qopen(pipealloc.pipeqsize, 0, 0, 0);
  81. if(p->q[0] == 0)
  82. error(Enomem);
  83. p->q[1] = qopen(pipealloc.pipeqsize, 0, 0, 0);
  84. if(p->q[1] == 0)
  85. error(Enomem);
  86. poperror();
  87. lock(&pipealloc);
  88. p->path = ++pipealloc.path;
  89. unlock(&pipealloc);
  90. c->qid.path = NETQID(2*p->path, Qdir);
  91. c->qid.vers = 0;
  92. c->qid.type = QTDIR;
  93. c->aux = p;
  94. c->dev = 0;
  95. return c;
  96. }
  97. static int
  98. pipegen(Chan *c, char *, Dirtab *tab, int ntab, int i, Dir *dp)
  99. {
  100. int id, len;
  101. Qid qid;
  102. Pipe *p;
  103. if(i == DEVDOTDOT){
  104. devdir(c, c->qid, "#|", 0, eve, 0555, dp);
  105. return 1;
  106. }
  107. i++; /* skip . */
  108. if(tab==0 || i>=ntab)
  109. return -1;
  110. tab += i;
  111. p = c->aux;
  112. switch(NETTYPE(tab->qid.path)){
  113. case Qdata0:
  114. len = qlen(p->q[0]);
  115. break;
  116. case Qdata1:
  117. len = qlen(p->q[1]);
  118. break;
  119. default:
  120. len = tab->length;
  121. break;
  122. }
  123. id = NETID(c->qid.path);
  124. qid.path = NETQID(id, tab->qid.path);
  125. qid.vers = 0;
  126. qid.type = QTFILE;
  127. devdir(c, qid, tab->name, len, eve, tab->perm, dp);
  128. return 1;
  129. }
  130. static Walkqid*
  131. pipewalk(Chan *c, Chan *nc, char **name, int nname)
  132. {
  133. Walkqid *wq;
  134. Pipe *p;
  135. p = c->aux;
  136. wq = devwalk(c, nc, name, nname, p->pipedir, nelem(pipedir), pipegen);
  137. if(wq != nil && wq->clone != nil && wq->clone != c){
  138. qlock(p);
  139. p->ref++;
  140. if(c->flag & COPEN){
  141. switch(NETTYPE(c->qid.path)){
  142. case Qdata0:
  143. p->qref[0]++;
  144. break;
  145. case Qdata1:
  146. p->qref[1]++;
  147. break;
  148. }
  149. }
  150. qunlock(p);
  151. }
  152. return wq;
  153. }
  154. static int
  155. pipestat(Chan *c, uchar *db, int n)
  156. {
  157. Pipe *p;
  158. Dir dir;
  159. Dirtab *tab;
  160. p = c->aux;
  161. tab = p->pipedir;
  162. switch(NETTYPE(c->qid.path)){
  163. case Qdir:
  164. devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
  165. break;
  166. case Qdata0:
  167. devdir(c, c->qid, tab[1].name, qlen(p->q[0]), eve, tab[1].perm, &dir);
  168. break;
  169. case Qdata1:
  170. devdir(c, c->qid, tab[2].name, qlen(p->q[1]), eve, tab[2].perm, &dir);
  171. break;
  172. default:
  173. panic("pipestat");
  174. }
  175. n = convD2M(&dir, db, n);
  176. if(n < BIT16SZ)
  177. error(Eshortstat);
  178. return n;
  179. }
  180. /*
  181. * if the stream doesn't exist, create it
  182. */
  183. static Chan*
  184. pipeopen(Chan *c, int omode)
  185. {
  186. Pipe *p;
  187. if(c->qid.type & QTDIR){
  188. if(omode != OREAD)
  189. error(Ebadarg);
  190. c->mode = omode;
  191. c->flag |= COPEN;
  192. c->offset = 0;
  193. return c;
  194. }
  195. openmode(omode); /* check it */
  196. p = c->aux;
  197. qlock(p);
  198. if(waserror()){
  199. qunlock(p);
  200. nexterror();
  201. }
  202. switch(NETTYPE(c->qid.path)){
  203. case Qdata0:
  204. devpermcheck(p->user, p->pipedir[1].perm, omode);
  205. p->qref[0]++;
  206. break;
  207. case Qdata1:
  208. devpermcheck(p->user, p->pipedir[2].perm, omode);
  209. p->qref[1]++;
  210. break;
  211. }
  212. poperror();
  213. qunlock(p);
  214. c->mode = openmode(omode);
  215. c->flag |= COPEN;
  216. c->offset = 0;
  217. c->iounit = qiomaxatomic;
  218. return c;
  219. }
  220. static void
  221. pipeclose(Chan *c)
  222. {
  223. Pipe *p;
  224. p = c->aux;
  225. qlock(p);
  226. if(c->flag & COPEN){
  227. /*
  228. * closing either side hangs up the stream
  229. */
  230. switch(NETTYPE(c->qid.path)){
  231. case Qdata0:
  232. p->qref[0]--;
  233. if(p->qref[0] == 0){
  234. qhangup(p->q[1], 0);
  235. qclose(p->q[0]);
  236. }
  237. break;
  238. case Qdata1:
  239. p->qref[1]--;
  240. if(p->qref[1] == 0){
  241. qhangup(p->q[0], 0);
  242. qclose(p->q[1]);
  243. }
  244. break;
  245. }
  246. }
  247. /*
  248. * if both sides are closed, they are reusable
  249. */
  250. if(p->qref[0] == 0 && p->qref[1] == 0){
  251. qreopen(p->q[0]);
  252. qreopen(p->q[1]);
  253. }
  254. /*
  255. * free the structure on last close
  256. */
  257. p->ref--;
  258. if(p->ref == 0){
  259. qunlock(p);
  260. freepipe(p);
  261. } else
  262. qunlock(p);
  263. }
  264. static long
  265. piperead(Chan *c, void *va, long n, vlong)
  266. {
  267. Pipe *p;
  268. p = c->aux;
  269. switch(NETTYPE(c->qid.path)){
  270. case Qdir:
  271. return devdirread(c, va, n, p->pipedir, nelem(pipedir), pipegen);
  272. case Qdata0:
  273. return qread(p->q[0], va, n);
  274. case Qdata1:
  275. return qread(p->q[1], va, n);
  276. default:
  277. panic("piperead");
  278. }
  279. return -1; /* not reached */
  280. }
  281. static Block*
  282. pipebread(Chan *c, long n, ulong offset)
  283. {
  284. Pipe *p;
  285. p = c->aux;
  286. switch(NETTYPE(c->qid.path)){
  287. case Qdata0:
  288. return qbread(p->q[0], n);
  289. case Qdata1:
  290. return qbread(p->q[1], n);
  291. }
  292. return devbread(c, n, offset);
  293. }
  294. /*
  295. * a write to a closed pipe causes an exception to be sent to
  296. * the prog.
  297. */
  298. static long
  299. pipewrite(Chan *c, void *va, long n, vlong)
  300. {
  301. Pipe *p;
  302. Prog *r;
  303. if(waserror()) {
  304. /* avoid exceptions when pipe is a mounted queue */
  305. if((c->flag & CMSG) == 0) {
  306. r = up->iprog;
  307. if(r != nil && r->kill == nil)
  308. r->kill = "write on closed pipe";
  309. }
  310. nexterror();
  311. }
  312. p = c->aux;
  313. switch(NETTYPE(c->qid.path)){
  314. case Qdata0:
  315. n = qwrite(p->q[1], va, n);
  316. break;
  317. case Qdata1:
  318. n = qwrite(p->q[0], va, n);
  319. break;
  320. default:
  321. panic("pipewrite");
  322. }
  323. poperror();
  324. return n;
  325. }
  326. static long
  327. pipebwrite(Chan *c, Block *bp, ulong junk)
  328. {
  329. long n;
  330. Pipe *p;
  331. Prog *r;
  332. USED(junk);
  333. if(waserror()) {
  334. /* avoid exceptions when pipe is a mounted queue */
  335. if((c->flag & CMSG) == 0) {
  336. r = up->iprog;
  337. if(r != nil && r->kill == nil)
  338. r->kill = "write on closed pipe";
  339. }
  340. nexterror();
  341. }
  342. p = c->aux;
  343. switch(NETTYPE(c->qid.path)){
  344. case Qdata0:
  345. n = qbwrite(p->q[1], bp);
  346. break;
  347. case Qdata1:
  348. n = qbwrite(p->q[0], bp);
  349. break;
  350. default:
  351. n = 0;
  352. panic("pipebwrite");
  353. }
  354. poperror();
  355. return n;
  356. }
  357. static int
  358. pipewstat(Chan *c, uchar *dp, int n)
  359. {
  360. Dir *d;
  361. Pipe *p;
  362. int d1;
  363. if (c->qid.type&QTDIR)
  364. error(Eperm);
  365. p = c->aux;
  366. if(strcmp(up->env->user, p->user) != 0)
  367. error(Eperm);
  368. d = smalloc(sizeof(*d)+n);
  369. if(waserror()){
  370. free(d);
  371. nexterror();
  372. }
  373. n = convM2D(dp, n, d, (char*)&d[1]);
  374. if(n == 0)
  375. error(Eshortstat);
  376. d1 = NETTYPE(c->qid.path) == Qdata1;
  377. if(!emptystr(d->name)){
  378. validwstatname(d->name);
  379. if(strlen(d->name) >= KNAMELEN)
  380. error(Efilename);
  381. if(strcmp(p->pipedir[1+!d1].name, d->name) == 0)
  382. error(Eexist);
  383. kstrcpy(p->pipedir[1+d1].name, d->name, KNAMELEN);
  384. }
  385. if(d->mode != ~0UL)
  386. p->pipedir[d1 + 1].perm = d->mode & 0777;
  387. poperror();
  388. free(d);
  389. return n;
  390. }
  391. Dev pipedevtab = {
  392. '|',
  393. "pipe",
  394. devreset,
  395. pipeinit,
  396. devshutdown,
  397. pipeattach,
  398. pipewalk,
  399. pipestat,
  400. pipeopen,
  401. devcreate,
  402. pipeclose,
  403. piperead,
  404. pipebread,
  405. pipewrite,
  406. pipebwrite,
  407. devremove,
  408. pipewstat,
  409. };