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