xref: /csrg-svn/sys/kern/kern_descrip.c (revision 8029)
1 /*	kern_descrip.c	5.6	82/09/04	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/kernel.h"
8 #include "../h/inode.h"
9 #include "../h/proc.h"
10 #include "../h/conf.h"
11 #include "../h/file.h"
12 #include "../h/inline.h"
13 #include "../h/socket.h"
14 #include "../h/socketvar.h"
15 #include "../h/mount.h"
16 
17 #include "../h/descrip.h"
18 
19 /*
20  * Descriptor management.
21  */
22 
23 /*
24  * TODO:
25  *	getf should be renamed
26  *	ufalloc side effects are gross
27  */
28 
29 /*
30  * System calls on descriptors.
31  */
32 getdtablesize()
33 {
34 
35 	u.u_r.r_val1 = NOFILE;
36 }
37 
38 dup()
39 {
40 	register struct a {
41 		int	i;
42 	} *uap = (struct a *) u.u_ap;
43 	struct file *fp;
44 	int j;
45 
46 	if (uap->i &~ 077) { uap->i &= 077; dup2(); return; }	/* XXX */
47 
48 	fp = getf(uap->i);
49 	if (fp == 0)
50 		return;
51 	j = ufalloc();
52 	if (j < 0)
53 		return;
54 	dupit(j, fp, u.u_pofile[uap->i] & (RDLOCK|WRLOCK));
55 }
56 
57 dup2()
58 {
59 	register struct a {
60 		int	i, j;
61 	} *uap = (struct a *) u.u_ap;
62 	register struct file *fp;
63 
64 	fp = getf(uap->i);
65 	if (fp == 0)
66 		return;
67 	if (uap->j < 0 || uap->j >= NOFILE) {
68 		u.u_error = EBADF;
69 		return;
70 	}
71 	u.u_r.r_val1 = uap->j;
72 	if (uap->i == uap->j)
73 		return;
74 	if (u.u_ofile[uap->j]) {
75 		closef(u.u_ofile[uap->j], 0, u.u_pofile[uap->j]);
76 		if (u.u_error)
77 			return;
78 		/* u.u_ofile[uap->j] = 0; */
79 		/* u.u_pofile[uap->j] = 0; */
80 	}
81 	dupit(uap->j, fp, u.u_pofile[uap->i] & (RDLOCK|WRLOCK));
82 }
83 
84 dupit(fd, fp, lockflags)
85 	int fd;
86 	register struct file *fp;
87 	register int lockflags;
88 {
89 
90 	u.u_ofile[fd] = fp;
91 	u.u_pofile[fd] = lockflags;
92 	fp->f_count++;
93 	if (lockflags&RDLOCK)
94 		fp->f_inode->i_rdlockc++;
95 	if (lockflags&WRLOCK)
96 		fp->f_inode->i_wrlockc++;
97 }
98 
99 close()
100 {
101 	register struct a {
102 		int	i;
103 	} *uap = (struct a *)u.u_ap;
104 	register struct file *fp;
105 
106 	fp = getf(uap->i);
107 	if (fp == 0)
108 		return;
109 	closef(fp, 0, u.u_pofile[uap->i]);
110 	/* WHAT IF u.u_error ? */
111 	u.u_ofile[uap->i] = NULL;
112 	u.u_pofile[uap->i] = 0;
113 }
114 
115 getdprop()
116 {
117 	register struct a {
118 		int	d;
119 		struct	dtype *dtypeb;
120 	} *uap = (struct a *)u.u_ap;
121 	register struct file *fp;
122 	struct dtype adtype;
123 
124 	fp = getf(uap->d);
125 	if (fp == 0)
126 		return;
127 	adtype.dt_type = 0;		/* XXX */
128 	adtype.dt_protocol = 0;		/* XXX */
129 	if (copyout((caddr_t)&adtype, (caddr_t)uap->dtypeb,
130 	    sizeof (struct dtype)) < 0) {
131 		u.u_error = EFAULT;
132 		return;
133 	}
134 }
135 
136 wrap()
137 {
138 	register struct a {
139 		int	d;
140 		struct	dtype *dtypeb;
141 	} *uap = (struct a *)u.u_ap;
142 	register struct file *fp;
143 	struct dtype adtype;
144 
145 	fp = getf(uap->d);
146 	if (fp == 0)
147 		return;
148 	if (copyin((caddr_t)uap->dtypeb, (caddr_t)&adtype,
149 	    sizeof (struct dtype)) < 0) {
150 		u.u_error = EFAULT;
151 		return;
152 	}
153 	/* DO WRAP */
154 }
155 
156 select()
157 {
158 
159 }
160 
161 int	nselcoll;
162 /*
163  * Select system call.
164  */
165 oselect()
166 {
167 	register struct uap  {
168 		int	nfd;
169 		fd_set	*rp, *wp;
170 		struct	timeval *tv;
171 	} *uap = (struct uap *)u.u_ap;
172 	fd_set rd, wr;
173 	int nfds = 0, readable = 0, writeable = 0;
174 	struct timeval atv, origin, now;
175 	int s, tsel, ncoll, rem;
176 
177 	if (uap->nfd > NOFILE)
178 		uap->nfd = NOFILE;
179 	if (uap->nfd < 0) {
180 		u.u_error = EBADF;
181 		return;
182 	}
183 	if (uap->tv) {
184 		if (copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv))) {
185 			u.u_error = EFAULT;
186 			return;
187 		}
188 	} else
189 		timerclear(&atv);
190 	if (uap->rp && copyin((caddr_t)uap->rp,(caddr_t)&rd,sizeof(fd_set)))
191 		return;
192 	if (uap->wp && copyin((caddr_t)uap->wp,(caddr_t)&wr,sizeof(fd_set)))
193 		return;
194 retry:
195 	s = spl7(); now = time; splx(s);
196 	ncoll = nselcoll;
197 	u.u_procp->p_flag |= SSEL;
198 	if (uap->rp)
199 		readable = selscan(uap->nfd, rd, &nfds, FREAD);
200 	if (uap->wp)
201 		writeable = selscan(uap->nfd, wr, &nfds, FWRITE);
202 	if (u.u_error)
203 		goto done;
204 	if (readable || writeable)
205 		goto done;
206 	if (!timerisset(&atv))
207 		goto done;
208 	s = spl6();
209 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
210 		u.u_procp->p_flag &= ~SSEL;
211 		splx(s);
212 		goto retry;
213 	}
214 	u.u_procp->p_flag &= ~SSEL;
215 	tsel = tsleep((caddr_t)&selwait, PZERO+1, &atv);
216 	splx(s);
217 	switch (tsel) {
218 
219 	case TS_OK:
220 		now = time;
221 		timevalsub(&now, &origin);
222 		timevalsub(&atv, now);
223 		if (atv.tv_sec < 0 || atv.tv_usec < 0)
224 			timerclear(&atv);
225 		goto retry;
226 
227 	case TS_SIG:
228 		u.u_error = EINTR;
229 		return;
230 
231 	case TS_TIME:
232 		break;
233 	}
234 done:
235 	rd.fds_bits[0] = readable;
236 	wr.fds_bits[0] = writeable;
237 	s = sizeof (fd_set);
238 	if (s * NBBY > uap->nfd)
239 		s = (uap->nfd + NBBY - 1) / NBBY;
240 	u.u_r.r_val1 = nfds;
241 	if (uap->rp)
242 		(void) copyout((caddr_t)&rd, (caddr_t)uap->rp, sizeof(fd_set));
243 	if (uap->wp)
244 		(void) copyout((caddr_t)&wr, (caddr_t)uap->wp, sizeof(fd_set));
245 }
246 
247 selscan(nfd, fds, nfdp, flag)
248 	int nfd;
249 	fd_set fds;
250 	int *nfdp, flag;
251 {
252 	struct file *fp;
253 	struct inode *ip;
254 	register int bits;
255 	int i, able, res = 0;
256 
257 	bits = fds.fds_bits[0];
258 	while (i = ffs(bits)) {
259 		if (i > nfd)
260 			break;
261 		bits &= ~(1<<(i-1));
262 		fp = u.u_ofile[i-1];
263 		if (fp == NULL) {
264 			u.u_error = EBADF;
265 			return (0);
266 		}
267 		if (fp->f_type == DTYPE_SOCKET)
268 			able = soselect(fp->f_socket, flag);
269 		else {
270 			ip = fp->f_inode;
271 			switch (ip->i_mode & IFMT) {
272 
273 			case IFCHR:
274 				able =
275 				    (*cdevsw[major(ip->i_rdev)].d_select)
276 					(ip->i_rdev, flag);
277 				break;
278 
279 			case IFBLK:
280 			case IFREG:
281 			case IFDIR:
282 				able = 1;
283 				break;
284 			}
285 
286 		}
287 		if (able) {
288 			res |= (1<<(i-1));
289 			(*nfdp)++;
290 		}
291 	}
292 	return (res);
293 }
294 
295 /*ARGSUSED*/
296 seltrue(dev, flag)
297 	dev_t dev;
298 	int flag;
299 {
300 
301 	return (1);
302 }
303 
304 selwakeup(p, coll)
305 	register struct proc *p;
306 	int coll;
307 {
308 	int s;
309 
310 	if (coll) {
311 		nselcoll++;
312 		wakeup((caddr_t)&selwait);
313 	}
314 	if (p) {
315 		if (p->p_wchan == (caddr_t)&selwait)
316 			setrun(p);
317 		else {
318 			s = spl6();
319 			if (p->p_flag & SSEL)
320 				p->p_flag &= ~SSEL;
321 			splx(s);
322 		}
323 	}
324 }
325 
326 revoke()
327 {
328 
329 	/* XXX */
330 }
331 
332 /*
333  * Allocate a user file descriptor.
334  */
335 ufalloc()
336 {
337 	register i;
338 
339 	for (i=0; i<NOFILE; i++)
340 		if (u.u_ofile[i] == NULL) {
341 			u.u_r.r_val1 = i;
342 			u.u_pofile[i] = 0;
343 			return (i);
344 		}
345 	u.u_error = EMFILE;
346 	return (-1);
347 }
348 
349 struct	file *lastf;
350 /*
351  * Allocate a user file descriptor
352  * and a file structure.
353  * Initialize the descriptor
354  * to point at the file structure.
355  */
356 struct file *
357 falloc()
358 {
359 	register struct file *fp;
360 	register i;
361 
362 	i = ufalloc();
363 	if (i < 0)
364 		return (NULL);
365 	if (lastf == 0)
366 		lastf = file;
367 	for (fp = lastf; fp < fileNFILE; fp++)
368 		if (fp->f_count == 0)
369 			goto slot;
370 	for (fp = file; fp < lastf; fp++)
371 		if (fp->f_count == 0)
372 			goto slot;
373 	tablefull("file");
374 	u.u_error = ENFILE;
375 	return (NULL);
376 slot:
377 	u.u_ofile[i] = fp;
378 	fp->f_count++;
379 	fp->f_offset = 0;
380 	fp->f_inode = 0;
381 	lastf = fp + 1;
382 	return (fp);
383 }
384 /*
385  * Convert a user supplied file descriptor into a pointer
386  * to a file structure.  Only task is to check range of the descriptor.
387  * Critical paths should use the GETF macro, defined in inline.h.
388  */
389 struct file *
390 getf(f)
391 	register int f;
392 {
393 	register struct file *fp;
394 
395 	if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
396 		u.u_error = EBADF;
397 		return (NULL);
398 	}
399 	return (fp);
400 }
401 
402 /*
403  * Internal form of close.
404  * Decrement reference count on
405  * file structure.
406  * Also make sure the pipe protocol
407  * does not constipate.
408  *
409  * Decrement reference count on the inode following
410  * removal to the referencing file structure.
411  * Call device handler on last close.
412  * Nouser indicates that the user isn't available to present
413  * errors to.
414  *
415  * Handling locking at this level is RIDICULOUS.
416  */
417 closef(fp, nouser, flags)
418 	register struct file *fp;
419 	int nouser, flags;
420 {
421 	register struct inode *ip;
422 	register struct mount *mp;
423 	int flag, mode;
424 	dev_t dev;
425 	register int (*cfunc)();
426 
427 	if (fp == NULL)
428 		return;
429 	if (fp->f_count > 1) {
430 		fp->f_count--;
431 		return;
432 	}
433 	if (fp->f_type == DTYPE_SOCKET) {
434 		u.u_error = 0;			/* XXX */
435 		soclose(fp->f_socket, nouser);
436 		if (nouser == 0 && u.u_error)
437 			return;
438 		fp->f_socket = 0;
439 		fp->f_count = 0;
440 		return;
441 	}
442 	flag = fp->f_flag;
443 	ip = fp->f_inode;
444 	dev = (dev_t)ip->i_rdev;
445 	mode = ip->i_mode & IFMT;
446 	flags &= RDLOCK|WRLOCK;			/* conservative */
447 	if (flags)
448 		funlocki(ip, flags);
449 	ilock(ip);
450 	iput(ip);
451 	fp->f_count = 0;
452 
453 	switch (mode) {
454 
455 	case IFCHR:
456 		cfunc = cdevsw[major(dev)].d_close;
457 		break;
458 
459 	case IFBLK:
460 		/*
461 		 * We don't want to really close the device if it is mounted
462 		 */
463 		for (mp = mount; mp < &mount[NMOUNT]; mp++)
464 			if (mp->m_bufp != NULL && mp->m_dev == dev)
465 				return;
466 		cfunc = bdevsw[major(dev)].d_close;
467 		break;
468 
469 	default:
470 		return;
471 	}
472 	for (fp = file; fp < fileNFILE; fp++) {
473 		if (fp->f_type == DTYPE_SOCKET)		/* XXX */
474 			continue;
475 		if (fp->f_count && (ip = fp->f_inode) &&
476 		    ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
477 			return;
478 	}
479 	if (mode == IFBLK) {
480 		/*
481 		 * On last close of a block device (that isn't mounted)
482 		 * we must invalidate any in core blocks
483 		 */
484 		bflush(dev);
485 		binval(dev);
486 	}
487 	(*cfunc)(dev, flag, fp);
488 }
489