minor wording updates
[unix-history] / usr / src / sys / kern / kern_descrip.c
CommitLineData
da7c5cc6 1/*
7ddc4f96 2 * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
c4ec2128 3 * All rights reserved.
da7c5cc6 4 *
dbf0c423 5 * %sccs.include.redist.c%
c4ec2128 6 *
9e97623a 7 * @(#)kern_descrip.c 7.37 (Berkeley) %G%
da7c5cc6 8 */
40056b21 9
94368568
JB
10#include "param.h"
11#include "systm.h"
5e00df3b 12#include "filedesc.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"
a4128336 21#include "fcntl.h"
5e00df3b
KM
22#include "malloc.h"
23#include "syslog.h"
7ddc4f96 24#include "resourcevar.h"
4147b3f6
BJ
25
26/*
27 * Descriptor management.
28 */
c753a490
KM
29struct file *filehead; /* head of list of open files */
30int nfiles; /* actual number of open files */
4147b3f6 31
40056b21 32/*
4147b3f6 33 * System calls on descriptors.
40056b21 34 */
d5820a3c
CT
35struct getdtablesize_args {
36 int dummy;
37};
a53a698b
KM
38/* ARGSUSED */
39getdtablesize(p, uap, retval)
40 struct proc *p;
d5820a3c 41 struct getdtablesize_args *uap;
a53a698b 42 int *retval;
4147b3f6
BJ
43{
44
8429d022 45 *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
d9c2f47f 46 return (0);
4147b3f6
BJ
47}
48
a53a698b
KM
49/*
50 * Duplicate a file descriptor.
51 */
d5820a3c
CT
52struct dup_args {
53 int i;
54};
a53a698b
KM
55/* ARGSUSED */
56dup(p, uap, retval)
57 struct proc *p;
d5820a3c 58 struct dup_args *uap;
a53a698b
KM
59 int *retval;
60{
5e00df3b 61 register struct filedesc *fdp = p->p_fd;
a81e9a81 62 struct file *fp;
a53a698b 63 int fd, error;
4147b3f6 64
a53a698b
KM
65 /*
66 * XXX Compatibility
67 */
d9c2f47f 68 if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
4147b3f6 69
8429d022 70 if ((unsigned)uap->i >= fdp->fd_nfiles ||
7ddc4f96 71 (fp = fdp->fd_ofiles[uap->i]) == NULL)
d9c2f47f 72 return (EBADF);
8429d022 73 if (error = fdalloc(p, 0, &fd))
d9c2f47f 74 return (error);
7ddc4f96
MK
75 fdp->fd_ofiles[fd] = fp;
76 fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE;
a53a698b 77 fp->f_count++;
5e00df3b
KM
78 if (fd > fdp->fd_lastfile)
79 fdp->fd_lastfile = fd;
a53a698b 80 *retval = fd;
d9c2f47f 81 return (0);
4147b3f6
BJ
82}
83
a53a698b
KM
84/*
85 * Duplicate a file descriptor to a particular value.
86 */
d5820a3c
CT
87struct dup2_args {
88 u_int from;
89 u_int to;
90};
a53a698b
KM
91/* ARGSUSED */
92dup2(p, uap, retval)
93 struct proc *p;
d5820a3c 94 struct dup2_args *uap;
a53a698b 95 int *retval;
4147b3f6 96{
5e00df3b 97 register struct filedesc *fdp = p->p_fd;
4147b3f6 98 register struct file *fp;
7ddc4f96 99 register u_int old = uap->from, new = uap->to;
5e00df3b 100 int i, error;
40056b21 101
7ddc4f96
MK
102 if (old >= fdp->fd_nfiles ||
103 (fp = fdp->fd_ofiles[old]) == NULL ||
104 new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
d9c2f47f 105 return (EBADF);
7ddc4f96
MK
106 *retval = new;
107 if (old == new)
d9c2f47f 108 return (0);
7ddc4f96
MK
109 if (new >= fdp->fd_nfiles) {
110 if (error = fdalloc(p, new, &i))
5e00df3b 111 return (error);
7ddc4f96 112 if (new != i)
8429d022 113 panic("dup2: fdalloc");
7ddc4f96
MK
114 } else if (fdp->fd_ofiles[new]) {
115 if (fdp->fd_ofileflags[new] & UF_MAPPED)
116 (void) munmapfd(p, new);
117 /*
118 * dup2() must succeed even if the close has an error.
119 */
120 (void) closef(fdp->fd_ofiles[new], p);
4147b3f6 121 }
7ddc4f96
MK
122 fdp->fd_ofiles[new] = fp;
123 fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
a53a698b 124 fp->f_count++;
7ddc4f96
MK
125 if (new > fdp->fd_lastfile)
126 fdp->fd_lastfile = new;
127 return (0);
a81e9a81
SL
128}
129
88a7a62a
SL
130/*
131 * The file control system call.
132 */
d5820a3c
CT
133struct fcntl_args {
134 int fd;
135 int cmd;
136 int arg;
137};
a53a698b
KM
138/* ARGSUSED */
139fcntl(p, uap, retval)
140 struct proc *p;
d5820a3c 141 register struct fcntl_args *uap;
a53a698b
KM
142 int *retval;
143{
5e00df3b 144 register struct filedesc *fdp = p->p_fd;
a53a698b 145 register struct file *fp;
88a7a62a 146 register char *pop;
a4128336 147 struct vnode *vp;
208eb71b 148 int i, tmp, error, flg = F_POSIX;
a4128336 149 struct flock fl;
4147b3f6 150
8429d022 151 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
7ddc4f96 152 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
d9c2f47f 153 return (EBADF);
7ddc4f96 154 pop = &fdp->fd_ofileflags[uap->fd];
88a7a62a 155 switch(uap->cmd) {
85f01bd4 156 case F_DUPFD:
8429d022 157 if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
d9c2f47f 158 return (EINVAL);
8429d022 159 if (error = fdalloc(p, uap->arg, &i))
d9c2f47f 160 return (error);
7ddc4f96
MK
161 fdp->fd_ofiles[i] = fp;
162 fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE;
a53a698b 163 fp->f_count++;
5e00df3b
KM
164 if (i > fdp->fd_lastfile)
165 fdp->fd_lastfile = i;
a53a698b 166 *retval = i;
d9c2f47f 167 return (0);
12438177 168
85f01bd4 169 case F_GETFD:
a53a698b 170 *retval = *pop & 1;
d9c2f47f 171 return (0);
40056b21 172
85f01bd4 173 case F_SETFD:
88a7a62a 174 *pop = (*pop &~ 1) | (uap->arg & 1);
d9c2f47f 175 return (0);
12438177 176
85f01bd4 177 case F_GETFL:
f474c4c6 178 *retval = OFLAGS(fp->f_flag);
d9c2f47f 179 return (0);
12438177 180
85f01bd4 181 case F_SETFL:
f474c4c6
MK
182 fp->f_flag &= ~FCNTLFLAGS;
183 fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
ff0803f0 184 tmp = fp->f_flag & FNONBLOCK;
208eb71b
KM
185 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
186 if (error)
d9c2f47f 187 return (error);
ff0803f0 188 tmp = fp->f_flag & FASYNC;
208eb71b
KM
189 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
190 if (!error)
191 return (0);
ff0803f0 192 fp->f_flag &= ~FNONBLOCK;
208eb71b
KM
193 tmp = 0;
194 (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
d9c2f47f 195 return (error);
88a7a62a 196
85f01bd4 197 case F_GETOWN:
208eb71b
KM
198 if (fp->f_type == DTYPE_SOCKET) {
199 *retval = ((struct socket *)fp->f_data)->so_pgid;
200 return (0);
201 }
202 error = (*fp->f_ops->fo_ioctl)
203 (fp, (int)TIOCGPGRP, (caddr_t)retval, p);
204 *retval = -*retval;
205 return (error);
88a7a62a 206
85f01bd4 207 case F_SETOWN:
208eb71b
KM
208 if (fp->f_type == DTYPE_SOCKET) {
209 ((struct socket *)fp->f_data)->so_pgid = uap->arg;
210 return (0);
211 }
212 if (uap->arg <= 0) {
213 uap->arg = -uap->arg;
214 } else {
215 struct proc *p1 = pfind(uap->arg);
216 if (p1 == 0)
217 return (ESRCH);
218 uap->arg = p1->p_pgrp->pg_id;
219 }
220 return ((*fp->f_ops->fo_ioctl)
221 (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
88a7a62a 222
a4128336 223 case F_SETLKW:
208eb71b 224 flg |= F_WAIT;
a4128336
KM
225 /* Fall into F_SETLK */
226
227 case F_SETLK:
228 if (fp->f_type != DTYPE_VNODE)
229 return (EBADF);
230 vp = (struct vnode *)fp->f_data;
231 /* Copy in the lock structure */
232 error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
233 if (error)
234 return (error);
235 if (fl.l_whence == SEEK_CUR)
236 fl.l_start += fp->f_offset;
237 switch (fl.l_type) {
238
239 case F_RDLCK:
240 if ((fp->f_flag & FREAD) == 0)
241 return (EBADF);
9bd5ee04 242 p->p_flag |= SADVLCK;
208eb71b 243 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
a4128336
KM
244
245 case F_WRLCK:
246 if ((fp->f_flag & FWRITE) == 0)
247 return (EBADF);
9bd5ee04 248 p->p_flag |= SADVLCK;
208eb71b 249 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
a4128336
KM
250
251 case F_UNLCK:
208eb71b
KM
252 return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
253 F_POSIX));
a4128336
KM
254
255 default:
256 return (EINVAL);
257 }
258
259 case F_GETLK:
260 if (fp->f_type != DTYPE_VNODE)
261 return (EBADF);
262 vp = (struct vnode *)fp->f_data;
263 /* Copy in the lock structure */
264 error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
265 if (error)
266 return (error);
2975e814
KM
267 if (fl.l_whence == SEEK_CUR)
268 fl.l_start += fp->f_offset;
208eb71b 269 if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
a4128336
KM
270 return (error);
271 return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
272
88a7a62a 273 default:
d9c2f47f 274 return (EINVAL);
40056b21 275 }
a53a698b 276 /* NOTREACHED */
40056b21
BJ
277}
278
a53a698b
KM
279/*
280 * Close a file descriptor.
281 */
d5820a3c
CT
282struct close_args {
283 int fd;
284};
a53a698b
KM
285/* ARGSUSED */
286close(p, uap, retval)
287 struct proc *p;
d5820a3c 288 struct close_args *uap;
a53a698b
KM
289 int *retval;
290{
5e00df3b 291 register struct filedesc *fdp = p->p_fd;
88a7a62a 292 register struct file *fp;
8429d022 293 register int fd = uap->fd;
92438dfc 294 register u_char *pf;
3ebb7a40 295
8429d022 296 if ((unsigned)fd >= fdp->fd_nfiles ||
7ddc4f96 297 (fp = fdp->fd_ofiles[fd]) == NULL)
d9c2f47f 298 return (EBADF);
7ddc4f96 299 pf = (u_char *)&fdp->fd_ofileflags[fd];
92438dfc 300 if (*pf & UF_MAPPED)
8429d022 301 (void) munmapfd(p, fd);
7ddc4f96
MK
302 fdp->fd_ofiles[fd] = NULL;
303 while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
5e00df3b 304 fdp->fd_lastfile--;
8429d022
MK
305 if (fd < fdp->fd_freefile)
306 fdp->fd_freefile = fd;
92438dfc 307 *pf = 0;
8429d022 308 return (closef(fp, p));
92438dfc
SL
309}
310
0c1cfb60 311#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
a53a698b
KM
312/*
313 * Return status information about a file descriptor.
314 */
d5820a3c
CT
315struct ofstat_args {
316 int fd;
317 struct ostat *sb;
318};
a53a698b 319/* ARGSUSED */
a5bec772 320ofstat(p, uap, retval)
6150798f 321 struct proc *p;
d5820a3c 322 register struct ofstat_args *uap;
6150798f
KM
323 int *retval;
324{
325 register struct filedesc *fdp = p->p_fd;
326 register struct file *fp;
327 struct stat ub;
328 struct ostat oub;
329 int error;
330
331 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
332 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
333 return (EBADF);
334 switch (fp->f_type) {
335
336 case DTYPE_VNODE:
337 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
338 break;
339
340 case DTYPE_SOCKET:
341 error = soo_stat((struct socket *)fp->f_data, &ub);
342 break;
343
344 default:
0c1cfb60 345 panic("ofstat");
6150798f
KM
346 /*NOTREACHED*/
347 }
348 cvtstat(&ub, &oub);
349 if (error == 0)
350 error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub));
351 return (error);
352}
0c1cfb60 353#endif /* COMPAT_43 || COMPAT_SUNOS */
6150798f
KM
354
355/*
356 * Return status information about a file descriptor.
357 */
d5820a3c
CT
358struct fstat_args {
359 int fd;
360 struct stat *sb;
361};
6150798f 362/* ARGSUSED */
a5bec772 363fstat(p, uap, retval)
a53a698b 364 struct proc *p;
d5820a3c 365 register struct fstat_args *uap;
a53a698b
KM
366 int *retval;
367{
5e00df3b 368 register struct filedesc *fdp = p->p_fd;
a53a698b 369 register struct file *fp;
92438dfc 370 struct stat ub;
a53a698b 371 int error;
92438dfc 372
8429d022 373 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
7ddc4f96 374 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
d9c2f47f 375 return (EBADF);
92438dfc
SL
376 switch (fp->f_type) {
377
c4ec2128 378 case DTYPE_VNODE:
208eb71b 379 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
92438dfc
SL
380 break;
381
382 case DTYPE_SOCKET:
a53a698b 383 error = soo_stat((struct socket *)fp->f_data, &ub);
92438dfc
SL
384 break;
385
386 default:
387 panic("fstat");
388 /*NOTREACHED*/
389 }
a53a698b
KM
390 if (error == 0)
391 error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
d9c2f47f 392 return (error);
3ebb7a40
BJ
393}
394
40056b21 395/*
8429d022 396 * Allocate a file descriptor for the process.
40056b21 397 */
8429d022 398int fdexpand;
5e00df3b 399
8429d022
MK
400fdalloc(p, want, result)
401 struct proc *p;
402 int want;
c4ec2128 403 int *result;
4147b3f6 404{
8429d022
MK
405 register struct filedesc *fdp = p->p_fd;
406 register int i;
407 int lim, last, nfiles;
5e00df3b
KM
408 struct file **newofile;
409 char *newofileflags;
410
8429d022
MK
411 /*
412 * Search for a free descriptor starting at the higher
413 * of want or fd_freefile. If that fails, consider
414 * expanding the ofile array.
415 */
416 lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
5e00df3b 417 for (;;) {
8429d022
MK
418 last = min(fdp->fd_nfiles, lim);
419 if ((i = want) < fdp->fd_freefile)
420 i = fdp->fd_freefile;
421 for (; i < last; i++) {
7ddc4f96
MK
422 if (fdp->fd_ofiles[i] == NULL) {
423 fdp->fd_ofileflags[i] = 0;
8429d022
MK
424 if (i > fdp->fd_lastfile)
425 fdp->fd_lastfile = i;
7ddc4f96 426 if (want <= fdp->fd_freefile)
8429d022
MK
427 fdp->fd_freefile = i;
428 *result = i;
5e00df3b
KM
429 return (0);
430 }
431 }
8429d022
MK
432
433 /*
434 * No space in current array. Expand?
435 */
436 if (fdp->fd_nfiles >= lim)
5e00df3b 437 return (EMFILE);
7ddc4f96
MK
438 if (fdp->fd_nfiles < NDEXTENT)
439 nfiles = NDEXTENT;
440 else
441 nfiles = 2 * fdp->fd_nfiles;
8429d022
MK
442 MALLOC(newofile, struct file **, nfiles * OFILESIZE,
443 M_FILEDESC, M_WAITOK);
444 newofileflags = (char *) &newofile[nfiles];
445 /*
446 * Copy the existing ofile and ofileflags arrays
447 * and zero the new portion of each array.
448 */
449 bcopy(fdp->fd_ofiles, newofile,
450 (i = sizeof(struct file *) * fdp->fd_nfiles));
451 bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
452 bcopy(fdp->fd_ofileflags, newofileflags,
453 (i = sizeof(char) * fdp->fd_nfiles));
454 bzero(newofileflags + i, nfiles * sizeof(char) - i);
7ddc4f96
MK
455 if (fdp->fd_nfiles > NDFILE)
456 FREE(fdp->fd_ofiles, M_FILEDESC);
8429d022
MK
457 fdp->fd_ofiles = newofile;
458 fdp->fd_ofileflags = newofileflags;
459 fdp->fd_nfiles = nfiles;
460 fdexpand++;
06b22f9b 461 }
4147b3f6
BJ
462}
463
a53a698b 464/*
7ddc4f96
MK
465 * Check to see whether n user file descriptors
466 * are available to the process p.
a53a698b 467 */
8429d022
MK
468fdavail(p, n)
469 struct proc *p;
470 register int n;
88a7a62a 471{
8429d022 472 register struct filedesc *fdp = p->p_fd;
7ddc4f96 473 register struct file **fpp;
8429d022 474 register int i;
88a7a62a 475
8429d022
MK
476 if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 &&
477 (n -= i) <= 0)
478 return (1);
7ddc4f96
MK
479 fpp = &fdp->fd_ofiles[fdp->fd_freefile];
480 for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
481 if (*fpp == NULL && --n <= 0)
8429d022
MK
482 return (1);
483 return (0);
88a7a62a
SL
484}
485
4147b3f6 486/*
8429d022
MK
487 * Create a new open file structure and allocate
488 * a file decriptor for the process that refers to it.
4147b3f6 489 */
5e00df3b
KM
490falloc(p, resultfp, resultfd)
491 register struct proc *p;
c4ec2128
KM
492 struct file **resultfp;
493 int *resultfd;
4147b3f6 494{
c753a490 495 register struct file *fp, *fq, **fpp;
c4ec2128 496 int error, i;
4147b3f6 497
8429d022 498 if (error = fdalloc(p, 0, &i))
c4ec2128 499 return (error);
c753a490
KM
500 if (nfiles >= maxfiles) {
501 tablefull("file");
502 return (ENFILE);
503 }
504 /*
505 * Allocate a new file descriptor.
506 * If the process has file descriptor zero open, add to the list
507 * of open files at that point, otherwise put it at the front of
508 * the list of open files.
509 */
510 nfiles++;
511 MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
c753a490
KM
512 if (fq = p->p_fd->fd_ofiles[0])
513 fpp = &fq->f_filef;
514 else
515 fpp = &filehead;
c1884703 516 p->p_fd->fd_ofiles[i] = fp;
c753a490
KM
517 if (fq = *fpp)
518 fq->f_fileb = &fp->f_filef;
519 fp->f_filef = fq;
520 fp->f_fileb = fpp;
521 *fpp = fp;
88a7a62a 522 fp->f_count = 1;
c753a490 523 fp->f_msgcount = 0;
4147b3f6 524 fp->f_offset = 0;
8429d022 525 fp->f_cred = p->p_ucred;
c4ec2128 526 crhold(fp->f_cred);
c4ec2128
KM
527 if (resultfp)
528 *resultfp = fp;
529 if (resultfd)
530 *resultfd = i;
531 return (0);
4147b3f6
BJ
532}
533
c753a490
KM
534/*
535 * Free a file descriptor.
536 */
537ffree(fp)
538 register struct file *fp;
539{
540 register struct file *fq;
541
542 if (fq = fp->f_filef)
543 fq->f_fileb = fp->f_fileb;
544 *fp->f_fileb = fq;
545 crfree(fp->f_cred);
546#ifdef DIAGNOSTIC
547 fp->f_filef = NULL;
548 fp->f_fileb = NULL;
549 fp->f_count = 0;
550#endif
551 nfiles--;
552 FREE(fp, M_FILE);
553}
554
5e00df3b 555/*
8429d022 556 * Copy a filedesc structure.
5e00df3b
KM
557 */
558struct filedesc *
8429d022
MK
559fdcopy(p)
560 struct proc *p;
5e00df3b 561{
7ddc4f96
MK
562 register struct filedesc *newfdp, *fdp = p->p_fd;
563 register struct file **fpp;
5e00df3b 564 register int i;
5e00df3b 565
7ddc4f96
MK
566 MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
567 M_FILEDESC, M_WAITOK);
568 bcopy(fdp, newfdp, sizeof(struct filedesc));
5e00df3b
KM
569 VREF(newfdp->fd_cdir);
570 if (newfdp->fd_rdir)
571 VREF(newfdp->fd_rdir);
572 newfdp->fd_refcnt = 1;
8429d022
MK
573
574 /*
7ddc4f96
MK
575 * If the number of open files fits in the internal arrays
576 * of the open file structure, use them, otherwise allocate
577 * additional memory for the number of descriptors currently
578 * in use.
8429d022 579 */
7ddc4f96
MK
580 if (newfdp->fd_lastfile < NDFILE) {
581 newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
582 newfdp->fd_ofileflags =
583 ((struct filedesc0 *) newfdp)->fd_dfileflags;
584 i = NDFILE;
585 } else {
586 /*
587 * Compute the smallest multiple of NDEXTENT needed
588 * for the file descriptors currently in use,
589 * allowing the table to shrink.
590 */
591 i = newfdp->fd_nfiles;
592 while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2)
593 i /= 2;
594 MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
595 M_FILEDESC, M_WAITOK);
596 newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
597 }
8429d022 598 newfdp->fd_nfiles = i;
8429d022
MK
599 bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
600 bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
7ddc4f96
MK
601 fpp = newfdp->fd_ofiles;
602 for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
603 if (*fpp != NULL)
604 (*fpp)->f_count++;
5e00df3b
KM
605 return (newfdp);
606}
607
608/*
609 * Release a filedesc structure.
610 */
7ddc4f96 611void
8429d022
MK
612fdfree(p)
613 struct proc *p;
5e00df3b 614{
8429d022 615 register struct filedesc *fdp = p->p_fd;
7ddc4f96 616 struct file **fpp;
5e00df3b
KM
617 register int i;
618
8429d022 619 if (--fdp->fd_refcnt > 0)
5e00df3b 620 return;
7ddc4f96
MK
621 fpp = fdp->fd_ofiles;
622 for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
623 if (*fpp)
624 (void) closef(*fpp, p);
625 if (fdp->fd_nfiles > NDFILE)
626 FREE(fdp->fd_ofiles, M_FILEDESC);
5e00df3b
KM
627 vrele(fdp->fd_cdir);
628 if (fdp->fd_rdir)
629 vrele(fdp->fd_rdir);
8429d022 630 FREE(fdp, M_FILEDESC);
5e00df3b
KM
631}
632
4147b3f6
BJ
633/*
634 * Internal form of close.
88a7a62a 635 * Decrement reference count on file structure.
93ca0e50
MK
636 * Note: p may be NULL when closing a file
637 * that was being passed in a message.
4147b3f6 638 */
8429d022 639closef(fp, p)
4147b3f6 640 register struct file *fp;
c753a490 641 register struct proc *p;
4147b3f6 642{
a4128336
KM
643 struct vnode *vp;
644 struct flock lf;
f9934296 645 int error;
4147b3f6 646
40056b21 647 if (fp == NULL)
f9934296 648 return (0);
a4128336
KM
649 /*
650 * POSIX record locking dictates that any close releases ALL
651 * locks owned by this process. This is handled by setting
652 * a flag in the unlock to free ONLY locks obeying POSIX
653 * semantics, and not to free BSD-style file locks.
93ca0e50
MK
654 * If the descriptor was in a message, POSIX-style locks
655 * aren't passed with the descriptor.
a4128336 656 */
93ca0e50 657 if (p && (p->p_flag & SADVLCK) && fp->f_type == DTYPE_VNODE) {
a4128336
KM
658 lf.l_whence = SEEK_SET;
659 lf.l_start = 0;
660 lf.l_len = 0;
661 lf.l_type = F_UNLCK;
662 vp = (struct vnode *)fp->f_data;
208eb71b 663 (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
a4128336 664 }
8429d022 665 if (--fp->f_count > 0)
f9934296 666 return (0);
8429d022
MK
667 if (fp->f_count < 0)
668 panic("closef: count < 0");
9bd5ee04
KM
669 if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
670 lf.l_whence = SEEK_SET;
671 lf.l_start = 0;
672 lf.l_len = 0;
673 lf.l_type = F_UNLCK;
674 vp = (struct vnode *)fp->f_data;
208eb71b 675 (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
9bd5ee04 676 }
208eb71b 677 error = (*fp->f_ops->fo_close)(fp, p);
c753a490 678 ffree(fp);
f9934296 679 return (error);
8d528261 680}
92438dfc
SL
681
682/*
683 * Apply an advisory lock on a file descriptor.
a4128336
KM
684 *
685 * Just attempt to get a record lock of the requested type on
686 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
92438dfc 687 */
d5820a3c
CT
688struct flock_args {
689 int fd;
690 int how;
691};
a53a698b
KM
692/* ARGSUSED */
693flock(p, uap, retval)
694 struct proc *p;
d5820a3c 695 register struct flock_args *uap;
a53a698b
KM
696 int *retval;
697{
5e00df3b 698 register struct filedesc *fdp = p->p_fd;
92438dfc 699 register struct file *fp;
a4128336
KM
700 struct vnode *vp;
701 struct flock lf;
702 int error;
92438dfc 703
8429d022 704 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
7ddc4f96 705 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
d9c2f47f 706 return (EBADF);
a53a698b 707 if (fp->f_type != DTYPE_VNODE)
d9c2f47f 708 return (EOPNOTSUPP);
a4128336
KM
709 vp = (struct vnode *)fp->f_data;
710 lf.l_whence = SEEK_SET;
711 lf.l_start = 0;
712 lf.l_len = 0;
55dfda24 713 if (uap->how & LOCK_UN) {
a4128336 714 lf.l_type = F_UNLCK;
9bd5ee04 715 fp->f_flag &= ~FHASLOCK;
208eb71b 716 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
92438dfc 717 }
742253b3 718 if (uap->how & LOCK_EX)
a4128336
KM
719 lf.l_type = F_WRLCK;
720 else if (uap->how & LOCK_SH)
721 lf.l_type = F_RDLCK;
722 else
723 return (EBADF);
9bd5ee04 724 fp->f_flag |= FHASLOCK;
a4128336 725 if (uap->how & LOCK_NB)
208eb71b
KM
726 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
727 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
92438dfc 728}
75ebd8c9
MT
729
730/*
731 * File Descriptor pseudo-device driver (/dev/fd/).
732 *
75ebd8c9
MT
733 * Opening minor device N dup()s the file (if any) connected to file
734 * descriptor N belonging to the calling process. Note that this driver
735 * consists of only the ``open()'' routine, because all subsequent
736 * references to this file will be direct to the other driver.
737 */
c4ec2128 738/* ARGSUSED */
b640277d 739fdopen(dev, mode, type, p)
75ebd8c9 740 dev_t dev;
c4ec2128 741 int mode, type;
b640277d 742 struct proc *p;
75ebd8c9 743{
75ebd8c9
MT
744
745 /*
8429d022 746 * XXX Kludge: set curproc->p_dupfd to contain the value of the
1105efe2
KM
747 * the file descriptor being sought for duplication. The error
748 * return ensures that the vnode for this device will be released
749 * by vn_open. Open will detect this special error and take the
750 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
751 * will simply report the error.
75ebd8c9 752 */
b640277d 753 p->p_dupfd = minor(dev);
1105efe2
KM
754 return (ENODEV);
755}
e99d5db8 756
1105efe2
KM
757/*
758 * Duplicate the specified descriptor to a free descriptor.
759 */
d1c3140e 760dupfdopen(fdp, indx, dfd, mode, error)
5e00df3b 761 register struct filedesc *fdp;
1105efe2
KM
762 register int indx, dfd;
763 int mode;
d1c3140e 764 int error;
1105efe2
KM
765{
766 register struct file *wfp;
767 struct file *fp;
768
75ebd8c9 769 /*
1105efe2
KM
770 * If the to-be-dup'd fd number is greater than the allowed number
771 * of file descriptors, or the fd to be dup'd has already been
772 * closed, reject. Note, check for new == old is necessary as
773 * falloc could allocate an already closed to-be-dup'd descriptor
774 * as the new descriptor.
75ebd8c9 775 */
7ddc4f96
MK
776 fp = fdp->fd_ofiles[indx];
777 if ((u_int)dfd >= fdp->fd_nfiles ||
778 (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
75ebd8c9 779 return (EBADF);
e99d5db8 780
75ebd8c9 781 /*
d1c3140e
JSP
782 * There are two cases of interest here.
783 *
784 * For ENODEV simply dup (dfd) to file descriptor
785 * (indx) and return.
786 *
787 * For ENXIO steal away the file structure from (dfd) and
788 * store it in (indx). (dfd) is effectively closed by
789 * this operation.
790 *
791 * Any other error code is just returned.
75ebd8c9 792 */
d1c3140e
JSP
793 switch (error) {
794 case ENODEV:
795 /*
796 * Check that the mode the file is being opened for is a
797 * subset of the mode of the existing descriptor.
798 */
799 if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
800 return (EACCES);
801 fdp->fd_ofiles[indx] = wfp;
802 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
803 wfp->f_count++;
804 if (indx > fdp->fd_lastfile)
805 fdp->fd_lastfile = indx;
806 return (0);
807
808 case ENXIO:
809 /*
810 * Steal away the file pointer from dfd, and stuff it into indx.
811 */
812 fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
813 fdp->fd_ofiles[dfd] = NULL;
814 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
815 fdp->fd_ofileflags[dfd] = 0;
816 /*
817 * Complete the clean up of the filedesc structure by
818 * recomputing the various hints.
819 */
820 if (indx > fdp->fd_lastfile)
821 fdp->fd_lastfile = indx;
822 else
823 while (fdp->fd_lastfile > 0 &&
824 fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
825 fdp->fd_lastfile--;
826 if (dfd < fdp->fd_freefile)
827 fdp->fd_freefile = dfd;
828 return (0);
829
830 default:
831 return (error);
832 }
833 /* NOTREACHED */
75ebd8c9 834}