Commit | Line | Data |
---|---|---|
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 */ |
30 | getdtablesize(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 */ | |
44 | dup(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 */ | |
76 | dup2(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 */ |
115 | fcntl(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 | 179 | fset(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 |
192 | fgetown(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 |
211 | fsetown(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 |
230 | fioctl(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 */ | |
243 | close(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 */ | |
270 | fstat(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 |
307 | ufalloc(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 |
327 | ufavail() |
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 |
337 | struct 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 |
344 | falloc(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 |
363 | slot: |
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 | 382 | closef(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 */ |
405 | flock(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 */ |
444 | fdopen(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 | */ | |
465 | dupfdopen(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 | } |