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