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