xref: /csrg-svn/sys/kern/kern_descrip.c (revision 28201)
1 /*
2  * Copyright (c) 1982 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)kern_descrip.c	6.13 (Berkeley) 05/15/86
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "dir.h"
12 #include "user.h"
13 #include "kernel.h"
14 #include "inode.h"
15 #include "proc.h"
16 #include "file.h"
17 #include "socket.h"
18 #include "socketvar.h"
19 #include "mount.h"
20 #include "stat.h"
21 
22 #include "ioctl.h"
23 
24 /*
25  * Descriptor management.
26  */
27 
28 /*
29  * TODO:
30  *	eliminate u.u_error side effects
31  */
32 
33 /*
34  * System calls on descriptors.
35  */
36 getdtablesize()
37 {
38 
39 	u.u_r.r_val1 = NOFILE;
40 }
41 
42 getdopt()
43 {
44 
45 }
46 
47 setdopt()
48 {
49 
50 }
51 
52 dup()
53 {
54 	register struct a {
55 		int	i;
56 	} *uap = (struct a *) u.u_ap;
57 	struct file *fp;
58 	int j;
59 
60 	if (uap->i &~ 077) { uap->i &= 077; dup2(); return; }	/* XXX */
61 
62 	GETF(fp, uap->i);
63 	j = ufalloc(0);
64 	if (j < 0)
65 		return;
66 	dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE);
67 }
68 
69 dup2()
70 {
71 	register struct a {
72 		int	i, j;
73 	} *uap = (struct a *) u.u_ap;
74 	register struct file *fp;
75 
76 	GETF(fp, uap->i);
77 	if (uap->j < 0 || uap->j >= NOFILE) {
78 		u.u_error = EBADF;
79 		return;
80 	}
81 	u.u_r.r_val1 = uap->j;
82 	if (uap->i == uap->j)
83 		return;
84 	if (u.u_ofile[uap->j]) {
85 		if (u.u_pofile[uap->j] & UF_MAPPED)
86 			munmapfd(uap->j);
87 		closef(u.u_ofile[uap->j]);
88 		if (u.u_error)
89 			return;
90 	}
91 	dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE);
92 }
93 
94 dupit(fd, fp, flags)
95 	int fd;
96 	register struct file *fp;
97 	register int flags;
98 {
99 
100 	u.u_ofile[fd] = fp;
101 	u.u_pofile[fd] = flags;
102 	fp->f_count++;
103 	if (fd > u.u_lastfile)
104 		u.u_lastfile = fd;
105 }
106 
107 /*
108  * The file control system call.
109  */
110 fcntl()
111 {
112 	register struct file *fp;
113 	register struct a {
114 		int	fdes;
115 		int	cmd;
116 		int	arg;
117 	} *uap;
118 	register i;
119 	register char *pop;
120 
121 	uap = (struct a *)u.u_ap;
122 	GETF(fp, uap->fdes);
123 	pop = &u.u_pofile[uap->fdes];
124 	switch(uap->cmd) {
125 	case F_DUPFD:
126 		i = uap->arg;
127 		if (i < 0 || i >= NOFILE) {
128 			u.u_error = EINVAL;
129 			return;
130 		}
131 		if ((i = ufalloc(i)) < 0)
132 			return;
133 		dupit(i, fp, *pop &~ UF_EXCLOSE);
134 		break;
135 
136 	case F_GETFD:
137 		u.u_r.r_val1 = *pop & 1;
138 		break;
139 
140 	case F_SETFD:
141 		*pop = (*pop &~ 1) | (uap->arg & 1);
142 		break;
143 
144 	case F_GETFL:
145 		u.u_r.r_val1 = fp->f_flag+FOPEN;
146 		break;
147 
148 	case F_SETFL:
149 		fp->f_flag &= FCNTLCANT;
150 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
151 		u.u_error = fset(fp, FNDELAY, fp->f_flag & FNDELAY);
152 		if (u.u_error)
153 			break;
154 		u.u_error = fset(fp, FASYNC, fp->f_flag & FASYNC);
155 		if (u.u_error)
156 			(void) fset(fp, FNDELAY, 0);
157 		break;
158 
159 	case F_GETOWN:
160 		u.u_error = fgetown(fp, &u.u_r.r_val1);
161 		break;
162 
163 	case F_SETOWN:
164 		u.u_error = fsetown(fp, uap->arg);
165 		break;
166 
167 	default:
168 		u.u_error = EINVAL;
169 	}
170 }
171 
172 fset(fp, bit, value)
173 	struct file *fp;
174 	int bit, value;
175 {
176 
177 	if (value)
178 		fp->f_flag |= bit;
179 	else
180 		fp->f_flag &= ~bit;
181 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
182 	    (caddr_t)&value));
183 }
184 
185 fgetown(fp, valuep)
186 	struct file *fp;
187 	int *valuep;
188 {
189 	int error;
190 
191 	switch (fp->f_type) {
192 
193 	case DTYPE_SOCKET:
194 		*valuep = ((struct socket *)fp->f_data)->so_pgrp;
195 		return (0);
196 
197 	default:
198 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
199 		*valuep = -*valuep;
200 		return (error);
201 	}
202 }
203 
204 fsetown(fp, value)
205 	struct file *fp;
206 	int value;
207 {
208 
209 	if (fp->f_type == DTYPE_SOCKET) {
210 		((struct socket *)fp->f_data)->so_pgrp = value;
211 		return (0);
212 	}
213 	if (value > 0) {
214 		struct proc *p = pfind(value);
215 		if (p == 0)
216 			return (ESRCH);
217 		value = p->p_pgrp;
218 	} else
219 		value = -value;
220 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
221 }
222 
223 fioctl(fp, cmd, value)
224 	struct file *fp;
225 	int cmd;
226 	caddr_t value;
227 {
228 
229 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
230 }
231 
232 close()
233 {
234 	struct a {
235 		int	i;
236 	} *uap = (struct a *)u.u_ap;
237 	register int i = uap->i;
238 	register struct file *fp;
239 	register u_char *pf;
240 
241 	GETF(fp, i);
242 	pf = (u_char *)&u.u_pofile[i];
243 	if (*pf & UF_MAPPED)
244 		munmapfd(i);
245 	u.u_ofile[i] = NULL;
246 	while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
247 		u.u_lastfile--;
248 	*pf = 0;
249 	closef(fp);
250 	/* WHAT IF u.u_error ? */
251 }
252 
253 fstat()
254 {
255 	register struct file *fp;
256 	register struct a {
257 		int	fdes;
258 		struct	stat *sb;
259 	} *uap;
260 	struct stat ub;
261 
262 	uap = (struct a *)u.u_ap;
263 	GETF(fp, uap->fdes);
264 	switch (fp->f_type) {
265 
266 	case DTYPE_INODE:
267 		u.u_error = ino_stat((struct inode *)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(i)
287 	register int i;
288 {
289 
290 	for (; i < NOFILE; i++)
291 		if (u.u_ofile[i] == NULL) {
292 			u.u_r.r_val1 = i;
293 			u.u_pofile[i] = 0;
294 			if (i > u.u_lastfile)
295 				u.u_lastfile = i;
296 			return (i);
297 		}
298 	u.u_error = EMFILE;
299 	return (-1);
300 }
301 
302 ufavail()
303 {
304 	register int i, avail = 0;
305 
306 	for (i = 0; i < NOFILE; i++)
307 		if (u.u_ofile[i] == NULL)
308 			avail++;
309 	return (avail);
310 }
311 
312 struct	file *lastf;
313 /*
314  * Allocate a user file descriptor
315  * and a file structure.
316  * Initialize the descriptor
317  * to point at the file structure.
318  */
319 struct file *
320 falloc()
321 {
322 	register struct file *fp;
323 	register i;
324 
325 	i = ufalloc(0);
326 	if (i < 0)
327 		return (NULL);
328 	if (lastf == 0)
329 		lastf = file;
330 	for (fp = lastf; fp < fileNFILE; fp++)
331 		if (fp->f_count == 0)
332 			goto slot;
333 	for (fp = file; fp < lastf; fp++)
334 		if (fp->f_count == 0)
335 			goto slot;
336 	tablefull("file");
337 	u.u_error = ENFILE;
338 	return (NULL);
339 slot:
340 	u.u_ofile[i] = fp;
341 	fp->f_count = 1;
342 	fp->f_data = 0;
343 	fp->f_offset = 0;
344 	lastf = fp + 1;
345 	return (fp);
346 }
347 
348 /*
349  * Convert a user supplied file descriptor into a pointer
350  * to a file structure.  Only task is to check range of the descriptor.
351  * Critical paths should use the GETF macro.
352  */
353 struct file *
354 getf(f)
355 	register int f;
356 {
357 	register struct file *fp;
358 
359 	if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
360 		u.u_error = EBADF;
361 		return (NULL);
362 	}
363 	return (fp);
364 }
365 
366 /*
367  * Internal form of close.
368  * Decrement reference count on file structure.
369  */
370 closef(fp)
371 	register struct file *fp;
372 {
373 
374 	if (fp == NULL)
375 		return;
376 	if (fp->f_count > 1) {
377 		fp->f_count--;
378 		return;
379 	}
380 	(*fp->f_ops->fo_close)(fp);
381 	fp->f_count = 0;
382 }
383 
384 /*
385  * Apply an advisory lock on a file descriptor.
386  */
387 flock()
388 {
389 	register struct a {
390 		int	fd;
391 		int	how;
392 	} *uap = (struct a *)u.u_ap;
393 	register struct file *fp;
394 
395 	GETF(fp, uap->fd);
396 	if (fp->f_type != DTYPE_INODE) {
397 		u.u_error = EOPNOTSUPP;
398 		return;
399 	}
400 	if (uap->how & LOCK_UN) {
401 		ino_unlock(fp, FSHLOCK|FEXLOCK);
402 		return;
403 	}
404 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
405 		return;					/* error? */
406 	if (uap->how & LOCK_EX)
407 		uap->how &= ~LOCK_SH;
408 	/* avoid work... */
409 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
410 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
411 		return;
412 	u.u_error = ino_lock(fp, uap->how);
413 }
414