1 #include "dat.h"
2 #include "fns.h"
3 #include "error.h"
4 #include "interp.h"
5
6 /* Qid is (2*fd + (file is ctl))+1 */
7
8 static int
dupgen(Chan * c,char * name,Dirtab * tab,int ntab,int s,Dir * dp)9 dupgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
10 {
11 Fgrp *fgrp = up->env->fgrp;
12 Chan *f;
13 static int perm[] = { 0400, 0200, 0600, 0 };
14 int p;
15 Qid q;
16
17 USED(name); USED(tab); USED(ntab);
18 if(s == DEVDOTDOT){
19 devdir(c, c->qid, ".", 0, eve, DMDIR|0555, dp);
20 return 1;
21 }
22 if(s == 0)
23 return 0;
24 s--;
25 if(s/2 > fgrp->maxfd)
26 return -1;
27 if((f=fgrp->fd[s/2]) == nil)
28 return 0;
29 if(s & 1){
30 p = 0400;
31 sprint(up->genbuf, "%dctl", s/2);
32 }else{
33 p = perm[f->mode&3];
34 sprint(up->genbuf, "%d", s/2);
35 }
36 mkqid(&q, s+1, 0, QTFILE);
37 devdir(c, q, up->genbuf, 0, eve, p, dp);
38 return 1;
39 }
40
41 static Chan*
dupattach(char * spec)42 dupattach(char *spec)
43 {
44 return devattach('d', spec);
45 }
46
47 static Walkqid*
dupwalk(Chan * c,Chan * nc,char ** name,int nname)48 dupwalk(Chan *c, Chan *nc, char **name, int nname)
49 {
50 return devwalk(c, nc, name, nname, nil, 0, dupgen);
51 }
52
53 static int
dupstat(Chan * c,uchar * db,int n)54 dupstat(Chan *c, uchar *db, int n)
55 {
56 return devstat(c, db, n, nil, 0, dupgen);
57 }
58
59 static Chan*
dupopen(Chan * c,int omode)60 dupopen(Chan *c, int omode)
61 {
62 Chan *f;
63 int fd, twicefd;
64
65 if(c->qid.type & QTDIR){
66 if(omode != 0)
67 error(Eisdir);
68 c->mode = 0;
69 c->flag |= COPEN;
70 c->offset = 0;
71 return c;
72 }
73 if(c->qid.type & QTAUTH)
74 error(Eperm);
75 twicefd = c->qid.path - 1;
76 fd = twicefd/2;
77 if((twicefd & 1)){
78 /* ctl file */
79 f = c;
80 f->mode = openmode(omode);
81 f->flag |= COPEN;
82 f->offset = 0;
83 }else{
84 /* fd file */
85 f = fdtochan(up->env->fgrp, fd, openmode(omode), 0, 1);
86 cclose(c);
87 }
88 if(omode & OCEXEC)
89 f->flag |= CCEXEC;
90 return f;
91 }
92
93 static void
dupclose(Chan * c)94 dupclose(Chan *c)
95 {
96 USED(c);
97 }
98
99 static long
dupread(Chan * c,void * va,long n,vlong offset)100 dupread(Chan *c, void *va, long n, vlong offset)
101 {
102 char *a = va;
103 char buf[256];
104 int fd, twicefd;
105
106 if(c->qid.type == QTDIR)
107 return devdirread(c, a, n, nil, 0, dupgen);
108 twicefd = c->qid.path - 1;
109 fd = twicefd/2;
110 if(twicefd & 1){
111 c = fdtochan(up->env->fgrp, fd, -1, 0, 1);
112 if(waserror()){
113 cclose(c);
114 nexterror();
115 }
116 progfdprint(c, fd, 0, buf, sizeof buf);
117 poperror();
118 cclose(c);
119 return readstr((ulong)offset, va, n, buf);
120 }
121 panic("dupread");
122 return 0;
123 }
124
125 static long
dupwrite(Chan * c,void * a,long n,vlong o)126 dupwrite(Chan *c, void *a, long n, vlong o)
127 {
128 USED(c); USED(a); USED(n); USED(o);
129 panic("dupwrite");
130 return 0; /* not reached */
131 }
132
133 Dev dupdevtab = {
134 'd',
135 "dup",
136
137 devinit,
138 dupattach,
139 dupwalk,
140 dupstat,
141 dupopen,
142 devcreate,
143 dupclose,
144 dupread,
145 devbread,
146 dupwrite,
147 devbwrite,
148 devremove,
149 devwstat,
150 };
151