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