xref: /inferno-os/os/port/devdup.c (revision c094a1409b780cc543c077e8469fdb28b4c90afb)
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 
8 /* Qid is (2*fd + (file is ctl))+1 */
9 
10 static int
11 dupgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
12 {
13 	Fgrp *fgrp = up->env->fgrp;
14 	Chan *f;
15 	static int perm[] = { 0400, 0200, 0600, 0 };
16 	int p;
17 	Qid q;
18 
19 	if(s == DEVDOTDOT){
20 		devdir(c, c->qid, ".", 0, eve, DMDIR|0555, dp);
21 		return 1;
22 	}
23 	if(s == 0)
24 		return 0;
25 	s--;
26 	if(s/2 > fgrp->maxfd)
27 		return -1;
28 	if((f=fgrp->fd[s/2]) == nil)
29 		return 0;
30 	if(s & 1){
31 		p = 0400;
32 		sprint(up->genbuf, "%dctl", s/2);
33 	}else{
34 		p = perm[f->mode&3];
35 		sprint(up->genbuf, "%d", s/2);
36 	}
37 	mkqid(&q, s+1, 0, QTFILE);
38 	devdir(c, q, up->genbuf, 0, eve, p, dp);
39 	return 1;
40 }
41 
42 static Chan*
43 dupattach(char *spec)
44 {
45 	return devattach('d', spec);
46 }
47 
48 static Walkqid*
49 dupwalk(Chan *c, Chan *nc, char **name, int nname)
50 {
51 	return devwalk(c, nc, name, nname, nil, 0, dupgen);
52 }
53 
54 static int
55 dupstat(Chan *c, uchar *db, int n)
56 {
57 	return devstat(c, db, n, nil, 0, dupgen);
58 }
59 
60 static Chan*
61 dupopen(Chan *c, int omode)
62 {
63 	Chan *f;
64 	int fd, twicefd;
65 
66 	if(c->qid.type & QTDIR){
67 		if(omode != 0)
68 			error(Eisdir);
69 		c->mode = 0;
70 		c->flag |= COPEN;
71 		c->offset = 0;
72 		return c;
73 	}
74 	if(c->qid.type & QTAUTH)
75 		error(Eperm);
76 	twicefd = c->qid.path - 1;
77 	fd = twicefd/2;
78 	if((twicefd & 1)){
79 		/* ctl file */
80 		f = c;
81 		f->mode = openmode(omode);
82 		f->flag |= COPEN;
83 		f->offset = 0;
84 	}else{
85 		/* fd file */
86 		f = fdtochan(up->env->fgrp, fd, openmode(omode), 0, 1);
87 		cclose(c);
88 	}
89 	if(omode & OCEXEC)
90 		f->flag |= CCEXEC;
91 	return f;
92 }
93 
94 static void
95 dupclose(Chan*)
96 {
97 }
98 
99 static long
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
126 dupwrite(Chan*, void*, long, vlong)
127 {
128 	panic("dupwrite");
129 	return 0;		/* not reached */
130 }
131 
132 Dev dupdevtab = {
133 	'd',
134 	"dup",
135 
136 	devreset,
137 	devinit,
138 	devshutdown,
139 	dupattach,
140 	dupwalk,
141 	dupstat,
142 	dupopen,
143 	devcreate,
144 	dupclose,
145 	dupread,
146 	devbread,
147 	dupwrite,
148 	devbwrite,
149 	devremove,
150 	devwstat,
151 };
152