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 | * | |
3c008f5d | 17 | * @(#)kern_descrip.c 7.7 (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" | |
29 | #include "mount.h" | |
30 | #include "stat.h" | |
4147b3f6 | 31 | |
94368568 | 32 | #include "ioctl.h" |
4147b3f6 BJ |
33 | |
34 | /* | |
35 | * Descriptor management. | |
36 | */ | |
37 | ||
40056b21 | 38 | /* |
4147b3f6 | 39 | * System calls on descriptors. |
40056b21 | 40 | */ |
3ebb7a40 | 41 | getdtablesize() |
4147b3f6 BJ |
42 | { |
43 | ||
44 | u.u_r.r_val1 = NOFILE; | |
45 | } | |
46 | ||
40056b21 BJ |
47 | dup() |
48 | { | |
4147b3f6 BJ |
49 | register struct a { |
50 | int i; | |
51 | } *uap = (struct a *) u.u_ap; | |
a81e9a81 SL |
52 | struct file *fp; |
53 | int j; | |
4147b3f6 BJ |
54 | |
55 | if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ | |
56 | ||
c4ec2128 KM |
57 | if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) |
58 | RETURN (EBADF); | |
59 | if (u.u_error = ufalloc(0, &j)) | |
4147b3f6 | 60 | return; |
c4ec2128 | 61 | u.u_r.r_val1 = j; |
c05c2528 | 62 | dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); |
4147b3f6 BJ |
63 | } |
64 | ||
65 | dup2() | |
66 | { | |
40056b21 | 67 | register struct a { |
4147b3f6 BJ |
68 | int i, j; |
69 | } *uap = (struct a *) u.u_ap; | |
70 | register struct file *fp; | |
f9934296 | 71 | int error; |
40056b21 | 72 | |
c4ec2128 KM |
73 | if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) |
74 | RETURN (EBADF); | |
f9934296 KM |
75 | if (uap->j < 0 || uap->j >= NOFILE) |
76 | RETURN (EBADF); | |
4147b3f6 BJ |
77 | u.u_r.r_val1 = uap->j; |
78 | if (uap->i == uap->j) | |
f9934296 | 79 | RETURN (0); |
4147b3f6 | 80 | if (u.u_ofile[uap->j]) { |
67fc76c5 BJ |
81 | if (u.u_pofile[uap->j] & UF_MAPPED) |
82 | munmapfd(uap->j); | |
f9934296 | 83 | error = closef(u.u_ofile[uap->j]); |
4147b3f6 | 84 | } |
c05c2528 | 85 | dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); |
f9934296 KM |
86 | /* |
87 | * dup2() must succeed even though the close had an error. | |
88 | */ | |
89 | error = 0; /* XXX */ | |
90 | RETURN (error); | |
a81e9a81 SL |
91 | } |
92 | ||
55dfda24 | 93 | dupit(fd, fp, flags) |
a81e9a81 SL |
94 | int fd; |
95 | register struct file *fp; | |
55dfda24 | 96 | register int flags; |
a81e9a81 SL |
97 | { |
98 | ||
99 | u.u_ofile[fd] = fp; | |
55dfda24 | 100 | u.u_pofile[fd] = flags; |
4147b3f6 | 101 | fp->f_count++; |
8694aaad MK |
102 | if (fd > u.u_lastfile) |
103 | u.u_lastfile = fd; | |
4147b3f6 BJ |
104 | } |
105 | ||
88a7a62a SL |
106 | /* |
107 | * The file control system call. | |
108 | */ | |
109 | fcntl() | |
4147b3f6 | 110 | { |
4147b3f6 | 111 | register struct file *fp; |
4147b3f6 | 112 | register struct a { |
88a7a62a SL |
113 | int fdes; |
114 | int cmd; | |
115 | int arg; | |
c4ec2128 | 116 | } *uap = (struct a *)u.u_ap; |
88a7a62a | 117 | register char *pop; |
c4ec2128 | 118 | int i; |
4147b3f6 | 119 | |
c4ec2128 KM |
120 | if ((unsigned)uap->fdes >= NOFILE || |
121 | (fp = u.u_ofile[uap->fdes]) == NULL) | |
122 | RETURN (EBADF); | |
88a7a62a SL |
123 | pop = &u.u_pofile[uap->fdes]; |
124 | switch(uap->cmd) { | |
85f01bd4 | 125 | case F_DUPFD: |
c4ec2128 | 126 | if (uap->arg < 0 || uap->arg >= NOFILE) { |
12438177 | 127 | u.u_error = EINVAL; |
88a7a62a | 128 | return; |
12438177 | 129 | } |
c4ec2128 | 130 | if (u.u_error = ufalloc(uap->arg, &i)) |
88a7a62a | 131 | return; |
c4ec2128 | 132 | u.u_r.r_val1 = i; |
c05c2528 | 133 | dupit(i, fp, *pop &~ UF_EXCLOSE); |
88a7a62a | 134 | break; |
12438177 | 135 | |
85f01bd4 | 136 | case F_GETFD: |
88a7a62a SL |
137 | u.u_r.r_val1 = *pop & 1; |
138 | break; | |
40056b21 | 139 | |
85f01bd4 | 140 | case F_SETFD: |
88a7a62a SL |
141 | *pop = (*pop &~ 1) | (uap->arg & 1); |
142 | break; | |
12438177 | 143 | |
85f01bd4 | 144 | case F_GETFL: |
88a7a62a | 145 | u.u_r.r_val1 = fp->f_flag+FOPEN; |
12438177 BJ |
146 | break; |
147 | ||
85f01bd4 | 148 | case F_SETFL: |
88a7a62a SL |
149 | fp->f_flag &= FCNTLCANT; |
150 | fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT; | |
151 | u.u_error = fset(fp, FNDELAY, fp->f_flag & FNDELAY); | |
152 | if (u.u_error) | |
153 | break; | |
154 | u.u_error = fset(fp, FASYNC, fp->f_flag & FASYNC); | |
155 | if (u.u_error) | |
156 | (void) fset(fp, FNDELAY, 0); | |
40056b21 | 157 | break; |
88a7a62a | 158 | |
85f01bd4 MK |
159 | case F_GETOWN: |
160 | u.u_error = fgetown(fp, &u.u_r.r_val1); | |
88a7a62a SL |
161 | break; |
162 | ||
85f01bd4 MK |
163 | case F_SETOWN: |
164 | u.u_error = fsetown(fp, uap->arg); | |
88a7a62a SL |
165 | break; |
166 | ||
167 | default: | |
168 | u.u_error = EINVAL; | |
40056b21 | 169 | } |
40056b21 BJ |
170 | } |
171 | ||
88a7a62a | 172 | fset(fp, bit, value) |
40056b21 | 173 | struct file *fp; |
88a7a62a SL |
174 | int bit, value; |
175 | { | |
40056b21 | 176 | |
88a7a62a SL |
177 | if (value) |
178 | fp->f_flag |= bit; | |
179 | else | |
180 | fp->f_flag &= ~bit; | |
181 | return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), | |
182 | (caddr_t)&value)); | |
183 | } | |
12438177 | 184 | |
88a7a62a SL |
185 | fgetown(fp, valuep) |
186 | struct file *fp; | |
187 | int *valuep; | |
188 | { | |
189 | int error; | |
40056b21 | 190 | |
88a7a62a | 191 | switch (fp->f_type) { |
12438177 | 192 | |
88a7a62a | 193 | case DTYPE_SOCKET: |
8fe87cbb | 194 | *valuep = ((struct socket *)fp->f_data)->so_pgid; |
88a7a62a SL |
195 | return (0); |
196 | ||
197 | default: | |
198 | error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); | |
199 | *valuep = -*valuep; | |
200 | return (error); | |
40056b21 | 201 | } |
40056b21 BJ |
202 | } |
203 | ||
88a7a62a SL |
204 | fsetown(fp, value) |
205 | struct file *fp; | |
206 | int value; | |
40056b21 | 207 | { |
c4ec2128 | 208 | |
88a7a62a | 209 | if (fp->f_type == DTYPE_SOCKET) { |
8fe87cbb | 210 | ((struct socket *)fp->f_data)->so_pgid = value; |
88a7a62a SL |
211 | return (0); |
212 | } | |
213 | if (value > 0) { | |
214 | struct proc *p = pfind(value); | |
215 | if (p == 0) | |
0aae4319 | 216 | return (ESRCH); |
8fe87cbb | 217 | value = p->p_pgrp->pg_id; |
88a7a62a SL |
218 | } else |
219 | value = -value; | |
220 | return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); | |
40056b21 BJ |
221 | } |
222 | ||
88a7a62a SL |
223 | fioctl(fp, cmd, value) |
224 | struct file *fp; | |
225 | int cmd; | |
226 | caddr_t value; | |
40056b21 | 227 | { |
40056b21 | 228 | |
88a7a62a | 229 | return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); |
40056b21 BJ |
230 | } |
231 | ||
88a7a62a | 232 | close() |
3ebb7a40 | 233 | { |
8694aaad | 234 | struct a { |
c4ec2128 | 235 | int fdes; |
88a7a62a SL |
236 | } *uap = (struct a *)u.u_ap; |
237 | register struct file *fp; | |
92438dfc | 238 | register u_char *pf; |
3ebb7a40 | 239 | |
c4ec2128 KM |
240 | if ((unsigned)uap->fdes >= NOFILE || |
241 | (fp = u.u_ofile[uap->fdes]) == NULL) | |
242 | RETURN (EBADF); | |
243 | pf = (u_char *)&u.u_pofile[uap->fdes]; | |
92438dfc | 244 | if (*pf & UF_MAPPED) |
c4ec2128 KM |
245 | munmapfd(uap->fdes); |
246 | u.u_ofile[uap->fdes] = NULL; | |
8694aaad MK |
247 | while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) |
248 | u.u_lastfile--; | |
92438dfc | 249 | *pf = 0; |
f9934296 | 250 | RETURN (closef(fp)); |
92438dfc SL |
251 | } |
252 | ||
253 | fstat() | |
254 | { | |
255 | register struct file *fp; | |
256 | register struct a { | |
257 | int fdes; | |
258 | struct stat *sb; | |
c4ec2128 | 259 | } *uap = (struct a *)u.u_ap; |
92438dfc SL |
260 | struct stat ub; |
261 | ||
c4ec2128 KM |
262 | if ((unsigned)uap->fdes >= NOFILE || |
263 | (fp = u.u_ofile[uap->fdes]) == NULL) | |
264 | RETURN (EBADF); | |
92438dfc SL |
265 | switch (fp->f_type) { |
266 | ||
c4ec2128 KM |
267 | case DTYPE_VNODE: |
268 | u.u_error = vn_stat((struct vnode *)fp->f_data, &ub); | |
92438dfc SL |
269 | break; |
270 | ||
271 | case DTYPE_SOCKET: | |
272 | u.u_error = soo_stat((struct socket *)fp->f_data, &ub); | |
273 | break; | |
274 | ||
275 | default: | |
276 | panic("fstat"); | |
277 | /*NOTREACHED*/ | |
278 | } | |
279 | if (u.u_error == 0) | |
55dfda24 SL |
280 | u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, |
281 | sizeof (ub)); | |
3ebb7a40 BJ |
282 | } |
283 | ||
40056b21 | 284 | /* |
4147b3f6 | 285 | * Allocate a user file descriptor. |
40056b21 | 286 | */ |
c4ec2128 KM |
287 | ufalloc(want, result) |
288 | register int want; | |
289 | int *result; | |
4147b3f6 | 290 | { |
4147b3f6 | 291 | |
c4ec2128 KM |
292 | for (; want < NOFILE; want++) |
293 | if (u.u_ofile[want] == NULL) { | |
294 | u.u_pofile[want] = 0; | |
295 | if (want > u.u_lastfile) | |
296 | u.u_lastfile = want; | |
297 | if (result) | |
298 | *result = want; | |
299 | return (0); | |
4147b3f6 | 300 | } |
c4ec2128 | 301 | return (EMFILE); |
4147b3f6 BJ |
302 | } |
303 | ||
88a7a62a SL |
304 | ufavail() |
305 | { | |
306 | register int i, avail = 0; | |
307 | ||
308 | for (i = 0; i < NOFILE; i++) | |
309 | if (u.u_ofile[i] == NULL) | |
310 | avail++; | |
311 | return (avail); | |
312 | } | |
313 | ||
4147b3f6 BJ |
314 | struct file *lastf; |
315 | /* | |
316 | * Allocate a user file descriptor | |
317 | * and a file structure. | |
318 | * Initialize the descriptor | |
319 | * to point at the file structure. | |
320 | */ | |
c4ec2128 KM |
321 | falloc(resultfp, resultfd) |
322 | struct file **resultfp; | |
323 | int *resultfd; | |
4147b3f6 BJ |
324 | { |
325 | register struct file *fp; | |
c4ec2128 | 326 | int error, i; |
4147b3f6 | 327 | |
c4ec2128 KM |
328 | if (error = ufalloc(0, &i)) |
329 | return (error); | |
4147b3f6 BJ |
330 | if (lastf == 0) |
331 | lastf = file; | |
332 | for (fp = lastf; fp < fileNFILE; fp++) | |
333 | if (fp->f_count == 0) | |
334 | goto slot; | |
335 | for (fp = file; fp < lastf; fp++) | |
336 | if (fp->f_count == 0) | |
337 | goto slot; | |
338 | tablefull("file"); | |
c4ec2128 | 339 | return (ENFILE); |
4147b3f6 BJ |
340 | slot: |
341 | u.u_ofile[i] = fp; | |
88a7a62a SL |
342 | fp->f_count = 1; |
343 | fp->f_data = 0; | |
4147b3f6 | 344 | fp->f_offset = 0; |
c4ec2128 KM |
345 | fp->f_cred = u.u_cred; |
346 | crhold(fp->f_cred); | |
4147b3f6 | 347 | lastf = fp + 1; |
c4ec2128 KM |
348 | if (resultfp) |
349 | *resultfp = fp; | |
350 | if (resultfd) | |
351 | *resultfd = i; | |
352 | return (0); | |
4147b3f6 BJ |
353 | } |
354 | ||
355 | /* | |
356 | * Internal form of close. | |
88a7a62a | 357 | * Decrement reference count on file structure. |
4147b3f6 | 358 | */ |
92438dfc | 359 | closef(fp) |
4147b3f6 BJ |
360 | register struct file *fp; |
361 | { | |
f9934296 | 362 | int error; |
4147b3f6 | 363 | |
40056b21 | 364 | if (fp == NULL) |
f9934296 | 365 | return (0); |
4147b3f6 BJ |
366 | if (fp->f_count > 1) { |
367 | fp->f_count--; | |
f9934296 | 368 | return (0); |
40056b21 | 369 | } |
c4ec2128 KM |
370 | if (fp->f_count < 1) |
371 | panic("closef: count < 1"); | |
f9934296 | 372 | error = (*fp->f_ops->fo_close)(fp); |
c4ec2128 | 373 | crfree(fp->f_cred); |
4147b3f6 | 374 | fp->f_count = 0; |
f9934296 | 375 | return (error); |
8d528261 | 376 | } |
92438dfc SL |
377 | |
378 | /* | |
379 | * Apply an advisory lock on a file descriptor. | |
380 | */ | |
381 | flock() | |
382 | { | |
383 | register struct a { | |
c4ec2128 | 384 | int fdes; |
92438dfc SL |
385 | int how; |
386 | } *uap = (struct a *)u.u_ap; | |
387 | register struct file *fp; | |
92438dfc | 388 | |
c4ec2128 KM |
389 | if ((unsigned)uap->fdes >= NOFILE || |
390 | (fp = u.u_ofile[uap->fdes]) == NULL) | |
391 | RETURN (EBADF); | |
392 | if (fp->f_type != DTYPE_VNODE) { | |
55dfda24 | 393 | u.u_error = EOPNOTSUPP; |
92438dfc SL |
394 | return; |
395 | } | |
55dfda24 | 396 | if (uap->how & LOCK_UN) { |
c4ec2128 | 397 | vn_unlock(fp, FSHLOCK|FEXLOCK); |
92438dfc | 398 | return; |
92438dfc | 399 | } |
8b026909 MK |
400 | if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) |
401 | return; /* error? */ | |
742253b3 MK |
402 | if (uap->how & LOCK_EX) |
403 | uap->how &= ~LOCK_SH; | |
55dfda24 | 404 | /* avoid work... */ |
742253b3 MK |
405 | if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || |
406 | (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) | |
92438dfc | 407 | return; |
c4ec2128 | 408 | u.u_error = vn_lock(fp, uap->how); |
92438dfc | 409 | } |
75ebd8c9 MT |
410 | |
411 | /* | |
412 | * File Descriptor pseudo-device driver (/dev/fd/). | |
413 | * | |
414 | * Fred Blonder - U of Maryland 11-Sep-1984 | |
415 | * | |
416 | * Opening minor device N dup()s the file (if any) connected to file | |
417 | * descriptor N belonging to the calling process. Note that this driver | |
418 | * consists of only the ``open()'' routine, because all subsequent | |
419 | * references to this file will be direct to the other driver. | |
420 | */ | |
c4ec2128 KM |
421 | /* ARGSUSED */ |
422 | fdopen(dev, mode, type) | |
75ebd8c9 | 423 | dev_t dev; |
c4ec2128 | 424 | int mode, type; |
75ebd8c9 MT |
425 | { |
426 | struct file *fp, *wfp; | |
c4ec2128 | 427 | int indx, dfd, rwmode; |
75ebd8c9 MT |
428 | |
429 | /* | |
430 | * Note the horrid kludge here: u.u_r.r_val1 contains the value | |
c4ec2128 KM |
431 | * of the new file descriptor, which was set before the call to |
432 | * vn_open() by copen() in vfs_syscalls.c | |
75ebd8c9 | 433 | */ |
c6fd5824 | 434 | indx = u.u_r.r_val1; /* XXX from copen */ |
c4ec2128 KM |
435 | if ((unsigned)indx >= NOFILE || (fp = u.u_ofile[indx]) == NULL) |
436 | return (EBADF); | |
437 | dfd = minor(dev); | |
438 | if ((unsigned)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL) | |
439 | return (EBADF); | |
75ebd8c9 MT |
440 | /* |
441 | * We must explicitly test for this case because ufalloc() may | |
442 | * have allocated us the same file desriptor we are referring | |
443 | * to, if the proccess referred to an invalid (closed) descriptor. | |
c4ec2128 KM |
444 | * Ordinarily this would be caught by the check for NULL above, |
445 | * but by the time we reach this routine u_pofile[minor(dev)] | |
446 | * could already be set to point to our file struct. | |
75ebd8c9 MT |
447 | */ |
448 | if (fp == wfp) | |
449 | return (EBADF); | |
450 | /* | |
451 | * Fake a ``dup()'' sys call. | |
452 | * Check that the mode the file is being opened | |
453 | * for is consistent with the mode of the existing | |
454 | * descriptor. This isn't as clean as it should be, | |
455 | * but this entire driver is a real kludge anyway. | |
456 | */ | |
457 | rwmode = mode & (FREAD|FWRITE); | |
3c008f5d | 458 | if ((wfp->f_flag & rwmode) != rwmode) |
75ebd8c9 | 459 | return (EACCES); |
75ebd8c9 MT |
460 | /* |
461 | * Dup the file descriptor. | |
462 | */ | |
c4ec2128 | 463 | dupit(indx, wfp, u.u_pofile[dfd]); |
c6fd5824 KM |
464 | /* |
465 | * Delete references to this pseudo-device by returning | |
466 | * a special error (-1) that will cause all resources to | |
467 | * be freed, then detected and cleared by copen. | |
468 | */ | |
469 | return (-1); | |
75ebd8c9 | 470 | } |