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