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