]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
23 | /* | |
24 | * Copyright (c) 1992, 1993 | |
25 | * The Regents of the University of California. All rights reserved. | |
26 | * | |
27 | * This code is derived from software donated to Berkeley by | |
28 | * Jan-Simon Pendry. | |
29 | * | |
30 | * Redistribution and use in source and binary forms, with or without | |
31 | * modification, are permitted provided that the following conditions | |
32 | * are met: | |
33 | * 1. Redistributions of source code must retain the above copyright | |
34 | * notice, this list of conditions and the following disclaimer. | |
35 | * 2. Redistributions in binary form must reproduce the above copyright | |
36 | * notice, this list of conditions and the following disclaimer in the | |
37 | * documentation and/or other materials provided with the distribution. | |
38 | * 3. All advertising materials mentioning features or use of this software | |
39 | * must display the following acknowledgement: | |
40 | * This product includes software developed by the University of | |
41 | * California, Berkeley and its contributors. | |
42 | * 4. Neither the name of the University nor the names of its contributors | |
43 | * may be used to endorse or promote products derived from this software | |
44 | * without specific prior written permission. | |
45 | * | |
46 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
56 | * SUCH DAMAGE. | |
57 | * | |
58 | * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95 | |
59 | * | |
60 | */ | |
61 | ||
62 | /* | |
63 | * /dev/fd Filesystem | |
64 | */ | |
65 | ||
66 | #include <sys/param.h> | |
67 | #include <sys/systm.h> | |
68 | #include <sys/types.h> | |
69 | #include <sys/time.h> | |
70 | #include <sys/proc.h> | |
71 | #include <sys/kernel.h> /* boottime */ | |
72 | #include <sys/resourcevar.h> | |
73 | #include <sys/filedesc.h> | |
74 | #include <sys/vnode.h> | |
75 | #include <sys/malloc.h> | |
76 | #include <sys/file.h> | |
77 | #include <sys/stat.h> | |
78 | #include <sys/mount.h> | |
79 | #include <sys/namei.h> | |
80 | #include <sys/buf.h> | |
81 | #include <sys/dirent.h> | |
82 | #include <sys/ubc.h> | |
83 | #include <miscfs/fdesc/fdesc.h> | |
84 | #include <vfs/vfs_support.h> | |
85 | ||
86 | #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) | |
87 | ||
88 | #define FDL_WANT 0x01 | |
89 | #define FDL_LOCKED 0x02 | |
90 | static int fdcache_lock; | |
91 | ||
92 | dev_t devctty; | |
93 | ||
94 | #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) | |
95 | FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 | |
96 | #endif | |
97 | ||
98 | #define NFDCACHE 4 | |
99 | ||
100 | #define FD_NHASH(ix) \ | |
101 | (&fdhashtbl[(ix) & fdhash]) | |
102 | LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; | |
103 | u_long fdhash; | |
104 | ||
105 | /* | |
106 | * Initialise cache headers | |
107 | */ | |
108 | fdesc_init(vfsp) | |
109 | struct vfsconf *vfsp; | |
110 | { | |
111 | ||
112 | devctty = makedev(nchrdev, 0); | |
113 | fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); | |
114 | } | |
115 | ||
116 | int | |
117 | fdesc_allocvp(ftype, ix, mp, vpp) | |
118 | fdntype ftype; | |
119 | int ix; | |
120 | struct mount *mp; | |
121 | struct vnode **vpp; | |
122 | { | |
123 | struct proc *p = current_proc(); /* XXX */ | |
124 | struct fdhashhead *fc; | |
125 | struct fdescnode *fd; | |
126 | int error = 0; | |
127 | ||
128 | fc = FD_NHASH(ix); | |
129 | loop: | |
130 | for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { | |
131 | if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { | |
132 | if (vget(fd->fd_vnode, 0, p)) | |
133 | goto loop; | |
134 | *vpp = fd->fd_vnode; | |
135 | return (error); | |
136 | } | |
137 | } | |
138 | ||
139 | /* | |
140 | * otherwise lock the array while we call getnewvnode | |
141 | * since that can block. | |
142 | */ | |
143 | if (fdcache_lock & FDL_LOCKED) { | |
144 | fdcache_lock |= FDL_WANT; | |
145 | sleep((caddr_t) &fdcache_lock, PINOD); | |
146 | goto loop; | |
147 | } | |
148 | fdcache_lock |= FDL_LOCKED; | |
149 | ||
150 | MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); | |
151 | error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); | |
152 | if (error) { | |
153 | FREE(fd, M_TEMP); | |
154 | goto out; | |
155 | } | |
156 | (*vpp)->v_data = fd; | |
157 | fd->fd_vnode = *vpp; | |
158 | fd->fd_type = ftype; | |
159 | fd->fd_fd = -1; | |
160 | fd->fd_link = 0; | |
161 | fd->fd_ix = ix; | |
162 | LIST_INSERT_HEAD(fc, fd, fd_hash); | |
163 | ||
164 | out: | |
165 | fdcache_lock &= ~FDL_LOCKED; | |
166 | ||
167 | if (fdcache_lock & FDL_WANT) { | |
168 | fdcache_lock &= ~FDL_WANT; | |
169 | wakeup((caddr_t) &fdcache_lock); | |
170 | } | |
171 | ||
172 | return (error); | |
173 | } | |
174 | ||
175 | /* | |
176 | * vp is the current namei directory | |
177 | * ndp is the name to locate in that directory... | |
178 | */ | |
179 | int | |
180 | fdesc_lookup(ap) | |
181 | struct vop_lookup_args /* { | |
182 | struct vnode * a_dvp; | |
183 | struct vnode ** a_vpp; | |
184 | struct componentname * a_cnp; | |
185 | } */ *ap; | |
186 | { | |
187 | struct vnode **vpp = ap->a_vpp; | |
188 | struct vnode *dvp = ap->a_dvp; | |
189 | struct componentname *cnp = ap->a_cnp; | |
190 | char *pname = cnp->cn_nameptr; | |
191 | struct proc *p = cnp->cn_proc; | |
192 | int nfiles = p->p_fd->fd_nfiles; | |
193 | unsigned fd; | |
194 | int error; | |
195 | struct vnode *fvp; | |
196 | char *ln; | |
197 | ||
198 | VOP_UNLOCK(dvp, 0, p); | |
199 | if (cnp->cn_namelen == 1 && *pname == '.') { | |
200 | *vpp = dvp; | |
201 | VREF(dvp); | |
202 | vn_lock(dvp, LK_SHARED | LK_RETRY, p); | |
203 | return (0); | |
204 | } | |
205 | ||
206 | switch (VTOFDESC(dvp)->fd_type) { | |
207 | default: | |
208 | case Flink: | |
209 | case Fdesc: | |
210 | case Fctty: | |
211 | error = ENOTDIR; | |
212 | goto bad; | |
213 | ||
214 | case Froot: | |
215 | if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { | |
216 | error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); | |
217 | if (error) | |
218 | goto bad; | |
219 | *vpp = fvp; | |
220 | fvp->v_type = VDIR; | |
221 | vn_lock(fvp, LK_SHARED | LK_RETRY, p); | |
222 | return (0); | |
223 | } | |
224 | ||
225 | if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { | |
226 | struct vnode *ttyvp = cttyvp(p); | |
227 | if (ttyvp == NULL) { | |
228 | error = ENXIO; | |
229 | goto bad; | |
230 | } | |
231 | error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); | |
232 | if (error) | |
233 | goto bad; | |
234 | *vpp = fvp; | |
235 | fvp->v_type = VCHR; | |
236 | vn_lock(fvp, LK_SHARED | LK_RETRY, p); | |
237 | return (0); | |
238 | } | |
239 | ||
240 | ln = 0; | |
241 | switch (cnp->cn_namelen) { | |
242 | case 5: | |
243 | if (bcmp(pname, "stdin", 5) == 0) { | |
244 | ln = "fd/0"; | |
245 | fd = FD_STDIN; | |
246 | } | |
247 | break; | |
248 | case 6: | |
249 | if (bcmp(pname, "stdout", 6) == 0) { | |
250 | ln = "fd/1"; | |
251 | fd = FD_STDOUT; | |
252 | } else | |
253 | if (bcmp(pname, "stderr", 6) == 0) { | |
254 | ln = "fd/2"; | |
255 | fd = FD_STDERR; | |
256 | } | |
257 | break; | |
258 | } | |
259 | ||
260 | if (ln) { | |
261 | error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp); | |
262 | if (error) | |
263 | goto bad; | |
264 | VTOFDESC(fvp)->fd_link = ln; | |
265 | *vpp = fvp; | |
266 | fvp->v_type = VLNK; | |
267 | vn_lock(fvp, LK_SHARED | LK_RETRY, p); | |
268 | return (0); | |
269 | } else { | |
270 | error = ENOENT; | |
271 | goto bad; | |
272 | } | |
273 | ||
274 | /* FALL THROUGH */ | |
275 | ||
276 | case Fdevfd: | |
277 | if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { | |
278 | if (error = fdesc_root(dvp->v_mount, vpp)) | |
279 | goto bad; | |
280 | return (0); | |
281 | } | |
282 | ||
283 | fd = 0; | |
284 | while (*pname >= '0' && *pname <= '9') { | |
285 | fd = 10 * fd + *pname++ - '0'; | |
286 | if (fd >= nfiles) | |
287 | break; | |
288 | } | |
289 | ||
290 | if (*pname != '\0') { | |
291 | error = ENOENT; | |
292 | goto bad; | |
293 | } | |
294 | ||
295 | if (fd >= nfiles || | |
296 | *fdfile(p, fd) == NULL || | |
297 | (*fdflags(p, fd) & UF_RESERVED)) { | |
298 | error = EBADF; | |
299 | goto bad; | |
300 | } | |
301 | ||
302 | error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp); | |
303 | if (error) | |
304 | goto bad; | |
305 | VTOFDESC(fvp)->fd_fd = fd; | |
306 | vn_lock(fvp, LK_SHARED | LK_RETRY, p); | |
307 | *vpp = fvp; | |
308 | return (0); | |
309 | } | |
310 | ||
311 | bad:; | |
312 | vn_lock(dvp, LK_SHARED | LK_RETRY, p); | |
313 | *vpp = NULL; | |
314 | return (error); | |
315 | } | |
316 | ||
317 | int | |
318 | fdesc_open(ap) | |
319 | struct vop_open_args /* { | |
320 | struct vnode *a_vp; | |
321 | int a_mode; | |
322 | struct ucred *a_cred; | |
323 | struct proc *a_p; | |
324 | } */ *ap; | |
325 | { | |
326 | struct vnode *vp = ap->a_vp; | |
327 | int error = 0; | |
328 | ||
329 | switch (VTOFDESC(vp)->fd_type) { | |
330 | case Fdesc: | |
331 | /* | |
332 | * XXX Kludge: set p->p_dupfd to contain the value of the | |
333 | * the file descriptor being sought for duplication. The error | |
334 | * return ensures that the vnode for this device will be | |
335 | * released by vn_open. Open will detect this special error and | |
336 | * take the actions in dupfdopen. Other callers of vn_open or | |
337 | * VOP_OPEN will simply report the error. | |
338 | */ | |
339 | ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ | |
340 | error = ENODEV; | |
341 | break; | |
342 | ||
343 | case Fctty: | |
344 | error = cttyopen(devctty, ap->a_mode, 0, ap->a_p); | |
345 | break; | |
346 | } | |
347 | ||
348 | return (error); | |
349 | } | |
350 | ||
351 | static int | |
352 | fdesc_attr(fd, vap, cred, p) | |
353 | int fd; | |
354 | struct vattr *vap; | |
355 | struct ucred *cred; | |
356 | struct proc *p; | |
357 | { | |
358 | struct file *fp; | |
359 | struct stat stb; | |
360 | int error; | |
361 | ||
362 | if (error = fdgetf(p, fd, &fp)) | |
363 | return (error); | |
364 | switch (fp->f_type) { | |
365 | case DTYPE_VNODE: | |
366 | error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); | |
367 | if (error == 0 && vap->va_type == VDIR) { | |
368 | /* | |
369 | * directories can cause loops in the namespace, | |
370 | * so turn off the 'x' bits to avoid trouble. | |
371 | */ | |
372 | vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6)); | |
373 | } | |
374 | break; | |
375 | ||
376 | case DTYPE_SOCKET: | |
377 | error = soo_stat((struct socket *)fp->f_data, &stb); | |
378 | if (error == 0) { | |
379 | vattr_null(vap); | |
380 | vap->va_type = VSOCK; | |
381 | vap->va_mode = stb.st_mode; | |
382 | vap->va_nlink = stb.st_nlink; | |
383 | vap->va_uid = stb.st_uid; | |
384 | vap->va_gid = stb.st_gid; | |
385 | vap->va_fsid = stb.st_dev; | |
386 | vap->va_fileid = stb.st_ino; | |
387 | vap->va_size = stb.st_size; | |
388 | vap->va_blocksize = stb.st_blksize; | |
389 | vap->va_atime = stb.st_atimespec; | |
390 | vap->va_mtime = stb.st_mtimespec; | |
391 | vap->va_ctime = stb.st_ctimespec; | |
392 | vap->va_gen = stb.st_gen; | |
393 | vap->va_flags = stb.st_flags; | |
394 | vap->va_rdev = stb.st_rdev; | |
395 | vap->va_bytes = stb.st_blocks * stb.st_blksize; | |
396 | } | |
397 | break; | |
398 | ||
399 | default: | |
400 | panic("fdesc attr"); | |
401 | break; | |
402 | } | |
403 | ||
404 | return (error); | |
405 | } | |
406 | ||
407 | int | |
408 | fdesc_getattr(ap) | |
409 | struct vop_getattr_args /* { | |
410 | struct vnode *a_vp; | |
411 | struct vattr *a_vap; | |
412 | struct ucred *a_cred; | |
413 | struct proc *a_p; | |
414 | } */ *ap; | |
415 | { | |
416 | struct vnode *vp = ap->a_vp; | |
417 | struct vattr *vap = ap->a_vap; | |
418 | unsigned fd; | |
419 | int error = 0; | |
420 | ||
421 | switch (VTOFDESC(vp)->fd_type) { | |
422 | case Froot: | |
423 | case Fdevfd: | |
424 | case Flink: | |
425 | case Fctty: | |
426 | bzero((caddr_t) vap, sizeof(*vap)); | |
427 | vattr_null(vap); | |
428 | vap->va_fileid = VTOFDESC(vp)->fd_ix; | |
429 | ||
430 | vap->va_uid = 0; | |
431 | vap->va_gid = 0; | |
432 | vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; | |
433 | vap->va_blocksize = DEV_BSIZE; | |
434 | vap->va_atime.tv_sec = boottime.tv_sec; | |
435 | vap->va_atime.tv_nsec = 0; | |
436 | vap->va_mtime = vap->va_atime; | |
437 | vap->va_ctime = vap->va_mtime; | |
438 | vap->va_gen = 0; | |
439 | vap->va_flags = 0; | |
440 | vap->va_rdev = 0; | |
441 | vap->va_bytes = 0; | |
442 | ||
443 | switch (VTOFDESC(vp)->fd_type) { | |
444 | case Flink: | |
445 | vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; | |
446 | vap->va_type = VLNK; | |
447 | vap->va_nlink = 1; | |
448 | vap->va_size = strlen(VTOFDESC(vp)->fd_link); | |
449 | break; | |
450 | ||
451 | case Fctty: | |
452 | vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; | |
453 | vap->va_type = VCHR; | |
454 | vap->va_nlink = 1; | |
455 | vap->va_size = 0; | |
456 | vap->va_rdev = devctty; | |
457 | break; | |
458 | ||
459 | default: | |
460 | vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; | |
461 | vap->va_type = VDIR; | |
462 | vap->va_nlink = 2; | |
463 | vap->va_size = DEV_BSIZE; | |
464 | break; | |
465 | } | |
466 | break; | |
467 | ||
468 | case Fdesc: | |
469 | fd = VTOFDESC(vp)->fd_fd; | |
470 | error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); | |
471 | break; | |
472 | ||
473 | default: | |
474 | panic("fdesc_getattr"); | |
475 | break; | |
476 | } | |
477 | ||
478 | if (error == 0) { | |
479 | vp->v_type = vap->va_type; | |
480 | } | |
481 | ||
482 | return (error); | |
483 | } | |
484 | ||
485 | int | |
486 | fdesc_setattr(ap) | |
487 | struct vop_setattr_args /* { | |
488 | struct vnode *a_vp; | |
489 | struct vattr *a_vap; | |
490 | struct ucred *a_cred; | |
491 | struct proc *a_p; | |
492 | } */ *ap; | |
493 | { | |
494 | struct file *fp; | |
495 | unsigned fd; | |
496 | int error; | |
497 | ||
498 | /* | |
499 | * Can't mess with the root vnode | |
500 | */ | |
501 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
502 | case Fdesc: | |
503 | break; | |
504 | ||
505 | case Fctty: | |
506 | return (0); | |
507 | ||
508 | default: | |
509 | return (EACCES); | |
510 | } | |
511 | ||
512 | fd = VTOFDESC(ap->a_vp)->fd_fd; | |
513 | if (error = fdgetf(ap->a_p, fd, &fp)) | |
514 | return (error); | |
515 | ||
516 | /* | |
517 | * Can setattr the underlying vnode, but not sockets! | |
518 | */ | |
519 | switch (fp->f_type) { | |
520 | case DTYPE_VNODE: | |
521 | error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); | |
522 | break; | |
523 | ||
524 | case DTYPE_SOCKET: | |
525 | error = 0; | |
526 | break; | |
527 | ||
528 | default: | |
529 | kprintf("fp->f_type = %d\n", fp->f_type); | |
530 | error = EBADF; | |
531 | break; | |
532 | } | |
533 | ||
534 | return (error); | |
535 | } | |
536 | ||
537 | #define UIO_MX 16 | |
538 | ||
539 | static struct dirtmp { | |
540 | u_long d_fileno; | |
541 | u_short d_reclen; | |
542 | u_short d_namlen; | |
543 | char d_name[8]; | |
544 | } rootent[] = { | |
545 | { FD_DEVFD, UIO_MX, 2, "fd" }, | |
546 | { FD_STDIN, UIO_MX, 5, "stdin" }, | |
547 | { FD_STDOUT, UIO_MX, 6, "stdout" }, | |
548 | { FD_STDERR, UIO_MX, 6, "stderr" }, | |
549 | { FD_CTTY, UIO_MX, 3, "tty" }, | |
550 | { 0 } | |
551 | }; | |
552 | ||
553 | int | |
554 | fdesc_readdir(ap) | |
555 | struct vop_readdir_args /* { | |
556 | struct vnode *a_vp; | |
557 | struct uio *a_uio; | |
558 | struct ucred *a_cred; | |
559 | int *a_eofflag; | |
560 | u_long *a_cookies; | |
561 | int a_ncookies; | |
562 | } */ *ap; | |
563 | { | |
564 | struct uio *uio = ap->a_uio; | |
565 | struct proc *p = uio->uio_procp; | |
566 | int i, error; | |
567 | ||
568 | /* | |
569 | * We don't allow exporting fdesc mounts, and currently local | |
570 | * requests do not need cookies. | |
571 | */ | |
572 | if (ap->a_ncookies) | |
573 | panic("fdesc_readdir: not hungry"); | |
574 | ||
575 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
576 | case Fctty: | |
577 | return (0); | |
578 | ||
579 | case Fdesc: | |
580 | return (ENOTDIR); | |
581 | ||
582 | default: | |
583 | break; | |
584 | } | |
585 | ||
586 | if (VTOFDESC(ap->a_vp)->fd_type == Froot) { | |
587 | struct dirent d; | |
588 | struct dirent *dp = &d; | |
589 | struct dirtmp *dt; | |
590 | int fd; | |
591 | ||
592 | i = uio->uio_offset / UIO_MX; | |
593 | error = 0; | |
594 | ||
595 | while (uio->uio_resid > 0) { | |
596 | dt = &rootent[i]; | |
597 | if (dt->d_fileno == 0) { | |
598 | /**eofflagp = 1;*/ | |
599 | break; | |
600 | } | |
601 | i++; | |
602 | ||
603 | switch (dt->d_fileno) { | |
604 | case FD_CTTY: | |
605 | if (cttyvp(uio->uio_procp) == NULL) | |
606 | continue; | |
607 | break; | |
608 | ||
609 | case FD_STDIN: | |
610 | case FD_STDOUT: | |
611 | case FD_STDERR: | |
612 | fd = dt->d_fileno - FD_STDIN; | |
613 | if (fd >= p->p_fd->fd_nfiles) | |
614 | continue; | |
615 | if (*fdfile(p, fd) == NULL && | |
616 | !(*fdflags(p, fd) & | |
617 | UF_RESERVED)) | |
618 | continue; | |
619 | break; | |
620 | } | |
621 | bzero((caddr_t) dp, UIO_MX); | |
622 | dp->d_fileno = dt->d_fileno; | |
623 | dp->d_namlen = dt->d_namlen; | |
624 | dp->d_type = DT_UNKNOWN; | |
625 | dp->d_reclen = dt->d_reclen; | |
626 | bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); | |
627 | error = uiomove((caddr_t) dp, UIO_MX, uio); | |
628 | if (error) | |
629 | break; | |
630 | } | |
631 | uio->uio_offset = i * UIO_MX; | |
632 | return (error); | |
633 | } | |
634 | ||
635 | i = uio->uio_offset / UIO_MX; | |
636 | error = 0; | |
637 | while (uio->uio_resid > 0) { | |
638 | if (i >= p->p_fd->fd_nfiles) | |
639 | break; | |
640 | ||
641 | if (*fdfile(p, i) != NULL && !(*fdflags(p, i) & UF_RESERVED)) { | |
642 | struct dirent d; | |
643 | struct dirent *dp = &d; | |
644 | ||
645 | bzero((caddr_t) dp, UIO_MX); | |
646 | ||
647 | dp->d_namlen = sprintf(dp->d_name, "%d", i); | |
648 | dp->d_reclen = UIO_MX; | |
649 | dp->d_type = DT_UNKNOWN; | |
650 | dp->d_fileno = i + FD_STDIN; | |
651 | /* | |
652 | * And ship to userland | |
653 | */ | |
654 | error = uiomove((caddr_t) dp, UIO_MX, uio); | |
655 | if (error) | |
656 | break; | |
657 | } | |
658 | i++; | |
659 | } | |
660 | ||
661 | uio->uio_offset = i * UIO_MX; | |
662 | return (error); | |
663 | } | |
664 | ||
665 | int | |
666 | fdesc_readlink(ap) | |
667 | struct vop_readlink_args /* { | |
668 | struct vnode *a_vp; | |
669 | struct uio *a_uio; | |
670 | struct ucred *a_cred; | |
671 | } */ *ap; | |
672 | { | |
673 | struct vnode *vp = ap->a_vp; | |
674 | int error; | |
675 | ||
676 | if (vp->v_type != VLNK) | |
677 | return (EPERM); | |
678 | ||
679 | if (VTOFDESC(vp)->fd_type == Flink) { | |
680 | char *ln = VTOFDESC(vp)->fd_link; | |
681 | error = uiomove(ln, strlen(ln), ap->a_uio); | |
682 | } else { | |
683 | error = EOPNOTSUPP; | |
684 | } | |
685 | ||
686 | return (error); | |
687 | } | |
688 | ||
689 | int | |
690 | fdesc_read(ap) | |
691 | struct vop_read_args /* { | |
692 | struct vnode *a_vp; | |
693 | struct uio *a_uio; | |
694 | int a_ioflag; | |
695 | struct ucred *a_cred; | |
696 | } */ *ap; | |
697 | { | |
698 | int error = EOPNOTSUPP; | |
699 | ||
700 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
701 | case Fctty: | |
702 | error = cttyread(devctty, ap->a_uio, ap->a_ioflag); | |
703 | break; | |
704 | ||
705 | default: | |
706 | error = EOPNOTSUPP; | |
707 | break; | |
708 | } | |
709 | ||
710 | return (error); | |
711 | } | |
712 | ||
713 | int | |
714 | fdesc_write(ap) | |
715 | struct vop_write_args /* { | |
716 | struct vnode *a_vp; | |
717 | struct uio *a_uio; | |
718 | int a_ioflag; | |
719 | struct ucred *a_cred; | |
720 | } */ *ap; | |
721 | { | |
722 | int error = EOPNOTSUPP; | |
723 | ||
724 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
725 | case Fctty: | |
726 | error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); | |
727 | break; | |
728 | ||
729 | default: | |
730 | error = EOPNOTSUPP; | |
731 | break; | |
732 | } | |
733 | ||
734 | return (error); | |
735 | } | |
736 | ||
737 | int | |
738 | fdesc_ioctl(ap) | |
739 | struct vop_ioctl_args /* { | |
740 | struct vnode *a_vp; | |
741 | int a_command; | |
742 | caddr_t a_data; | |
743 | int a_fflag; | |
744 | struct ucred *a_cred; | |
745 | struct proc *a_p; | |
746 | } */ *ap; | |
747 | { | |
748 | int error = EOPNOTSUPP; | |
749 | ||
750 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
751 | case Fctty: | |
752 | error = cttyioctl(devctty, ap->a_command, ap->a_data, | |
753 | ap->a_fflag, ap->a_p); | |
754 | break; | |
755 | ||
756 | default: | |
757 | error = EOPNOTSUPP; | |
758 | break; | |
759 | } | |
760 | ||
761 | return (error); | |
762 | } | |
763 | ||
764 | int | |
765 | fdesc_select(ap) | |
766 | struct vop_select_args /* { | |
767 | struct vnode *a_vp; | |
768 | int a_which; | |
769 | int a_fflags; | |
770 | struct ucred *a_cred; | |
0b4e3aa0 | 771 | void *a_wql; |
1c79356b A |
772 | struct proc *a_p; |
773 | } */ *ap; | |
774 | { | |
775 | int error = EOPNOTSUPP; | |
776 | ||
777 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
778 | case Fctty: | |
0b4e3aa0 | 779 | error = cttyselect(devctty, ap->a_fflags, ap->a_wql, ap->a_p); |
1c79356b A |
780 | break; |
781 | ||
782 | default: | |
783 | error = EOPNOTSUPP; | |
784 | break; | |
785 | } | |
786 | ||
787 | return (error); | |
788 | } | |
789 | ||
790 | int | |
791 | fdesc_inactive(ap) | |
792 | struct vop_inactive_args /* { | |
793 | struct vnode *a_vp; | |
794 | struct proc *a_p; | |
795 | } */ *ap; | |
796 | { | |
797 | struct vnode *vp = ap->a_vp; | |
798 | ||
799 | /* | |
800 | * Clear out the v_type field to avoid | |
801 | * nasty things happening in vgone(). | |
802 | */ | |
803 | VOP_UNLOCK(vp, 0, ap->a_p); | |
804 | vp->v_type = VNON; | |
805 | return (0); | |
806 | } | |
807 | ||
808 | int | |
809 | fdesc_reclaim(ap) | |
810 | struct vop_reclaim_args /* { | |
811 | struct vnode *a_vp; | |
812 | } */ *ap; | |
813 | { | |
814 | struct vnode *vp = ap->a_vp; | |
815 | struct fdescnode *fd = VTOFDESC(vp); | |
816 | ||
817 | LIST_REMOVE(fd, fd_hash); | |
818 | FREE(vp->v_data, M_TEMP); | |
819 | vp->v_data = 0; | |
820 | ||
821 | return (0); | |
822 | } | |
823 | ||
824 | /* | |
825 | * Return POSIX pathconf information applicable to special devices. | |
826 | */ | |
827 | fdesc_pathconf(ap) | |
828 | struct vop_pathconf_args /* { | |
829 | struct vnode *a_vp; | |
830 | int a_name; | |
831 | int *a_retval; | |
832 | } */ *ap; | |
833 | { | |
834 | ||
835 | switch (ap->a_name) { | |
836 | case _PC_LINK_MAX: | |
837 | *ap->a_retval = LINK_MAX; | |
838 | return (0); | |
839 | case _PC_MAX_CANON: | |
840 | *ap->a_retval = MAX_CANON; | |
841 | return (0); | |
842 | case _PC_MAX_INPUT: | |
843 | *ap->a_retval = MAX_INPUT; | |
844 | return (0); | |
845 | case _PC_PIPE_BUF: | |
846 | *ap->a_retval = PIPE_BUF; | |
847 | return (0); | |
848 | case _PC_CHOWN_RESTRICTED: | |
849 | *ap->a_retval = 1; | |
850 | return (0); | |
851 | case _PC_VDISABLE: | |
852 | *ap->a_retval = _POSIX_VDISABLE; | |
853 | return (0); | |
854 | default: | |
855 | return (EINVAL); | |
856 | } | |
857 | /* NOTREACHED */ | |
858 | } | |
859 | ||
860 | /* | |
861 | * Print out the contents of a /dev/fd vnode. | |
862 | */ | |
863 | /* ARGSUSED */ | |
864 | int | |
865 | fdesc_print(ap) | |
866 | struct vop_print_args /* { | |
867 | struct vnode *a_vp; | |
868 | } */ *ap; | |
869 | { | |
870 | ||
871 | printf("tag VT_NON, fdesc vnode\n"); | |
872 | return (0); | |
873 | } | |
874 | ||
875 | /*void*/ | |
876 | int | |
877 | fdesc_vfree(ap) | |
878 | struct vop_vfree_args /* { | |
879 | struct vnode *a_pvp; | |
880 | ino_t a_ino; | |
881 | int a_mode; | |
882 | } */ *ap; | |
883 | { | |
884 | ||
885 | return (0); | |
886 | } | |
887 | ||
888 | /* | |
889 | * /dev/fd "should never get here" operation | |
890 | */ | |
891 | int | |
892 | fdesc_badop() | |
893 | { | |
894 | ||
895 | panic("fdesc: bad op"); | |
896 | /* NOTREACHED */ | |
897 | } | |
898 | ||
899 | #define VOPFUNC int (*)(void *) | |
900 | ||
901 | #define fdesc_create ((int (*) __P((struct vop_create_args *)))eopnotsupp) | |
902 | #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp) | |
903 | #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) | |
904 | #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) | |
905 | #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp) | |
906 | #define fdesc_revoke vop_revoke | |
907 | #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) | |
908 | #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) | |
909 | #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp) | |
910 | #define fdesc_link ((int (*) __P((struct vop_link_args *)))eopnotsupp) | |
911 | #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp) | |
912 | #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp) | |
913 | #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp) | |
914 | #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp) | |
915 | #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) | |
916 | #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) | |
917 | #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) | |
918 | #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) | |
919 | #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) | |
920 | #define fdesc_islocked \ | |
921 | ((int (*) __P((struct vop_islocked_args *)))vop_noislocked) | |
922 | #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp) | |
923 | #define fdesc_blkatoff \ | |
924 | ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp) | |
925 | #define fdesc_valloc ((int(*) __P(( \ | |
926 | struct vnode *pvp, \ | |
927 | int mode, \ | |
928 | struct ucred *cred, \ | |
929 | struct vnode **vpp))) eopnotsupp) | |
930 | #define fdesc_truncate \ | |
931 | ((int (*) __P((struct vop_truncate_args *)))eopnotsupp) | |
932 | #define fdesc_update ((int (*) __P((struct vop_update_args *)))eopnotsupp) | |
933 | #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp) | |
934 | #define fdesc_blktooff ((int (*) __P((struct vop_blktooff_args *)))eopnotsupp) | |
935 | #define fdesc_offtoblk ((int (*) __P((struct vop_offtoblk_args *)))eopnotsupp) | |
936 | #define fdesc_cmap ((int (*) __P((struct vop_cmap_args *)))eopnotsupp) | |
937 | ||
938 | int (**fdesc_vnodeop_p)(void *); | |
939 | struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { | |
940 | { &vop_default_desc, (VOPFUNC)vn_default_error }, | |
941 | { &vop_lookup_desc, (VOPFUNC)fdesc_lookup }, /* lookup */ | |
942 | { &vop_create_desc, (VOPFUNC)fdesc_create }, /* create */ | |
943 | { &vop_mknod_desc, (VOPFUNC)fdesc_mknod }, /* mknod */ | |
944 | { &vop_open_desc, (VOPFUNC)fdesc_open }, /* open */ | |
945 | { &vop_close_desc, (VOPFUNC)fdesc_close }, /* close */ | |
946 | { &vop_access_desc, (VOPFUNC)fdesc_access }, /* access */ | |
947 | { &vop_getattr_desc, (VOPFUNC)fdesc_getattr }, /* getattr */ | |
948 | { &vop_setattr_desc, (VOPFUNC)fdesc_setattr }, /* setattr */ | |
949 | { &vop_read_desc, (VOPFUNC)fdesc_read }, /* read */ | |
950 | { &vop_write_desc, (VOPFUNC)fdesc_write }, /* write */ | |
951 | { &vop_ioctl_desc, (VOPFUNC)fdesc_ioctl }, /* ioctl */ | |
952 | { &vop_select_desc, (VOPFUNC)fdesc_select }, /* select */ | |
953 | { &vop_revoke_desc, (VOPFUNC)fdesc_revoke }, /* revoke */ | |
954 | { &vop_mmap_desc, (VOPFUNC)fdesc_mmap }, /* mmap */ | |
955 | { &vop_fsync_desc, (VOPFUNC)fdesc_fsync }, /* fsync */ | |
956 | { &vop_seek_desc, (VOPFUNC)fdesc_seek }, /* seek */ | |
957 | { &vop_remove_desc, (VOPFUNC)fdesc_remove }, /* remove */ | |
958 | { &vop_link_desc, (VOPFUNC)fdesc_link }, /* link */ | |
959 | { &vop_rename_desc, (VOPFUNC)fdesc_rename }, /* rename */ | |
960 | { &vop_mkdir_desc, (VOPFUNC)fdesc_mkdir }, /* mkdir */ | |
961 | { &vop_rmdir_desc, (VOPFUNC)fdesc_rmdir }, /* rmdir */ | |
962 | { &vop_symlink_desc, (VOPFUNC)fdesc_symlink }, /* symlink */ | |
963 | { &vop_readdir_desc, (VOPFUNC)fdesc_readdir }, /* readdir */ | |
964 | { &vop_readlink_desc, (VOPFUNC)fdesc_readlink },/* readlink */ | |
965 | { &vop_abortop_desc, (VOPFUNC)fdesc_abortop }, /* abortop */ | |
966 | { &vop_inactive_desc, (VOPFUNC)fdesc_inactive },/* inactive */ | |
967 | { &vop_reclaim_desc, (VOPFUNC)fdesc_reclaim }, /* reclaim */ | |
968 | { &vop_lock_desc, (VOPFUNC)fdesc_lock }, /* lock */ | |
969 | { &vop_unlock_desc, (VOPFUNC)fdesc_unlock }, /* unlock */ | |
970 | { &vop_bmap_desc, (VOPFUNC)fdesc_bmap }, /* bmap */ | |
971 | { &vop_strategy_desc, (VOPFUNC)fdesc_strategy }, /* strategy */ | |
972 | { &vop_print_desc, (VOPFUNC)fdesc_print }, /* print */ | |
973 | { &vop_islocked_desc, (VOPFUNC)fdesc_islocked }, /* islocked */ | |
974 | { &vop_pathconf_desc, (VOPFUNC)fdesc_pathconf }, /* pathconf */ | |
975 | { &vop_advlock_desc, (VOPFUNC)fdesc_advlock }, /* advlock */ | |
976 | { &vop_blkatoff_desc, (VOPFUNC)fdesc_blkatoff }, /* blkatoff */ | |
977 | { &vop_valloc_desc, (VOPFUNC)fdesc_valloc }, /* valloc */ | |
978 | { &vop_vfree_desc, (VOPFUNC)fdesc_vfree }, /* vfree */ | |
979 | { &vop_truncate_desc, (VOPFUNC)fdesc_truncate }, /* truncate */ | |
980 | { &vop_update_desc, (VOPFUNC)fdesc_update }, /* update */ | |
981 | { &vop_bwrite_desc, (VOPFUNC)fdesc_bwrite }, /* bwrite */ | |
982 | { &vop_pagein_desc, (VOPFUNC)err_pagein }, /* pagein */ | |
983 | { &vop_pageout_desc, (VOPFUNC)err_pageout }, /* pageout */ | |
984 | { &vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ | |
985 | { &vop_blktooff_desc, (VOPFUNC)fdesc_blktooff }, /* blktooff */ | |
986 | { &vop_blktooff_desc, (VOPFUNC)fdesc_offtoblk }, /* offtoblk */ | |
987 | { &vop_cmap_desc, (VOPFUNC)fdesc_cmap }, /* cmap */ | |
988 | { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } | |
989 | }; | |
990 | struct vnodeopv_desc fdesc_vnodeop_opv_desc = | |
991 | { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; |