1 | /* $NetBSD: fdesc_vnops.c,v 1.127 2016/08/20 12:37:08 hannken Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1992, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * This code is derived from software donated to Berkeley by |
8 | * Jan-Simon Pendry. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. |
21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. |
33 | * |
34 | * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95 |
35 | * |
36 | * #Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp # |
37 | */ |
38 | |
39 | /* |
40 | * /dev/fd Filesystem |
41 | */ |
42 | |
43 | #include <sys/cdefs.h> |
44 | __KERNEL_RCSID(0, "$NetBSD: fdesc_vnops.c,v 1.127 2016/08/20 12:37:08 hannken Exp $" ); |
45 | |
46 | #include <sys/param.h> |
47 | #include <sys/systm.h> |
48 | #include <sys/time.h> |
49 | #include <sys/proc.h> |
50 | #include <sys/kernel.h> /* boottime */ |
51 | #include <sys/resourcevar.h> |
52 | #include <sys/socketvar.h> |
53 | #include <sys/filedesc.h> |
54 | #include <sys/vnode.h> |
55 | #include <sys/malloc.h> |
56 | #include <sys/conf.h> |
57 | #include <sys/file.h> |
58 | #include <sys/stat.h> |
59 | #include <sys/mount.h> |
60 | #include <sys/namei.h> |
61 | #include <sys/buf.h> |
62 | #include <sys/dirent.h> |
63 | #include <sys/tty.h> |
64 | #include <sys/kauth.h> |
65 | #include <sys/atomic.h> |
66 | |
67 | #include <miscfs/fdesc/fdesc.h> |
68 | #include <miscfs/genfs/genfs.h> |
69 | |
70 | #define cttyvp(p) ((p)->p_lflag & PL_CONTROLT ? (p)->p_session->s_ttyvp : NULL) |
71 | |
72 | dev_t devctty; |
73 | |
74 | #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) |
75 | FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 |
76 | #endif |
77 | |
78 | int fdesc_lookup(void *); |
79 | #define fdesc_create genfs_eopnotsupp |
80 | #define fdesc_mknod genfs_eopnotsupp |
81 | int fdesc_open(void *); |
82 | #define fdesc_close genfs_nullop |
83 | #define fdesc_access genfs_nullop |
84 | int fdesc_getattr(void *); |
85 | int fdesc_setattr(void *); |
86 | int fdesc_read(void *); |
87 | int fdesc_write(void *); |
88 | int fdesc_ioctl(void *); |
89 | int fdesc_poll(void *); |
90 | int fdesc_kqfilter(void *); |
91 | #define fdesc_mmap genfs_eopnotsupp |
92 | #define fdesc_fcntl genfs_fcntl |
93 | #define fdesc_fsync genfs_nullop |
94 | #define fdesc_seek genfs_seek |
95 | #define fdesc_remove genfs_eopnotsupp |
96 | int fdesc_link(void *); |
97 | #define fdesc_rename genfs_eopnotsupp |
98 | #define fdesc_mkdir genfs_eopnotsupp |
99 | #define fdesc_rmdir genfs_eopnotsupp |
100 | int fdesc_symlink(void *); |
101 | int fdesc_readdir(void *); |
102 | int fdesc_readlink(void *); |
103 | #define fdesc_abortop genfs_abortop |
104 | int fdesc_inactive(void *); |
105 | int fdesc_reclaim(void *); |
106 | #define fdesc_lock genfs_lock |
107 | #define fdesc_unlock genfs_unlock |
108 | #define fdesc_bmap genfs_badop |
109 | #define fdesc_strategy genfs_badop |
110 | int fdesc_print(void *); |
111 | int fdesc_pathconf(void *); |
112 | #define fdesc_islocked genfs_islocked |
113 | #define fdesc_advlock genfs_einval |
114 | #define fdesc_bwrite genfs_eopnotsupp |
115 | #define fdesc_revoke genfs_revoke |
116 | #define fdesc_putpages genfs_null_putpages |
117 | |
118 | static int fdesc_attr(int, struct vattr *, kauth_cred_t); |
119 | |
120 | int (**fdesc_vnodeop_p)(void *); |
121 | const struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { |
122 | { &vop_default_desc, vn_default_error }, |
123 | { &vop_lookup_desc, fdesc_lookup }, /* lookup */ |
124 | { &vop_create_desc, fdesc_create }, /* create */ |
125 | { &vop_mknod_desc, fdesc_mknod }, /* mknod */ |
126 | { &vop_open_desc, fdesc_open }, /* open */ |
127 | { &vop_close_desc, fdesc_close }, /* close */ |
128 | { &vop_access_desc, fdesc_access }, /* access */ |
129 | { &vop_getattr_desc, fdesc_getattr }, /* getattr */ |
130 | { &vop_setattr_desc, fdesc_setattr }, /* setattr */ |
131 | { &vop_read_desc, fdesc_read }, /* read */ |
132 | { &vop_write_desc, fdesc_write }, /* write */ |
133 | { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ |
134 | { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ |
135 | { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */ |
136 | { &vop_fcntl_desc, fdesc_fcntl }, /* fcntl */ |
137 | { &vop_poll_desc, fdesc_poll }, /* poll */ |
138 | { &vop_kqfilter_desc, fdesc_kqfilter }, /* kqfilter */ |
139 | { &vop_revoke_desc, fdesc_revoke }, /* revoke */ |
140 | { &vop_mmap_desc, fdesc_mmap }, /* mmap */ |
141 | { &vop_fsync_desc, fdesc_fsync }, /* fsync */ |
142 | { &vop_seek_desc, fdesc_seek }, /* seek */ |
143 | { &vop_remove_desc, fdesc_remove }, /* remove */ |
144 | { &vop_link_desc, fdesc_link }, /* link */ |
145 | { &vop_rename_desc, fdesc_rename }, /* rename */ |
146 | { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */ |
147 | { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */ |
148 | { &vop_symlink_desc, fdesc_symlink }, /* symlink */ |
149 | { &vop_readdir_desc, fdesc_readdir }, /* readdir */ |
150 | { &vop_readlink_desc, fdesc_readlink }, /* readlink */ |
151 | { &vop_abortop_desc, fdesc_abortop }, /* abortop */ |
152 | { &vop_inactive_desc, fdesc_inactive }, /* inactive */ |
153 | { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */ |
154 | { &vop_lock_desc, fdesc_lock }, /* lock */ |
155 | { &vop_unlock_desc, fdesc_unlock }, /* unlock */ |
156 | { &vop_bmap_desc, fdesc_bmap }, /* bmap */ |
157 | { &vop_strategy_desc, fdesc_strategy }, /* strategy */ |
158 | { &vop_print_desc, fdesc_print }, /* print */ |
159 | { &vop_islocked_desc, fdesc_islocked }, /* islocked */ |
160 | { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */ |
161 | { &vop_advlock_desc, fdesc_advlock }, /* advlock */ |
162 | { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */ |
163 | { &vop_putpages_desc, fdesc_putpages }, /* putpages */ |
164 | { NULL, NULL } |
165 | }; |
166 | |
167 | const struct vnodeopv_desc fdesc_vnodeop_opv_desc = |
168 | { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; |
169 | |
170 | /* |
171 | * Initialise cache headers |
172 | */ |
173 | void |
174 | fdesc_init(void) |
175 | { |
176 | int cttymajor; |
177 | |
178 | /* locate the major number */ |
179 | cttymajor = devsw_name2chr("ctty" , NULL, 0); |
180 | devctty = makedev(cttymajor, 0); |
181 | } |
182 | |
183 | void |
184 | fdesc_done(void) |
185 | { |
186 | } |
187 | |
188 | /* |
189 | * vp is the current namei directory |
190 | * ndp is the name to locate in that directory... |
191 | */ |
192 | int |
193 | fdesc_lookup(void *v) |
194 | { |
195 | struct vop_lookup_v2_args /* { |
196 | struct vnode * a_dvp; |
197 | struct vnode ** a_vpp; |
198 | struct componentname * a_cnp; |
199 | } */ *ap = v; |
200 | struct vnode **vpp = ap->a_vpp; |
201 | struct vnode *dvp = ap->a_dvp; |
202 | struct componentname *cnp = ap->a_cnp; |
203 | struct lwp *l = curlwp; |
204 | const char *pname = cnp->cn_nameptr; |
205 | struct proc *p = l->l_proc; |
206 | unsigned fd = 0; |
207 | int error, ix = -1; |
208 | fdtab_t *dt; |
209 | |
210 | dt = curlwp->l_fd->fd_dt; |
211 | |
212 | if (cnp->cn_namelen == 1 && *pname == '.') { |
213 | *vpp = dvp; |
214 | vref(dvp); |
215 | return (0); |
216 | } |
217 | |
218 | switch (VTOFDESC(dvp)->fd_type) { |
219 | default: |
220 | case Flink: |
221 | case Fdesc: |
222 | case Fctty: |
223 | error = ENOTDIR; |
224 | goto bad; |
225 | |
226 | case Froot: |
227 | if (cnp->cn_namelen == 2 && memcmp(pname, "fd" , 2) == 0) { |
228 | ix = FD_DEVFD; |
229 | goto good; |
230 | } |
231 | |
232 | if (cnp->cn_namelen == 3 && memcmp(pname, "tty" , 3) == 0) { |
233 | struct vnode *ttyvp = cttyvp(p); |
234 | if (ttyvp == NULL) { |
235 | error = ENXIO; |
236 | goto bad; |
237 | } |
238 | ix = FD_CTTY; |
239 | goto good; |
240 | } |
241 | |
242 | switch (cnp->cn_namelen) { |
243 | case 5: |
244 | if (memcmp(pname, "stdin" , 5) == 0) { |
245 | ix = FD_STDIN; |
246 | goto good; |
247 | } |
248 | break; |
249 | case 6: |
250 | if (memcmp(pname, "stdout" , 6) == 0) { |
251 | ix = FD_STDOUT; |
252 | goto good; |
253 | } else if (memcmp(pname, "stderr" , 6) == 0) { |
254 | ix = FD_STDERR; |
255 | goto good; |
256 | } |
257 | break; |
258 | } |
259 | |
260 | error = ENOENT; |
261 | goto bad; |
262 | |
263 | case Fdevfd: |
264 | if (cnp->cn_namelen == 2 && memcmp(pname, ".." , 2) == 0) { |
265 | ix = FD_ROOT; |
266 | goto good; |
267 | } |
268 | |
269 | fd = 0; |
270 | while (*pname >= '0' && *pname <= '9') { |
271 | fd = 10 * fd + *pname++ - '0'; |
272 | if (fd >= dt->dt_nfiles) |
273 | break; |
274 | } |
275 | |
276 | if (*pname != '\0') { |
277 | error = ENOENT; |
278 | goto bad; |
279 | } |
280 | |
281 | if (fd >= dt->dt_nfiles || dt->dt_ff[fd] == NULL || |
282 | dt->dt_ff[fd]->ff_file == NULL) { |
283 | error = EBADF; |
284 | goto bad; |
285 | } |
286 | |
287 | ix = FD_DESC + fd; |
288 | goto good; |
289 | } |
290 | |
291 | bad: |
292 | *vpp = NULL; |
293 | return error; |
294 | |
295 | good: |
296 | KASSERT(ix != -1); |
297 | error = vcache_get(dvp->v_mount, &ix, sizeof(ix), vpp); |
298 | if (error == 0 && ix == FD_CTTY) |
299 | (*vpp)->v_type = VCHR; |
300 | return error; |
301 | } |
302 | |
303 | int |
304 | fdesc_open(void *v) |
305 | { |
306 | struct vop_open_args /* { |
307 | struct vnode *a_vp; |
308 | int a_mode; |
309 | kauth_cred_t a_cred; |
310 | } */ *ap = v; |
311 | struct vnode *vp = ap->a_vp; |
312 | |
313 | switch (VTOFDESC(vp)->fd_type) { |
314 | case Fdesc: |
315 | /* |
316 | * XXX Kludge: set dupfd to contain the value of the |
317 | * the file descriptor being sought for duplication. The error |
318 | * return ensures that the vnode for this device will be |
319 | * released by vn_open. Open will detect this special error and |
320 | * take the actions in dupfdopen. Other callers of vn_open or |
321 | * VOP_OPEN will simply report the error. |
322 | */ |
323 | curlwp->l_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ |
324 | return EDUPFD; |
325 | |
326 | case Fctty: |
327 | return cdev_open(devctty, ap->a_mode, 0, curlwp); |
328 | case Froot: |
329 | case Fdevfd: |
330 | case Flink: |
331 | break; |
332 | } |
333 | |
334 | return (0); |
335 | } |
336 | |
337 | static int |
338 | fdesc_attr(int fd, struct vattr *vap, kauth_cred_t cred) |
339 | { |
340 | file_t *fp; |
341 | struct stat stb; |
342 | int error; |
343 | |
344 | if ((fp = fd_getfile(fd)) == NULL) |
345 | return (EBADF); |
346 | |
347 | switch (fp->f_type) { |
348 | case DTYPE_VNODE: |
349 | vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); |
350 | error = VOP_GETATTR(fp->f_vnode, vap, cred); |
351 | VOP_UNLOCK(fp->f_vnode); |
352 | if (error == 0 && vap->va_type == VDIR) { |
353 | /* |
354 | * directories can cause loops in the namespace, |
355 | * so turn off the 'x' bits to avoid trouble. |
356 | */ |
357 | vap->va_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); |
358 | } |
359 | break; |
360 | |
361 | default: |
362 | memset(&stb, 0, sizeof(stb)); |
363 | error = (*fp->f_ops->fo_stat)(fp, &stb); |
364 | if (error) |
365 | break; |
366 | |
367 | vattr_null(vap); |
368 | switch(fp->f_type) { |
369 | case DTYPE_SOCKET: |
370 | vap->va_type = VSOCK; |
371 | break; |
372 | case DTYPE_PIPE: |
373 | vap->va_type = VFIFO; |
374 | break; |
375 | default: |
376 | /* use VNON perhaps? */ |
377 | vap->va_type = VBAD; |
378 | break; |
379 | } |
380 | vap->va_mode = stb.st_mode; |
381 | vap->va_nlink = stb.st_nlink; |
382 | vap->va_uid = stb.st_uid; |
383 | vap->va_gid = stb.st_gid; |
384 | vap->va_fsid = stb.st_dev; |
385 | vap->va_fileid = stb.st_ino; |
386 | vap->va_size = stb.st_size; |
387 | vap->va_blocksize = stb.st_blksize; |
388 | vap->va_atime = stb.st_atimespec; |
389 | vap->va_mtime = stb.st_mtimespec; |
390 | vap->va_ctime = stb.st_ctimespec; |
391 | vap->va_gen = stb.st_gen; |
392 | vap->va_flags = stb.st_flags; |
393 | vap->va_rdev = stb.st_rdev; |
394 | vap->va_bytes = stb.st_blocks * stb.st_blksize; |
395 | break; |
396 | } |
397 | |
398 | fd_putfile(fd); |
399 | return (error); |
400 | } |
401 | |
402 | int |
403 | fdesc_getattr(void *v) |
404 | { |
405 | struct vop_getattr_args /* { |
406 | struct vnode *a_vp; |
407 | struct vattr *a_vap; |
408 | kauth_cred_t a_cred; |
409 | struct lwp *a_l; |
410 | } */ *ap = v; |
411 | struct vnode *vp = ap->a_vp; |
412 | struct vattr *vap = ap->a_vap; |
413 | unsigned fd; |
414 | int error = 0; |
415 | |
416 | switch (VTOFDESC(vp)->fd_type) { |
417 | case Froot: |
418 | case Fdevfd: |
419 | case Flink: |
420 | case Fctty: |
421 | vattr_null(vap); |
422 | vap->va_fileid = VTOFDESC(vp)->fd_ix; |
423 | |
424 | #define R_ALL (S_IRUSR|S_IRGRP|S_IROTH) |
425 | #define W_ALL (S_IWUSR|S_IWGRP|S_IWOTH) |
426 | #define X_ALL (S_IXUSR|S_IXGRP|S_IXOTH) |
427 | |
428 | switch (VTOFDESC(vp)->fd_type) { |
429 | case Flink: |
430 | vap->va_mode = R_ALL|X_ALL; |
431 | vap->va_type = VLNK; |
432 | vap->va_rdev = 0; |
433 | vap->va_nlink = 1; |
434 | vap->va_size = strlen(VTOFDESC(vp)->fd_link); |
435 | break; |
436 | |
437 | case Fctty: |
438 | vap->va_mode = R_ALL|W_ALL; |
439 | vap->va_type = VCHR; |
440 | vap->va_rdev = devctty; |
441 | vap->va_nlink = 1; |
442 | vap->va_size = 0; |
443 | break; |
444 | |
445 | default: |
446 | vap->va_mode = R_ALL|X_ALL; |
447 | vap->va_type = VDIR; |
448 | vap->va_rdev = 0; |
449 | vap->va_nlink = 2; |
450 | vap->va_size = DEV_BSIZE; |
451 | break; |
452 | } |
453 | vap->va_uid = 0; |
454 | vap->va_gid = 0; |
455 | vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; |
456 | vap->va_blocksize = DEV_BSIZE; |
457 | vap->va_atime.tv_sec = boottime.tv_sec; |
458 | vap->va_atime.tv_nsec = 0; |
459 | vap->va_mtime = vap->va_atime; |
460 | vap->va_ctime = vap->va_mtime; |
461 | vap->va_gen = 0; |
462 | vap->va_flags = 0; |
463 | vap->va_bytes = 0; |
464 | break; |
465 | |
466 | case Fdesc: |
467 | fd = VTOFDESC(vp)->fd_fd; |
468 | error = fdesc_attr(fd, vap, ap->a_cred); |
469 | break; |
470 | |
471 | default: |
472 | panic("fdesc_getattr" ); |
473 | break; |
474 | } |
475 | |
476 | if (error == 0) |
477 | vp->v_type = vap->va_type; |
478 | |
479 | return (error); |
480 | } |
481 | |
482 | int |
483 | fdesc_setattr(void *v) |
484 | { |
485 | struct vop_setattr_args /* { |
486 | struct vnode *a_vp; |
487 | struct vattr *a_vap; |
488 | kauth_cred_t a_cred; |
489 | } */ *ap = v; |
490 | file_t *fp; |
491 | unsigned fd; |
492 | |
493 | /* |
494 | * Can't mess with the root vnode |
495 | */ |
496 | switch (VTOFDESC(ap->a_vp)->fd_type) { |
497 | case Fdesc: |
498 | break; |
499 | |
500 | case Fctty: |
501 | return (0); |
502 | |
503 | default: |
504 | return (EACCES); |
505 | } |
506 | |
507 | fd = VTOFDESC(ap->a_vp)->fd_fd; |
508 | if ((fp = fd_getfile(fd)) == NULL) |
509 | return (EBADF); |
510 | |
511 | /* |
512 | * XXX: Can't reasonably set the attr's on any types currently. |
513 | * On vnode's this will cause truncation and socket/pipes make |
514 | * no sense. |
515 | */ |
516 | fd_putfile(fd); |
517 | return (0); |
518 | } |
519 | |
520 | |
521 | struct fdesc_target { |
522 | ino_t ft_fileno; |
523 | u_char ft_type; |
524 | u_char ft_namlen; |
525 | const char *ft_name; |
526 | } fdesc_targets[] = { |
527 | #define N(s) sizeof(s)-1, s |
528 | { FD_DEVFD, DT_DIR, N("fd" ) }, |
529 | { FD_STDIN, DT_LNK, N("stdin" ) }, |
530 | { FD_STDOUT, DT_LNK, N("stdout" ) }, |
531 | { FD_STDERR, DT_LNK, N("stderr" ) }, |
532 | { FD_CTTY, DT_UNKNOWN, N("tty" ) }, |
533 | #undef N |
534 | #define UIO_MX _DIRENT_RECLEN((struct dirent *)NULL, sizeof("stderr") - 1) |
535 | }; |
536 | static int nfdesc_targets = sizeof(fdesc_targets) / sizeof(fdesc_targets[0]); |
537 | |
538 | int |
539 | fdesc_readdir(void *v) |
540 | { |
541 | struct vop_readdir_args /* { |
542 | struct vnode *a_vp; |
543 | struct uio *a_uio; |
544 | kauth_cred_t a_cred; |
545 | int *a_eofflag; |
546 | off_t **a_cookies; |
547 | int *a_ncookies; |
548 | } */ *ap = v; |
549 | struct uio *uio = ap->a_uio; |
550 | struct dirent d; |
551 | off_t i; |
552 | int j; |
553 | int error; |
554 | off_t *cookies = NULL; |
555 | int ncookies; |
556 | fdtab_t *dt; |
557 | |
558 | switch (VTOFDESC(ap->a_vp)->fd_type) { |
559 | case Fctty: |
560 | return 0; |
561 | |
562 | case Fdesc: |
563 | return ENOTDIR; |
564 | |
565 | default: |
566 | break; |
567 | } |
568 | |
569 | dt = curlwp->l_fd->fd_dt; |
570 | |
571 | if (uio->uio_resid < UIO_MX) |
572 | return EINVAL; |
573 | if (uio->uio_offset < 0) |
574 | return EINVAL; |
575 | |
576 | error = 0; |
577 | i = uio->uio_offset; |
578 | (void)memset(&d, 0, UIO_MX); |
579 | d.d_reclen = UIO_MX; |
580 | if (ap->a_ncookies) |
581 | ncookies = uio->uio_resid / UIO_MX; |
582 | else |
583 | ncookies = 0; |
584 | |
585 | if (VTOFDESC(ap->a_vp)->fd_type == Froot) { |
586 | struct fdesc_target *ft; |
587 | |
588 | if (i >= nfdesc_targets) |
589 | return 0; |
590 | |
591 | if (ap->a_ncookies) { |
592 | ncookies = min(ncookies, (nfdesc_targets - i)); |
593 | cookies = malloc(ncookies * sizeof(off_t), |
594 | M_TEMP, M_WAITOK); |
595 | *ap->a_cookies = cookies; |
596 | *ap->a_ncookies = ncookies; |
597 | } |
598 | |
599 | for (ft = &fdesc_targets[i]; uio->uio_resid >= UIO_MX && |
600 | i < nfdesc_targets; ft++, i++) { |
601 | switch (ft->ft_fileno) { |
602 | case FD_CTTY: |
603 | if (cttyvp(curproc) == NULL) |
604 | continue; |
605 | break; |
606 | |
607 | case FD_STDIN: |
608 | case FD_STDOUT: |
609 | case FD_STDERR: |
610 | if ((ft->ft_fileno - FD_STDIN) >= |
611 | dt->dt_nfiles) |
612 | continue; |
613 | if (dt->dt_ff[ft->ft_fileno - FD_STDIN] |
614 | == NULL || dt->dt_ff[ft->ft_fileno - |
615 | FD_STDIN]->ff_file == NULL) |
616 | continue; |
617 | break; |
618 | } |
619 | |
620 | d.d_fileno = ft->ft_fileno; |
621 | d.d_namlen = ft->ft_namlen; |
622 | (void)memcpy(d.d_name, ft->ft_name, ft->ft_namlen + 1); |
623 | d.d_type = ft->ft_type; |
624 | |
625 | if ((error = uiomove(&d, UIO_MX, uio)) != 0) |
626 | break; |
627 | if (cookies) |
628 | *cookies++ = i + 1; |
629 | } |
630 | } else { |
631 | membar_consumer(); |
632 | if (ap->a_ncookies) { |
633 | ncookies = min(ncookies, dt->dt_nfiles + 2); |
634 | cookies = malloc(ncookies * sizeof(off_t), |
635 | M_TEMP, M_WAITOK); |
636 | *ap->a_cookies = cookies; |
637 | *ap->a_ncookies = ncookies; |
638 | } |
639 | for (; i - 2 < dt->dt_nfiles && uio->uio_resid >= UIO_MX; i++) { |
640 | switch (i) { |
641 | case 0: |
642 | case 1: |
643 | d.d_fileno = FD_ROOT; /* XXX */ |
644 | d.d_namlen = i + 1; |
645 | (void)memcpy(d.d_name, ".." , d.d_namlen); |
646 | d.d_name[i + 1] = '\0'; |
647 | d.d_type = DT_DIR; |
648 | break; |
649 | |
650 | default: |
651 | j = (int)i - 2; |
652 | if (dt->dt_ff[j] == NULL || |
653 | dt->dt_ff[j]->ff_file == NULL) |
654 | continue; |
655 | d.d_fileno = j + FD_STDIN; |
656 | d.d_namlen = snprintf(d.d_name, |
657 | sizeof(d.d_name), "%d" , j); |
658 | d.d_type = DT_UNKNOWN; |
659 | break; |
660 | } |
661 | |
662 | if ((error = uiomove(&d, UIO_MX, uio)) != 0) |
663 | break; |
664 | if (cookies) |
665 | *cookies++ = i + 1; |
666 | } |
667 | } |
668 | |
669 | if (ap->a_ncookies && error) { |
670 | free(*ap->a_cookies, M_TEMP); |
671 | *ap->a_ncookies = 0; |
672 | *ap->a_cookies = NULL; |
673 | } |
674 | |
675 | uio->uio_offset = i; |
676 | return error; |
677 | } |
678 | |
679 | int |
680 | fdesc_readlink(void *v) |
681 | { |
682 | struct vop_readlink_args /* { |
683 | struct vnode *a_vp; |
684 | struct uio *a_uio; |
685 | kauth_cred_t a_cred; |
686 | } */ *ap = v; |
687 | struct vnode *vp = ap->a_vp; |
688 | int error; |
689 | |
690 | if (vp->v_type != VLNK) |
691 | return (EPERM); |
692 | |
693 | if (VTOFDESC(vp)->fd_type == Flink) { |
694 | const char *ln = VTOFDESC(vp)->fd_link; |
695 | error = uiomove(__UNCONST(ln), strlen(ln), ap->a_uio); |
696 | } else { |
697 | error = EOPNOTSUPP; |
698 | } |
699 | |
700 | return (error); |
701 | } |
702 | |
703 | int |
704 | fdesc_read(void *v) |
705 | { |
706 | struct vop_read_args /* { |
707 | struct vnode *a_vp; |
708 | struct uio *a_uio; |
709 | int a_ioflag; |
710 | kauth_cred_t a_cred; |
711 | } */ *ap = v; |
712 | int error = EOPNOTSUPP; |
713 | struct vnode *vp = ap->a_vp; |
714 | |
715 | switch (VTOFDESC(vp)->fd_type) { |
716 | case Fctty: |
717 | VOP_UNLOCK(vp); |
718 | error = cdev_read(devctty, ap->a_uio, ap->a_ioflag); |
719 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
720 | break; |
721 | |
722 | default: |
723 | error = EOPNOTSUPP; |
724 | break; |
725 | } |
726 | |
727 | return (error); |
728 | } |
729 | |
730 | int |
731 | fdesc_write(void *v) |
732 | { |
733 | struct vop_write_args /* { |
734 | struct vnode *a_vp; |
735 | struct uio *a_uio; |
736 | int a_ioflag; |
737 | kauth_cred_t a_cred; |
738 | } */ *ap = v; |
739 | int error = EOPNOTSUPP; |
740 | struct vnode *vp = ap->a_vp; |
741 | |
742 | switch (VTOFDESC(vp)->fd_type) { |
743 | case Fctty: |
744 | VOP_UNLOCK(vp); |
745 | error = cdev_write(devctty, ap->a_uio, ap->a_ioflag); |
746 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
747 | break; |
748 | |
749 | default: |
750 | error = EOPNOTSUPP; |
751 | break; |
752 | } |
753 | |
754 | return (error); |
755 | } |
756 | |
757 | int |
758 | fdesc_ioctl(void *v) |
759 | { |
760 | struct vop_ioctl_args /* { |
761 | struct vnode *a_vp; |
762 | u_long a_command; |
763 | void *a_data; |
764 | int a_fflag; |
765 | kauth_cred_t a_cred; |
766 | } */ *ap = v; |
767 | int error = EOPNOTSUPP; |
768 | |
769 | switch (VTOFDESC(ap->a_vp)->fd_type) { |
770 | case Fctty: |
771 | error = cdev_ioctl(devctty, ap->a_command, ap->a_data, |
772 | ap->a_fflag, curlwp); |
773 | break; |
774 | |
775 | default: |
776 | error = EOPNOTSUPP; |
777 | break; |
778 | } |
779 | |
780 | return (error); |
781 | } |
782 | |
783 | int |
784 | fdesc_poll(void *v) |
785 | { |
786 | struct vop_poll_args /* { |
787 | struct vnode *a_vp; |
788 | int a_events; |
789 | } */ *ap = v; |
790 | int revents; |
791 | |
792 | switch (VTOFDESC(ap->a_vp)->fd_type) { |
793 | case Fctty: |
794 | revents = cdev_poll(devctty, ap->a_events, curlwp); |
795 | break; |
796 | |
797 | default: |
798 | revents = genfs_poll(v); |
799 | break; |
800 | } |
801 | |
802 | return (revents); |
803 | } |
804 | |
805 | int |
806 | fdesc_kqfilter(void *v) |
807 | { |
808 | struct vop_kqfilter_args /* { |
809 | struct vnode *a_vp; |
810 | struct knote *a_kn; |
811 | } */ *ap = v; |
812 | int error, fd; |
813 | file_t *fp; |
814 | |
815 | switch (VTOFDESC(ap->a_vp)->fd_type) { |
816 | case Fctty: |
817 | error = cdev_kqfilter(devctty, ap->a_kn); |
818 | break; |
819 | |
820 | case Fdesc: |
821 | /* just invoke kqfilter for the underlying descriptor */ |
822 | fd = VTOFDESC(ap->a_vp)->fd_fd; |
823 | if ((fp = fd_getfile(fd)) == NULL) |
824 | return (1); |
825 | error = (*fp->f_ops->fo_kqfilter)(fp, ap->a_kn); |
826 | fd_putfile(fd); |
827 | break; |
828 | |
829 | default: |
830 | return (genfs_kqfilter(v)); |
831 | } |
832 | |
833 | return (error); |
834 | } |
835 | |
836 | int |
837 | fdesc_inactive(void *v) |
838 | { |
839 | struct vop_inactive_args /* { |
840 | struct vnode *a_vp; |
841 | } */ *ap = v; |
842 | struct vnode *vp = ap->a_vp; |
843 | struct fdescnode *fd = VTOFDESC(vp); |
844 | |
845 | /* |
846 | * Clear out the v_type field to avoid |
847 | * nasty things happening on reclaim. |
848 | */ |
849 | if (fd->fd_type == Fctty || fd->fd_type == Fdesc) |
850 | vp->v_type = VNON; |
851 | VOP_UNLOCK(vp); |
852 | return (0); |
853 | } |
854 | |
855 | int |
856 | fdesc_reclaim(void *v) |
857 | { |
858 | struct vop_reclaim_args /* { |
859 | struct vnode *a_vp; |
860 | } */ *ap = v; |
861 | struct vnode *vp = ap->a_vp; |
862 | struct fdescnode *fd = VTOFDESC(vp); |
863 | |
864 | vp->v_data = NULL; |
865 | kmem_free(fd, sizeof(struct fdescnode)); |
866 | |
867 | return (0); |
868 | } |
869 | |
870 | /* |
871 | * Return POSIX pathconf information applicable to special devices. |
872 | */ |
873 | int |
874 | fdesc_pathconf(void *v) |
875 | { |
876 | struct vop_pathconf_args /* { |
877 | struct vnode *a_vp; |
878 | int a_name; |
879 | register_t *a_retval; |
880 | } */ *ap = v; |
881 | |
882 | switch (ap->a_name) { |
883 | case _PC_LINK_MAX: |
884 | *ap->a_retval = LINK_MAX; |
885 | return (0); |
886 | case _PC_MAX_CANON: |
887 | *ap->a_retval = MAX_CANON; |
888 | return (0); |
889 | case _PC_MAX_INPUT: |
890 | *ap->a_retval = MAX_INPUT; |
891 | return (0); |
892 | case _PC_PIPE_BUF: |
893 | *ap->a_retval = PIPE_BUF; |
894 | return (0); |
895 | case _PC_CHOWN_RESTRICTED: |
896 | *ap->a_retval = 1; |
897 | return (0); |
898 | case _PC_VDISABLE: |
899 | *ap->a_retval = _POSIX_VDISABLE; |
900 | return (0); |
901 | case _PC_SYNC_IO: |
902 | *ap->a_retval = 1; |
903 | return (0); |
904 | default: |
905 | return (EINVAL); |
906 | } |
907 | /* NOTREACHED */ |
908 | } |
909 | |
910 | /* |
911 | * Print out the contents of a /dev/fd vnode. |
912 | */ |
913 | /* ARGSUSED */ |
914 | int |
915 | fdesc_print(void *v) |
916 | { |
917 | printf("tag VT_NON, fdesc vnode\n" ); |
918 | return (0); |
919 | } |
920 | |
921 | int |
922 | fdesc_link(void *v) |
923 | { |
924 | struct vop_link_v2_args /* { |
925 | struct vnode *a_dvp; |
926 | struct vnode *a_vp; |
927 | struct componentname *a_cnp; |
928 | } */ *ap = v; |
929 | |
930 | VOP_ABORTOP(ap->a_dvp, ap->a_cnp); |
931 | return (EROFS); |
932 | } |
933 | |
934 | int |
935 | fdesc_symlink(void *v) |
936 | { |
937 | struct vop_symlink_v3_args /* { |
938 | struct vnode *a_dvp; |
939 | struct vnode **a_vpp; |
940 | struct componentname *a_cnp; |
941 | struct vattr *a_vap; |
942 | char *a_target; |
943 | } */ *ap = v; |
944 | |
945 | VOP_ABORTOP(ap->a_dvp, ap->a_cnp); |
946 | return (EROFS); |
947 | } |
948 | |