xref: /plan9/sys/src/9/port/dev.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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 #define	DEVTAB
8 #include	"devtab.h"
9 
10 extern ulong	kerndate;
11 
12 int
13 devno(int c, int user)
14 {
15 	Rune *s;
16 	int i;
17 
18 	s = devchar;
19 	i = 0;
20 	while(*s){
21 		if(c == *s)
22 			return i;
23 		i++;
24 		s++;
25 	}
26 
27 	if(user)
28 		return -1;
29 	panic("devno %C 0x%ux", c, c);
30 	return 0;
31 }
32 
33 void
34 devdir(Chan *c, Qid qid, char *n, long length, char *user, long perm, Dir *db)
35 {
36 	strcpy(db->name, n);
37 	db->qid = qid;
38 	db->type = devchar[c->type];
39 	db->dev = c->dev;
40 	if(qid.path & CHDIR)
41 		db->mode = CHDIR|perm;
42 	else
43 		db->mode = perm;
44 	if(c->flag&CMSG)
45 		db->mode |= CHMOUNT;
46 	db->atime = seconds();
47 	db->mtime = kerndate;
48 	db->hlength = 0;
49 	db->length = length;
50 	memmove(db->uid, user, NAMELEN);
51 	memmove(db->gid, eve, NAMELEN);
52 }
53 
54 int
55 devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
56 {
57 	if(tab==0 || i>=ntab)
58 		return -1;
59 	tab += i;
60 	devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
61 	return 1;
62 }
63 
64 Chan *
65 devattach(int tc, char *spec)
66 {
67 	Chan *c;
68 
69 	USED(spec);
70 	c = newchan();
71 	c->qid = (Qid){CHDIR, 0};
72 	c->type = devno(tc, 0);
73 	return c;
74 }
75 
76 Chan *
77 devclone(Chan *c, Chan *nc)
78 {
79 	if(c->flag & COPEN)
80 		panic("clone of open file type %C\n", devchar[c->type]);
81 	if(nc == 0)
82 		nc = newchan();
83 	nc->type = c->type;
84 	nc->dev = c->dev;
85 	nc->mode = c->mode;
86 	nc->qid = c->qid;
87 	nc->offset = c->offset;
88 	nc->flag = c->flag;
89 	nc->mnt = c->mnt;
90 	nc->mountid = c->mountid;
91 	nc->aux = c->aux;
92 	nc->mchan = c->mchan;
93 	nc->mqid = c->mqid;
94 	return nc;
95 }
96 
97 int
98 devwalk(Chan *c, char *name, Dirtab *tab, int ntab, Devgen *gen)
99 {
100 	long i;
101 	Dir dir;
102 
103 	isdir(c);
104 	if(name[0]=='.' && name[1]==0)
105 		return 1;
106 	for(i=0;; i++)
107 		switch((*gen)(c, tab, ntab, i, &dir)){
108 		case -1:
109 			strncpy(u->error, Enonexist, NAMELEN);
110 			return 0;
111 		case 0:
112 			continue;
113 		case 1:
114 			if(strcmp(name, dir.name) == 0){
115 				c->qid = dir.qid;
116 				return 1;
117 			}
118 			continue;
119 		}
120 	return 1;	/* not reached */
121 }
122 
123 void
124 devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen)
125 {
126 	int i;
127 	Dir dir;
128 
129 	for(i=0;; i++)
130 		switch((*gen)(c, tab, ntab, i, &dir)){
131 		case -1:
132 			/*
133 			 *  given a channel, we cannot derive the directory name
134 			 *  that the channel was generated from since it was lost
135 			 *  by namec.
136 			 */
137 			if(c->qid.path & CHDIR){
138 				devdir(c, c->qid, ".", 0L, eve, CHDIR|0775, &dir);
139 				convD2M(&dir, db);
140 				return;
141 			}
142 			print("%s %s: devstat %C %lux\n", u->p->text, u->p->user,
143 							devchar[c->type], c->qid.path);
144 			error(Enonexist);
145 		case 0:
146 			break;
147 		case 1:
148 			if(eqqid(c->qid, dir.qid)){
149 				if(c->flag&CMSG)
150 					dir.mode |= CHMOUNT;
151 				convD2M(&dir, db);
152 				return;
153 			}
154 			break;
155 		}
156 }
157 
158 long
159 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
160 {
161 	long k, m;
162 	Dir dir;
163 
164 	k = c->offset/DIRLEN;
165 	for(m=0; m<n; k++)
166 		switch((*gen)(c, tab, ntab, k, &dir)){
167 		case -1:
168 			return m;
169 
170 		case 0:
171 			c->offset += DIRLEN;
172 			break;
173 
174 		case 1:
175 			convD2M(&dir, d);
176 			m += DIRLEN;
177 			d += DIRLEN;
178 			break;
179 		}
180 	return m;
181 }
182 
183 Chan *
184 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
185 {
186 	int i;
187 	Dir dir;
188 	ulong t, mode;
189 	static int access[] = { 0400, 0200, 0600, 0100 };
190 
191 	for(i=0;; i++)
192 		switch((*gen)(c, tab, ntab, i, &dir)){
193 		case -1:
194 			goto Return;
195 		case 0:
196 			break;
197 		case 1:
198 			if(eqqid(c->qid, dir.qid)) {
199 				if(strcmp(u->p->user, dir.uid) == 0)	/* User */
200 					mode = dir.mode;
201 				else if(strcmp(u->p->user, eve) == 0)	/* eve is group */
202 					mode = dir.mode<<3;
203 				else
204 					mode = dir.mode<<6;		/* Other */
205 
206 				t = access[omode&3];
207 				if((t & mode) == t)
208 					goto Return;
209 				error(Eperm);
210 			}
211 			break;
212 		}
213     Return:
214 	c->offset = 0;
215 	if((c->qid.path&CHDIR) && omode!=OREAD)
216 		error(Eperm);
217 	c->mode = openmode(omode);
218 	c->flag |= COPEN;
219 	return c;
220 }
221