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