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