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