1 /* $NetBSD: ptyfs_vnops.c,v 1.32 2009/07/03 21:17:40 elad Exp $ */
4 * Copyright (c) 1993, 1995
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
34 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
38 * Copyright (c) 1993 Jan-Simon Pendry
40 * This code is derived from software contributed to Berkeley by
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
75 * ptyfs vnode interface
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.32 2009/07/03 21:17:40 elad Exp $");
81 #include <sys/param.h>
82 #include <sys/systm.h>
84 #include <sys/kernel.h>
86 #include <sys/filedesc.h>
88 #include <sys/vnode.h>
89 #include <sys/namei.h>
90 #include <sys/malloc.h>
91 #include <sys/mount.h>
92 #include <sys/select.h>
93 #include <sys/dirent.h>
94 #include <sys/resourcevar.h>
99 #include <sys/kauth.h>
101 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
103 #include <machine/reg.h>
105 #include <fs/ptyfs/ptyfs.h>
106 #include <miscfs/genfs/genfs.h>
107 #include <miscfs/specfs/specdev.h>
109 MALLOC_DECLARE(M_PTYFSTMP
);
116 int ptyfs_lookup (void *);
117 #define ptyfs_create genfs_eopnotsupp
118 #define ptyfs_mknod genfs_eopnotsupp
119 int ptyfs_open (void *);
120 int ptyfs_close (void *);
121 int ptyfs_access (void *);
122 int ptyfs_getattr (void *);
123 int ptyfs_setattr (void *);
124 int ptyfs_read (void *);
125 int ptyfs_write (void *);
126 #define ptyfs_fcntl genfs_fcntl
127 int ptyfs_ioctl (void *);
128 int ptyfs_poll (void *);
129 int ptyfs_kqfilter (void *);
130 #define ptyfs_revoke genfs_revoke
131 #define ptyfs_mmap genfs_eopnotsupp
132 #define ptyfs_fsync genfs_nullop
133 #define ptyfs_seek genfs_nullop
134 #define ptyfs_remove genfs_eopnotsupp
135 #define ptyfs_link genfs_abortop
136 #define ptyfs_rename genfs_eopnotsupp
137 #define ptyfs_mkdir genfs_eopnotsupp
138 #define ptyfs_rmdir genfs_eopnotsupp
139 #define ptyfs_symlink genfs_abortop
140 int ptyfs_readdir (void *);
141 #define ptyfs_readlink genfs_eopnotsupp
142 #define ptyfs_abortop genfs_abortop
143 int ptyfs_reclaim (void *);
144 #define ptyfs_lock genfs_lock
145 #define ptyfs_unlock genfs_unlock
146 #define ptyfs_bmap genfs_badop
147 #define ptyfs_strategy genfs_badop
148 int ptyfs_print (void *);
149 int ptyfs_pathconf (void *);
150 #define ptyfs_islocked genfs_islocked
151 #define ptyfs_advlock genfs_einval
152 #define ptyfs_bwrite genfs_eopnotsupp
153 #define ptyfs_putpages genfs_null_putpages
155 static int ptyfs_update(struct vnode
*, const struct timespec
*,
156 const struct timespec
*, int);
157 static int ptyfs_chown(struct vnode
*, uid_t
, gid_t
, kauth_cred_t
,
159 static int ptyfs_chmod(struct vnode
*, mode_t
, kauth_cred_t
, struct lwp
*);
160 static int atoi(const char *, size_t);
163 * ptyfs vnode operations.
165 int (**ptyfs_vnodeop_p
)(void *);
166 const struct vnodeopv_entry_desc ptyfs_vnodeop_entries
[] = {
167 { &vop_default_desc
, vn_default_error
},
168 { &vop_lookup_desc
, ptyfs_lookup
}, /* lookup */
169 { &vop_create_desc
, ptyfs_create
}, /* create */
170 { &vop_mknod_desc
, ptyfs_mknod
}, /* mknod */
171 { &vop_open_desc
, ptyfs_open
}, /* open */
172 { &vop_close_desc
, ptyfs_close
}, /* close */
173 { &vop_access_desc
, ptyfs_access
}, /* access */
174 { &vop_getattr_desc
, ptyfs_getattr
}, /* getattr */
175 { &vop_setattr_desc
, ptyfs_setattr
}, /* setattr */
176 { &vop_read_desc
, ptyfs_read
}, /* read */
177 { &vop_write_desc
, ptyfs_write
}, /* write */
178 { &vop_ioctl_desc
, ptyfs_ioctl
}, /* ioctl */
179 { &vop_fcntl_desc
, ptyfs_fcntl
}, /* fcntl */
180 { &vop_poll_desc
, ptyfs_poll
}, /* poll */
181 { &vop_kqfilter_desc
, ptyfs_kqfilter
}, /* kqfilter */
182 { &vop_revoke_desc
, ptyfs_revoke
}, /* revoke */
183 { &vop_mmap_desc
, ptyfs_mmap
}, /* mmap */
184 { &vop_fsync_desc
, ptyfs_fsync
}, /* fsync */
185 { &vop_seek_desc
, ptyfs_seek
}, /* seek */
186 { &vop_remove_desc
, ptyfs_remove
}, /* remove */
187 { &vop_link_desc
, ptyfs_link
}, /* link */
188 { &vop_rename_desc
, ptyfs_rename
}, /* rename */
189 { &vop_mkdir_desc
, ptyfs_mkdir
}, /* mkdir */
190 { &vop_rmdir_desc
, ptyfs_rmdir
}, /* rmdir */
191 { &vop_symlink_desc
, ptyfs_symlink
}, /* symlink */
192 { &vop_readdir_desc
, ptyfs_readdir
}, /* readdir */
193 { &vop_readlink_desc
, ptyfs_readlink
}, /* readlink */
194 { &vop_abortop_desc
, ptyfs_abortop
}, /* abortop */
195 { &vop_inactive_desc
, spec_inactive
}, /* inactive */
196 { &vop_reclaim_desc
, ptyfs_reclaim
}, /* reclaim */
197 { &vop_lock_desc
, ptyfs_lock
}, /* lock */
198 { &vop_unlock_desc
, ptyfs_unlock
}, /* unlock */
199 { &vop_bmap_desc
, ptyfs_bmap
}, /* bmap */
200 { &vop_strategy_desc
, ptyfs_strategy
}, /* strategy */
201 { &vop_print_desc
, ptyfs_print
}, /* print */
202 { &vop_islocked_desc
, ptyfs_islocked
}, /* islocked */
203 { &vop_pathconf_desc
, ptyfs_pathconf
}, /* pathconf */
204 { &vop_advlock_desc
, ptyfs_advlock
}, /* advlock */
205 { &vop_bwrite_desc
, ptyfs_bwrite
}, /* bwrite */
206 { &vop_putpages_desc
, ptyfs_putpages
}, /* putpages */
209 const struct vnodeopv_desc ptyfs_vnodeop_opv_desc
=
210 { &ptyfs_vnodeop_p
, ptyfs_vnodeop_entries
};
213 * _reclaim is called when getnewvnode()
214 * wants to make use of an entry on the vnode
215 * free list. at this time the filesystem needs
216 * to free any private data and remove the node
217 * from any private lists.
220 ptyfs_reclaim(void *v
)
222 struct vop_reclaim_args
/* {
225 return ptyfs_freevp(ap
->a_vp
);
229 * Return POSIX pathconf information applicable to special devices.
232 ptyfs_pathconf(void *v
)
234 struct vop_pathconf_args
/* {
237 register_t *a_retval;
240 switch (ap
->a_name
) {
242 *ap
->a_retval
= LINK_MAX
;
245 *ap
->a_retval
= MAX_CANON
;
248 *ap
->a_retval
= MAX_INPUT
;
251 *ap
->a_retval
= PIPE_BUF
;
253 case _PC_CHOWN_RESTRICTED
:
257 *ap
->a_retval
= _POSIX_VDISABLE
;
268 * _print is used for debugging.
269 * just print a readable description
275 struct vop_print_args
/* {
278 struct ptyfsnode
*ptyfs
= VTOPTYFS(ap
->a_vp
);
280 printf("tag VT_PTYFS, type %d, pty %d\n",
281 ptyfs
->ptyfs_type
, ptyfs
->ptyfs_pty
);
286 * Invent attributes for ptyfsnode (vp) and store
288 * Directories lengths are returned as zero since
289 * any real length would require the genuine size
290 * to be computed, and nothing cares anyway.
292 * this is relatively minimal for ptyfs.
295 ptyfs_getattr(void *v
)
297 struct vop_getattr_args
/* {
302 struct ptyfsnode
*ptyfs
= VTOPTYFS(ap
->a_vp
);
303 struct vattr
*vap
= ap
->a_vap
;
305 PTYFS_ITIMES(ptyfs
, NULL
, NULL
, NULL
);
307 /* start by zeroing out the attributes */
310 /* next do all the common fields */
311 vap
->va_type
= ap
->a_vp
->v_type
;
312 vap
->va_fsid
= ap
->a_vp
->v_mount
->mnt_stat
.f_fsidx
.__fsid_val
[0];
313 vap
->va_fileid
= ptyfs
->ptyfs_fileno
;
317 vap
->va_blocksize
= PAGE_SIZE
;
319 vap
->va_atime
= ptyfs
->ptyfs_atime
;
320 vap
->va_mtime
= ptyfs
->ptyfs_mtime
;
321 vap
->va_ctime
= ptyfs
->ptyfs_ctime
;
322 vap
->va_birthtime
= ptyfs
->ptyfs_birthtime
;
323 vap
->va_mode
= ptyfs
->ptyfs_mode
;
324 vap
->va_flags
= ptyfs
->ptyfs_flags
;
325 vap
->va_uid
= ptyfs
->ptyfs_uid
;
326 vap
->va_gid
= ptyfs
->ptyfs_gid
;
328 switch (ptyfs
->ptyfs_type
) {
331 if (pty_isfree(ptyfs
->ptyfs_pty
, 1))
333 vap
->va_bytes
= vap
->va_size
= 0;
334 vap
->va_rdev
= ap
->a_vp
->v_rdev
;
338 vap
->va_bytes
= vap
->va_size
= DEV_BSIZE
;
350 ptyfs_setattr(void *v
)
352 struct vop_setattr_args
/* {
353 struct vnodeop_desc *a_desc;
358 struct vnode
*vp
= ap
->a_vp
;
359 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
360 struct vattr
*vap
= ap
->a_vap
;
361 kauth_cred_t cred
= ap
->a_cred
;
362 struct lwp
*l
= curlwp
;
365 if (vap
->va_size
!= VNOVAL
) {
366 switch (ptyfs
->ptyfs_type
) {
377 if (vap
->va_flags
!= VNOVAL
) {
378 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
380 if (kauth_cred_geteuid(cred
) != ptyfs
->ptyfs_uid
&&
381 (error
= kauth_authorize_generic(cred
, KAUTH_GENERIC_ISSUSER
,
384 /* Immutable and append-only flags are not supported on ptyfs. */
385 if (vap
->va_flags
& (IMMUTABLE
| APPEND
))
387 if (kauth_authorize_generic(cred
, KAUTH_GENERIC_ISSUSER
, NULL
) == 0) {
388 /* Snapshot flag cannot be set or cleared */
389 if ((vap
->va_flags
& SF_SNAPSHOT
) !=
390 (ptyfs
->ptyfs_flags
& SF_SNAPSHOT
))
392 ptyfs
->ptyfs_flags
= vap
->va_flags
;
394 if ((ptyfs
->ptyfs_flags
& SF_SETTABLE
) !=
395 (vap
->va_flags
& SF_SETTABLE
))
397 ptyfs
->ptyfs_flags
&= SF_SETTABLE
;
398 ptyfs
->ptyfs_flags
|= (vap
->va_flags
& UF_SETTABLE
);
400 ptyfs
->ptyfs_flag
|= PTYFS_CHANGE
;
404 * Go through the fields and update iff not VNOVAL.
406 if (vap
->va_uid
!= (uid_t
)VNOVAL
|| vap
->va_gid
!= (gid_t
)VNOVAL
) {
407 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
409 if (ptyfs
->ptyfs_type
== PTYFSroot
)
411 error
= ptyfs_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
, l
);
416 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
||
417 vap
->va_birthtime
.tv_sec
!= VNOVAL
) {
418 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
420 if ((ptyfs
->ptyfs_flags
& SF_SNAPSHOT
) != 0)
422 error
= genfs_can_chtimes(vp
, vap
->va_vaflags
, ptyfs
->ptyfs_uid
,
426 if (vap
->va_atime
.tv_sec
!= VNOVAL
)
427 if (!(vp
->v_mount
->mnt_flag
& MNT_NOATIME
))
428 ptyfs
->ptyfs_flag
|= PTYFS_ACCESS
;
429 if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
430 ptyfs
->ptyfs_flag
|= PTYFS_CHANGE
| PTYFS_MODIFY
;
431 if (vap
->va_birthtime
.tv_sec
!= VNOVAL
)
432 ptyfs
->ptyfs_birthtime
= vap
->va_birthtime
;
433 ptyfs
->ptyfs_flag
|= PTYFS_CHANGE
;
434 error
= ptyfs_update(vp
, &vap
->va_atime
, &vap
->va_mtime
, 0);
438 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
439 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
441 if (ptyfs
->ptyfs_type
== PTYFSroot
)
443 if ((ptyfs
->ptyfs_flags
& SF_SNAPSHOT
) != 0 &&
445 (S_IXUSR
|S_IWUSR
|S_IXGRP
|S_IWGRP
|S_IXOTH
|S_IWOTH
)))
447 error
= ptyfs_chmod(vp
, vap
->va_mode
, cred
, l
);
451 VN_KNOTE(vp
, NOTE_ATTRIB
);
456 * Change the mode on a file.
457 * Inode must be locked before calling.
460 ptyfs_chmod(struct vnode
*vp
, mode_t mode
, kauth_cred_t cred
, struct lwp
*l
)
462 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
465 error
= genfs_can_chmod(vp
, cred
, ptyfs
->ptyfs_uid
,
466 ptyfs
->ptyfs_gid
, mode
);
470 ptyfs
->ptyfs_mode
&= ~ALLPERMS
;
471 ptyfs
->ptyfs_mode
|= (mode
& ALLPERMS
);
476 * Perform chown operation on inode ip;
477 * inode must be locked prior to call.
480 ptyfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, kauth_cred_t cred
,
483 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
486 if (uid
== (uid_t
)VNOVAL
)
487 uid
= ptyfs
->ptyfs_uid
;
488 if (gid
== (gid_t
)VNOVAL
)
489 gid
= ptyfs
->ptyfs_gid
;
491 error
= genfs_can_chown(vp
, cred
, ptyfs
->ptyfs_uid
,
492 ptyfs
->ptyfs_gid
, uid
, gid
);
496 ptyfs
->ptyfs_gid
= gid
;
497 ptyfs
->ptyfs_uid
= uid
;
502 ptyfs_check_possible(struct vnode
*vp
, mode_t mode
)
509 ptyfs_check_permitted(struct vattr
*va
, mode_t mode
, kauth_cred_t cred
)
512 return genfs_can_access(va
->va_type
, va
->va_mode
,
513 va
->va_uid
, va
->va_gid
, mode
, cred
);
517 * implement access checking.
519 * actually, the check for super-user is slightly
520 * broken since it will allow read access to write-only
521 * objects. this doesn't cause any particular trouble
522 * but does mean that the i/o entry points need to check
523 * that the operation really does make sense.
526 ptyfs_access(void *v
)
528 struct vop_access_args
/* {
536 if ((error
= VOP_GETATTR(ap
->a_vp
, &va
, ap
->a_cred
)) != 0)
539 error
= ptyfs_check_possible(ap
->a_vp
, ap
->a_mode
);
543 error
= ptyfs_check_permitted(&va
, ap
->a_mode
, ap
->a_cred
);
549 * lookup. this is incredibly complicated in the
550 * general case, however for most pseudo-filesystems
551 * very little needs to be done.
553 * Locking isn't hard here, just poorly documented.
555 * If we're looking up ".", just vref the parent & return it.
557 * If we're looking up "..", unlock the parent, and lock "..". If everything
558 * went ok, try to re-lock the parent. We do this to prevent lock races.
560 * For anything else, get the needed node.
562 * We try to exit with the parent locked in error cases.
565 ptyfs_lookup(void *v
)
567 struct vop_lookup_args
/* {
568 struct vnode * a_dvp;
569 struct vnode ** a_vpp;
570 struct componentname * a_cnp;
572 struct componentname
*cnp
= ap
->a_cnp
;
573 struct vnode
**vpp
= ap
->a_vpp
;
574 struct vnode
*dvp
= ap
->a_dvp
;
575 const char *pname
= cnp
->cn_nameptr
;
576 struct ptyfsnode
*ptyfs
;
581 if (cnp
->cn_nameiop
== DELETE
|| cnp
->cn_nameiop
== RENAME
)
584 if (cnp
->cn_namelen
== 1 && *pname
== '.') {
590 ptyfs
= VTOPTYFS(dvp
);
591 switch (ptyfs
->ptyfs_type
) {
594 * Shouldn't get here with .. in the root node.
596 if (cnp
->cn_flags
& ISDOTDOT
)
599 pty
= atoi(pname
, cnp
->cn_namelen
);
601 if (pty
< 0 || pty
>= npty
|| pty_isfree(pty
, 1))
604 error
= ptyfs_allocvp(dvp
->v_mount
, vpp
, PTYFSpts
, pty
,
612 return cnp
->cn_nameiop
== LOOKUP
? ENOENT
: EROFS
;
616 * readdir returns directory entries from ptyfsnode (vp).
618 * the strategy here with ptyfs is to generate a single
619 * directory entry at a time (struct dirent) and then
620 * copy that out to userland using uiomove. a more efficent
621 * though more complex implementation, would try to minimize
622 * the number of calls to uiomove(). for ptyfs, this is
623 * hardly worth the added code complexity.
625 * this should just be done through read()
628 ptyfs_readdir(void *v
)
630 struct vop_readdir_args
/* {
638 struct uio
*uio
= ap
->a_uio
;
640 struct ptyfsnode
*ptyfs
;
643 off_t
*cookies
= NULL
;
649 ptyfs
= VTOPTYFS(vp
);
651 if (uio
->uio_resid
< UIO_MX
)
653 if (uio
->uio_offset
< 0)
656 dp
= malloc(sizeof(struct dirent
), M_PTYFSTMP
, M_WAITOK
| M_ZERO
);
660 dp
->d_reclen
= UIO_MX
;
661 ncookies
= uio
->uio_resid
/ UIO_MX
;
663 if (ptyfs
->ptyfs_type
!= PTYFSroot
) {
671 if (ap
->a_ncookies
) {
672 ncookies
= min(ncookies
, (npty
+ 2 - i
));
673 cookies
= malloc(ncookies
* sizeof (off_t
),
675 *ap
->a_cookies
= cookies
;
679 /* `.' and/or `..' */
680 dp
->d_fileno
= PTYFS_FILENO(0, PTYFSroot
);
681 dp
->d_namlen
= i
+ 1;
682 (void)memcpy(dp
->d_name
, "..", dp
->d_namlen
);
683 dp
->d_name
[i
+ 1] = '\0';
685 if ((error
= uiomove(dp
, UIO_MX
, uio
)) != 0)
691 for (; uio
->uio_resid
>= UIO_MX
&& i
< npty
; i
++) {
692 /* check for used ptys */
693 if (pty_isfree(i
- 2, 1))
696 dp
->d_fileno
= PTYFS_FILENO(i
- 2, PTYFSpts
);
697 dp
->d_namlen
= snprintf(dp
->d_name
, sizeof(dp
->d_name
),
698 "%lld", (long long)(i
- 2));
700 if ((error
= uiomove(dp
, UIO_MX
, uio
)) != 0)
708 /* not pertinent in error cases */
711 if (ap
->a_ncookies
) {
714 free(*ap
->a_cookies
, M_TEMP
);
716 *ap
->a_cookies
= NULL
;
718 *ap
->a_ncookies
= ncookies
;
721 free(dp
, M_PTYFSTMP
);
728 struct vop_open_args
/* {
733 struct vnode
*vp
= ap
->a_vp
;
734 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
736 ptyfs
->ptyfs_flag
|= PTYFS_CHANGE
|PTYFS_ACCESS
;
737 switch (ptyfs
->ptyfs_type
) {
751 struct vop_close_args
/* {
756 struct vnode
*vp
= ap
->a_vp
;
757 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
759 mutex_enter(&vp
->v_interlock
);
760 if (vp
->v_usecount
> 1)
761 PTYFS_ITIMES(ptyfs
, NULL
, NULL
, NULL
);
762 mutex_exit(&vp
->v_interlock
);
764 switch (ptyfs
->ptyfs_type
) {
767 return spec_close(v
);
778 struct vop_read_args
/* {
785 struct vnode
*vp
= ap
->a_vp
;
786 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
789 ptyfs
->ptyfs_flag
|= PTYFS_ACCESS
;
790 /* hardclock() resolution is good enough for ptyfs */
792 (void)ptyfs_update(vp
, &ts
, &ts
, 0);
794 switch (ptyfs
->ptyfs_type
) {
798 error
= cdev_read(vp
->v_rdev
, ap
->a_uio
, ap
->a_ioflag
);
799 vn_lock(vp
, LK_RETRY
|LK_EXCLUSIVE
);
809 struct vop_write_args
/* {
816 struct vnode
*vp
= ap
->a_vp
;
817 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
820 ptyfs
->ptyfs_flag
|= PTYFS_MODIFY
;
822 (void)ptyfs_update(vp
, &ts
, &ts
, 0);
824 switch (ptyfs
->ptyfs_type
) {
828 error
= cdev_write(vp
->v_rdev
, ap
->a_uio
, ap
->a_ioflag
);
829 vn_lock(vp
, LK_RETRY
|LK_EXCLUSIVE
);
839 struct vop_ioctl_args
/* {
846 struct vnode
*vp
= ap
->a_vp
;
847 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
849 switch (ptyfs
->ptyfs_type
) {
852 return cdev_ioctl(vp
->v_rdev
, ap
->a_command
,
853 ap
->a_data
, ap
->a_fflag
, curlwp
);
862 struct vop_poll_args
/* {
866 struct vnode
*vp
= ap
->a_vp
;
867 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
869 switch (ptyfs
->ptyfs_type
) {
872 return cdev_poll(vp
->v_rdev
, ap
->a_events
, curlwp
);
874 return genfs_poll(v
);
879 ptyfs_kqfilter(void *v
)
881 struct vop_kqfilter_args
/* {
885 struct vnode
*vp
= ap
->a_vp
;
886 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
888 switch (ptyfs
->ptyfs_type
) {
891 return cdev_kqfilter(vp
->v_rdev
, ap
->a_kn
);
893 return genfs_kqfilter(v
);
898 ptyfs_update(struct vnode
*vp
, const struct timespec
*acc
,
899 const struct timespec
*mod
, int flags
)
901 struct ptyfsnode
*ptyfs
= VTOPTYFS(vp
);
903 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
906 PTYFS_ITIMES(ptyfs
, acc
, mod
, NULL
);
911 ptyfs_itimes(struct ptyfsnode
*ptyfs
, const struct timespec
*acc
,
912 const struct timespec
*mod
, const struct timespec
*cre
)
916 KASSERT(ptyfs
->ptyfs_flag
& (PTYFS_ACCESS
|PTYFS_CHANGE
|PTYFS_MODIFY
));
919 if (ptyfs
->ptyfs_flag
& PTYFS_ACCESS
) {
922 ptyfs
->ptyfs_atime
= *acc
;
924 if (ptyfs
->ptyfs_flag
& PTYFS_MODIFY
) {
927 ptyfs
->ptyfs_mtime
= *mod
;
929 if (ptyfs
->ptyfs_flag
& PTYFS_CHANGE
) {
932 ptyfs
->ptyfs_ctime
= *cre
;
934 ptyfs
->ptyfs_flag
&= ~(PTYFS_ACCESS
|PTYFS_CHANGE
|PTYFS_MODIFY
);
938 * convert decimal ascii to int
941 atoi(const char *b
, size_t len
)
947 if (c
< '0' || c
> '9')
949 p
= 10 * p
+ (c
- '0');