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 | * |
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 */ |
43 | getdtablesize(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 */ | |
57 | dup(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 */ | |
89 | dup2(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 */ |
128 | fcntl(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 | 192 | fset(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 |
205 | fgetown(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 |
224 | fsetown(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 |
243 | fioctl(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 */ | |
256 | close(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 */ | |
283 | fstat(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 |
320 | ufalloc(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 |
340 | ufavail() |
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 |
350 | struct 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 |
357 | falloc(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 |
376 | slot: |
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 | 395 | closef(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 */ |
418 | flock(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 */ |
457 | fdopen(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 | */ | |
478 | dupfdopen(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 | } |