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