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