xref: /csrg-svn/sys/kern/kern_descrip.c (revision 43406)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)kern_descrip.c	7.13 (Berkeley) 06/21/90
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "syscontext.h"
23 #include "kernel.h"
24 #include "vnode.h"
25 #include "proc.h"
26 #include "file.h"
27 #include "socket.h"
28 #include "socketvar.h"
29 #include "stat.h"
30 #include "ioctl.h"
31 
32 #define	p_devtmp	p_logname[11]
33 
34 /*
35  * Descriptor management.
36  */
37 
38 /*
39  * System calls on descriptors.
40  */
41 /* ARGSUSED */
42 getdtablesize(p, uap, retval)
43 	struct proc *p;
44 	struct args *uap;
45 	int *retval;
46 {
47 
48 	*retval = NOFILE;
49 	RETURN (0);
50 }
51 
52 /*
53  * Duplicate a file descriptor.
54  */
55 /* ARGSUSED */
56 dup(p, uap, retval)
57 	struct proc *p;
58 	struct args {
59 		int	i;
60 	} *uap;
61 	int *retval;
62 {
63 	struct file *fp;
64 	int fd, error;
65 
66 	/*
67 	 * XXX Compatibility
68 	 */
69 	if (uap->i &~ 077) { uap->i &= 077; RETURN (dup2(p, uap, retval)); }
70 
71 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
72 		RETURN (EBADF);
73 	if (error = ufalloc(0, &fd))
74 		RETURN (error);
75 	u.u_ofile[fd] = fp;
76 	u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
77 	fp->f_count++;
78 	if (fd > u.u_lastfile)
79 		u.u_lastfile = fd;
80 	*retval = fd;
81 	RETURN (0);
82 }
83 
84 /*
85  * Duplicate a file descriptor to a particular value.
86  */
87 /* ARGSUSED */
88 dup2(p, uap, retval)
89 	struct proc *p;
90 	register struct args {
91 		int	i;
92 		int	j;
93 	} *uap;
94 	int *retval;
95 {
96 	register struct file *fp;
97 	int error;
98 
99 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
100 		RETURN (EBADF);
101 	if (uap->j < 0 || uap->j >= NOFILE)
102 		RETURN (EBADF);
103 	*retval = uap->j;
104 	if (uap->i == uap->j)
105 		RETURN (0);
106 	if (u.u_ofile[uap->j]) {
107 		if (u.u_pofile[uap->j] & UF_MAPPED)
108 			munmapfd(uap->j);
109 		error = closef(u.u_ofile[uap->j]);
110 	}
111 	u.u_ofile[uap->j] = fp;
112 	u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
113 	fp->f_count++;
114 	if (uap->j > u.u_lastfile)
115 		u.u_lastfile = uap->j;
116 	/*
117 	 * dup2() must succeed even though the close had an error.
118 	 */
119 	error = 0;		/* XXX */
120 	RETURN (error);
121 }
122 
123 /*
124  * The file control system call.
125  */
126 /* ARGSUSED */
127 fcntl(p, uap, retval)
128 	struct proc *p;
129 	register struct args {
130 		int	fdes;
131 		int	cmd;
132 		int	arg;
133 	} *uap;
134 	int *retval;
135 {
136 	register struct file *fp;
137 	register char *pop;
138 	int i, error;
139 
140 	if ((unsigned)uap->fdes >= NOFILE ||
141 	    (fp = u.u_ofile[uap->fdes]) == NULL)
142 		RETURN (EBADF);
143 	pop = &u.u_pofile[uap->fdes];
144 	switch(uap->cmd) {
145 	case F_DUPFD:
146 		if (uap->arg < 0 || uap->arg >= NOFILE)
147 			RETURN (EINVAL);
148 		if (error = ufalloc(uap->arg, &i))
149 			RETURN (error);
150 		u.u_ofile[i] = fp;
151 		u.u_pofile[i] = *pop &~ UF_EXCLOSE;
152 		fp->f_count++;
153 		if (i > u.u_lastfile)
154 			u.u_lastfile = i;
155 		*retval = i;
156 		RETURN (0);
157 
158 	case F_GETFD:
159 		*retval = *pop & 1;
160 		RETURN (0);
161 
162 	case F_SETFD:
163 		*pop = (*pop &~ 1) | (uap->arg & 1);
164 		RETURN (0);
165 
166 	case F_GETFL:
167 		*retval = fp->f_flag + FOPEN;
168 		RETURN (0);
169 
170 	case F_SETFL:
171 		fp->f_flag &= FCNTLCANT;
172 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
173 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
174 			RETURN (error);
175 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
176 			(void) fset(fp, FNDELAY, 0);
177 		RETURN (error);
178 
179 	case F_GETOWN:
180 		RETURN (fgetown(fp, retval));
181 
182 	case F_SETOWN:
183 		RETURN (fsetown(fp, uap->arg));
184 
185 	default:
186 		RETURN (EINVAL);
187 	}
188 	/* NOTREACHED */
189 }
190 
191 fset(fp, bit, value)
192 	struct file *fp;
193 	int bit, value;
194 {
195 
196 	if (value)
197 		fp->f_flag |= bit;
198 	else
199 		fp->f_flag &= ~bit;
200 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
201 	    (caddr_t)&value));
202 }
203 
204 fgetown(fp, valuep)
205 	struct file *fp;
206 	int *valuep;
207 {
208 	int error;
209 
210 	switch (fp->f_type) {
211 
212 	case DTYPE_SOCKET:
213 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
214 		return (0);
215 
216 	default:
217 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
218 		*valuep = -*valuep;
219 		return (error);
220 	}
221 }
222 
223 fsetown(fp, value)
224 	struct file *fp;
225 	int value;
226 {
227 
228 	if (fp->f_type == DTYPE_SOCKET) {
229 		((struct socket *)fp->f_data)->so_pgid = value;
230 		return (0);
231 	}
232 	if (value > 0) {
233 		struct proc *p = pfind(value);
234 		if (p == 0)
235 			return (ESRCH);
236 		value = p->p_pgrp->pg_id;
237 	} else
238 		value = -value;
239 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
240 }
241 
242 fioctl(fp, cmd, value)
243 	struct file *fp;
244 	int cmd;
245 	caddr_t value;
246 {
247 
248 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
249 }
250 
251 /*
252  * Close a file descriptor.
253  */
254 /* ARGSUSED */
255 close(p, uap, retval)
256 	struct proc *p;
257 	struct args {
258 		int	fdes;
259 	} *uap;
260 	int *retval;
261 {
262 	register struct file *fp;
263 	register u_char *pf;
264 
265 	if ((unsigned)uap->fdes >= NOFILE ||
266 	    (fp = u.u_ofile[uap->fdes]) == NULL)
267 		RETURN (EBADF);
268 	pf = (u_char *)&u.u_pofile[uap->fdes];
269 	if (*pf & UF_MAPPED)
270 		munmapfd(uap->fdes);
271 	u.u_ofile[uap->fdes] = NULL;
272 	while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
273 		u.u_lastfile--;
274 	*pf = 0;
275 	RETURN (closef(fp));
276 }
277 
278 /*
279  * Return status information about a file descriptor.
280  */
281 /* ARGSUSED */
282 fstat(p, uap, retval)
283 	struct proc *p;
284 	register struct args {
285 		int	fdes;
286 		struct	stat *sb;
287 	} *uap;
288 	int *retval;
289 {
290 	register struct file *fp;
291 	struct stat ub;
292 	int error;
293 
294 	if ((unsigned)uap->fdes >= NOFILE ||
295 	    (fp = u.u_ofile[uap->fdes]) == NULL)
296 		RETURN (EBADF);
297 	switch (fp->f_type) {
298 
299 	case DTYPE_VNODE:
300 		error = vn_stat((struct vnode *)fp->f_data, &ub);
301 		break;
302 
303 	case DTYPE_SOCKET:
304 		error = soo_stat((struct socket *)fp->f_data, &ub);
305 		break;
306 
307 	default:
308 		panic("fstat");
309 		/*NOTREACHED*/
310 	}
311 	if (error == 0)
312 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
313 	RETURN (error);
314 }
315 
316 /*
317  * Allocate a user file descriptor.
318  */
319 ufalloc(want, result)
320 	register int want;
321 	int *result;
322 {
323 
324 	for (; want < NOFILE; want++) {
325 		if (u.u_ofile[want] == NULL) {
326 			u.u_pofile[want] = 0;
327 			if (want > u.u_lastfile)
328 				u.u_lastfile = want;
329 			*result = want;
330 			return (0);
331 		}
332 	}
333 	return (EMFILE);
334 }
335 
336 /*
337  * Check to see if any user file descriptors are available.
338  */
339 ufavail()
340 {
341 	register int i, avail = 0;
342 
343 	for (i = 0; i < NOFILE; i++)
344 		if (u.u_ofile[i] == NULL)
345 			avail++;
346 	return (avail);
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 falloc(resultfp, resultfd)
357 	struct file **resultfp;
358 	int *resultfd;
359 {
360 	register struct file *fp;
361 	int error, i;
362 
363 	if (error = ufalloc(0, &i))
364 		return (error);
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 	return (ENFILE);
375 slot:
376 	u.u_ofile[i] = fp;
377 	fp->f_count = 1;
378 	fp->f_data = 0;
379 	fp->f_offset = 0;
380 	fp->f_cred = u.u_cred;
381 	crhold(fp->f_cred);
382 	lastf = fp + 1;
383 	if (resultfp)
384 		*resultfp = fp;
385 	if (resultfd)
386 		*resultfd = i;
387 	return (0);
388 }
389 
390 /*
391  * Internal form of close.
392  * Decrement reference count on file structure.
393  */
394 closef(fp)
395 	register struct file *fp;
396 {
397 	int error;
398 
399 	if (fp == NULL)
400 		return (0);
401 	if (fp->f_count > 1) {
402 		fp->f_count--;
403 		return (0);
404 	}
405 	if (fp->f_count < 1)
406 		panic("closef: count < 1");
407 	error = (*fp->f_ops->fo_close)(fp);
408 	crfree(fp->f_cred);
409 	fp->f_count = 0;
410 	return (error);
411 }
412 
413 /*
414  * Apply an advisory lock on a file descriptor.
415  */
416 /* ARGSUSED */
417 flock(p, uap, retval)
418 	struct proc *p;
419 	register struct args {
420 		int	fdes;
421 		int	how;
422 	} *uap;
423 	int *retval;
424 {
425 	register struct file *fp;
426 
427 	if ((unsigned)uap->fdes >= NOFILE ||
428 	    (fp = u.u_ofile[uap->fdes]) == NULL)
429 		RETURN (EBADF);
430 	if (fp->f_type != DTYPE_VNODE)
431 		RETURN (EOPNOTSUPP);
432 	if (uap->how & LOCK_UN) {
433 		vn_unlock(fp, FSHLOCK|FEXLOCK);
434 		RETURN (0);
435 	}
436 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
437 		RETURN (0);				/* error? */
438 	if (uap->how & LOCK_EX)
439 		uap->how &= ~LOCK_SH;
440 	/* avoid work... */
441 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
442 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
443 		RETURN (0);
444 	RETURN (vn_lock(fp, uap->how));
445 }
446 
447 /*
448  * File Descriptor pseudo-device driver (/dev/fd/).
449  *
450  * Opening minor device N dup()s the file (if any) connected to file
451  * descriptor N belonging to the calling process.  Note that this driver
452  * consists of only the ``open()'' routine, because all subsequent
453  * references to this file will be direct to the other driver.
454  */
455 /* ARGSUSED */
456 fdopen(dev, mode, type)
457 	dev_t dev;
458 	int mode, type;
459 {
460 	struct proc *p = u.u_procp;		/* XXX */
461 
462 	/*
463 	 * XXX Kludge: set p->p_devtmp to contain the value of the
464 	 * the file descriptor being sought for duplication. The error
465 	 * return ensures that the vnode for this device will be released
466 	 * by vn_open. Open will detect this special error and take the
467 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
468 	 * will simply report the error.
469 	 */
470 	p->p_devtmp = minor(dev);
471 	return (ENODEV);
472 }
473 
474 /*
475  * Duplicate the specified descriptor to a free descriptor.
476  */
477 dupfdopen(indx, dfd, mode)
478 	register int indx, dfd;
479 	int mode;
480 {
481 	register struct file *wfp;
482 	struct file *fp;
483 
484 	/*
485 	 * If the to-be-dup'd fd number is greater than the allowed number
486 	 * of file descriptors, or the fd to be dup'd has already been
487 	 * closed, reject.  Note, check for new == old is necessary as
488 	 * falloc could allocate an already closed to-be-dup'd descriptor
489 	 * as the new descriptor.
490 	 */
491 	fp = u.u_ofile[indx];
492 	if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL ||
493 	    fp == wfp)
494 		return (EBADF);
495 
496 	/*
497 	 * Check that the mode the file is being opened for is a subset
498 	 * of the mode of the existing descriptor.
499 	 */
500 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
501 		return (EACCES);
502 	u.u_ofile[indx] = wfp;
503 	u.u_pofile[indx] = u.u_pofile[dfd];
504 	wfp->f_count++;
505 	if (indx > u.u_lastfile)
506 		u.u_lastfile = indx;
507 	return (0);
508 }
509