1 1.69 riastrad /* $NetBSD: ptyfs_vnops.c,v 1.69 2022/08/05 10:36:02 riastradh Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /* 4 1.1 jdolecek * Copyright (c) 1993, 1995 5 1.1 jdolecek * The Regents of the University of California. All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * This code is derived from software contributed to Berkeley by 8 1.1 jdolecek * Jan-Simon Pendry. 9 1.1 jdolecek * 10 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 11 1.1 jdolecek * modification, are permitted provided that the following conditions 12 1.1 jdolecek * are met: 13 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 15 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 17 1.1 jdolecek * documentation and/or other materials provided with the distribution. 18 1.1 jdolecek * 3. Neither the name of the University nor the names of its contributors 19 1.1 jdolecek * may be used to endorse or promote products derived from this software 20 1.1 jdolecek * without specific prior written permission. 21 1.1 jdolecek * 22 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 jdolecek * SUCH DAMAGE. 33 1.1 jdolecek * 34 1.1 jdolecek * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 35 1.1 jdolecek */ 36 1.1 jdolecek 37 1.1 jdolecek /* 38 1.1 jdolecek * Copyright (c) 1993 Jan-Simon Pendry 39 1.1 jdolecek * 40 1.1 jdolecek * This code is derived from software contributed to Berkeley by 41 1.1 jdolecek * Jan-Simon Pendry. 42 1.1 jdolecek * 43 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 44 1.1 jdolecek * modification, are permitted provided that the following conditions 45 1.1 jdolecek * are met: 46 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 47 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 48 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 49 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 50 1.1 jdolecek * documentation and/or other materials provided with the distribution. 51 1.1 jdolecek * 3. All advertising materials mentioning features or use of this software 52 1.1 jdolecek * must display the following acknowledgement: 53 1.1 jdolecek * This product includes software developed by the University of 54 1.1 jdolecek * California, Berkeley and its contributors. 55 1.1 jdolecek * 4. Neither the name of the University nor the names of its contributors 56 1.1 jdolecek * may be used to endorse or promote products derived from this software 57 1.1 jdolecek * without specific prior written permission. 58 1.1 jdolecek * 59 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 1.1 jdolecek * SUCH DAMAGE. 70 1.1 jdolecek * 71 1.1 jdolecek * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 72 1.1 jdolecek */ 73 1.1 jdolecek 74 1.1 jdolecek /* 75 1.1 jdolecek * ptyfs vnode interface 76 1.1 jdolecek */ 77 1.1 jdolecek 78 1.1 jdolecek #include <sys/cdefs.h> 79 1.69 riastrad __KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.69 2022/08/05 10:36:02 riastradh Exp $"); 80 1.1 jdolecek 81 1.1 jdolecek #include <sys/param.h> 82 1.1 jdolecek #include <sys/systm.h> 83 1.1 jdolecek #include <sys/time.h> 84 1.1 jdolecek #include <sys/kernel.h> 85 1.1 jdolecek #include <sys/file.h> 86 1.1 jdolecek #include <sys/filedesc.h> 87 1.1 jdolecek #include <sys/proc.h> 88 1.1 jdolecek #include <sys/vnode.h> 89 1.1 jdolecek #include <sys/namei.h> 90 1.1 jdolecek #include <sys/malloc.h> 91 1.1 jdolecek #include <sys/mount.h> 92 1.1 jdolecek #include <sys/select.h> 93 1.1 jdolecek #include <sys/dirent.h> 94 1.1 jdolecek #include <sys/resourcevar.h> 95 1.1 jdolecek #include <sys/stat.h> 96 1.1 jdolecek #include <sys/conf.h> 97 1.1 jdolecek #include <sys/tty.h> 98 1.1 jdolecek #include <sys/pty.h> 99 1.14 elad #include <sys/kauth.h> 100 1.1 jdolecek 101 1.1 jdolecek #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ 102 1.1 jdolecek 103 1.1 jdolecek #include <machine/reg.h> 104 1.1 jdolecek 105 1.2 jdolecek #include <fs/ptyfs/ptyfs.h> 106 1.1 jdolecek #include <miscfs/genfs/genfs.h> 107 1.1 jdolecek #include <miscfs/specfs/specdev.h> 108 1.1 jdolecek 109 1.24 rumble MALLOC_DECLARE(M_PTYFSTMP); 110 1.24 rumble 111 1.1 jdolecek /* 112 1.1 jdolecek * Vnode Operations. 113 1.1 jdolecek * 114 1.1 jdolecek */ 115 1.1 jdolecek 116 1.1 jdolecek int ptyfs_lookup (void *); 117 1.1 jdolecek int ptyfs_open (void *); 118 1.1 jdolecek int ptyfs_close (void *); 119 1.1 jdolecek int ptyfs_access (void *); 120 1.1 jdolecek int ptyfs_getattr (void *); 121 1.1 jdolecek int ptyfs_setattr (void *); 122 1.1 jdolecek int ptyfs_read (void *); 123 1.1 jdolecek int ptyfs_write (void *); 124 1.1 jdolecek int ptyfs_ioctl (void *); 125 1.1 jdolecek int ptyfs_poll (void *); 126 1.1 jdolecek int ptyfs_kqfilter (void *); 127 1.1 jdolecek int ptyfs_readdir (void *); 128 1.1 jdolecek int ptyfs_reclaim (void *); 129 1.46 christos int ptyfs_inactive (void *); 130 1.1 jdolecek int ptyfs_print (void *); 131 1.1 jdolecek int ptyfs_pathconf (void *); 132 1.42 christos int ptyfs_advlock (void *); 133 1.1 jdolecek 134 1.11 yamt static int ptyfs_update(struct vnode *, const struct timespec *, 135 1.11 yamt const struct timespec *, int); 136 1.14 elad static int ptyfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, 137 1.16 ad struct lwp *); 138 1.16 ad static int ptyfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *); 139 1.1 jdolecek static int atoi(const char *, size_t); 140 1.1 jdolecek 141 1.1 jdolecek /* 142 1.1 jdolecek * ptyfs vnode operations. 143 1.1 jdolecek */ 144 1.1 jdolecek int (**ptyfs_vnodeop_p)(void *); 145 1.1 jdolecek const struct vnodeopv_entry_desc ptyfs_vnodeop_entries[] = { 146 1.1 jdolecek { &vop_default_desc, vn_default_error }, 147 1.64 dholland { &vop_parsepath_desc, genfs_parsepath }, /* parsepath */ 148 1.1 jdolecek { &vop_lookup_desc, ptyfs_lookup }, /* lookup */ 149 1.65 dholland { &vop_create_desc, genfs_eopnotsupp }, /* create */ 150 1.65 dholland { &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */ 151 1.1 jdolecek { &vop_open_desc, ptyfs_open }, /* open */ 152 1.1 jdolecek { &vop_close_desc, ptyfs_close }, /* close */ 153 1.1 jdolecek { &vop_access_desc, ptyfs_access }, /* access */ 154 1.59 christos { &vop_accessx_desc, genfs_accessx }, /* accessx */ 155 1.1 jdolecek { &vop_getattr_desc, ptyfs_getattr }, /* getattr */ 156 1.1 jdolecek { &vop_setattr_desc, ptyfs_setattr }, /* setattr */ 157 1.1 jdolecek { &vop_read_desc, ptyfs_read }, /* read */ 158 1.1 jdolecek { &vop_write_desc, ptyfs_write }, /* write */ 159 1.47 dholland { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ 160 1.47 dholland { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ 161 1.1 jdolecek { &vop_ioctl_desc, ptyfs_ioctl }, /* ioctl */ 162 1.65 dholland { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 163 1.1 jdolecek { &vop_poll_desc, ptyfs_poll }, /* poll */ 164 1.1 jdolecek { &vop_kqfilter_desc, ptyfs_kqfilter }, /* kqfilter */ 165 1.65 dholland { &vop_revoke_desc, genfs_revoke }, /* revoke */ 166 1.65 dholland { &vop_mmap_desc, genfs_eopnotsupp }, /* mmap */ 167 1.65 dholland { &vop_fsync_desc, genfs_nullop }, /* fsync */ 168 1.65 dholland { &vop_seek_desc, genfs_nullop }, /* seek */ 169 1.65 dholland { &vop_remove_desc, genfs_eopnotsupp }, /* remove */ 170 1.66 dholland { &vop_link_desc, genfs_eopnotsupp }, /* link */ 171 1.65 dholland { &vop_rename_desc, genfs_eopnotsupp }, /* rename */ 172 1.65 dholland { &vop_mkdir_desc, genfs_eopnotsupp }, /* mkdir */ 173 1.65 dholland { &vop_rmdir_desc, genfs_eopnotsupp }, /* rmdir */ 174 1.66 dholland { &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */ 175 1.1 jdolecek { &vop_readdir_desc, ptyfs_readdir }, /* readdir */ 176 1.65 dholland { &vop_readlink_desc, genfs_eopnotsupp }, /* readlink */ 177 1.65 dholland { &vop_abortop_desc, genfs_abortop }, /* abortop */ 178 1.46 christos { &vop_inactive_desc, ptyfs_inactive }, /* inactive */ 179 1.1 jdolecek { &vop_reclaim_desc, ptyfs_reclaim }, /* reclaim */ 180 1.65 dholland { &vop_lock_desc, genfs_lock }, /* lock */ 181 1.65 dholland { &vop_unlock_desc, genfs_unlock }, /* unlock */ 182 1.65 dholland { &vop_bmap_desc, genfs_eopnotsupp }, /* bmap */ 183 1.65 dholland { &vop_strategy_desc, genfs_badop }, /* strategy */ 184 1.1 jdolecek { &vop_print_desc, ptyfs_print }, /* print */ 185 1.65 dholland { &vop_islocked_desc, genfs_islocked }, /* islocked */ 186 1.1 jdolecek { &vop_pathconf_desc, ptyfs_pathconf }, /* pathconf */ 187 1.1 jdolecek { &vop_advlock_desc, ptyfs_advlock }, /* advlock */ 188 1.65 dholland { &vop_bwrite_desc, genfs_eopnotsupp }, /* bwrite */ 189 1.65 dholland { &vop_putpages_desc, genfs_null_putpages }, /* putpages */ 190 1.1 jdolecek { NULL, NULL } 191 1.1 jdolecek }; 192 1.1 jdolecek const struct vnodeopv_desc ptyfs_vnodeop_opv_desc = 193 1.1 jdolecek { &ptyfs_vnodeop_p, ptyfs_vnodeop_entries }; 194 1.1 jdolecek 195 1.1 jdolecek /* 196 1.49 hannken * free any private data and remove the node 197 1.1 jdolecek * from any private lists. 198 1.1 jdolecek */ 199 1.1 jdolecek int 200 1.1 jdolecek ptyfs_reclaim(void *v) 201 1.1 jdolecek { 202 1.54 riastrad struct vop_reclaim_v2_args /* { 203 1.1 jdolecek struct vnode *a_vp; 204 1.1 jdolecek } */ *ap = v; 205 1.49 hannken struct vnode *vp = ap->a_vp; 206 1.49 hannken 207 1.54 riastrad VOP_UNLOCK(vp); 208 1.54 riastrad 209 1.49 hannken vp->v_data = NULL; 210 1.49 hannken return 0; 211 1.1 jdolecek } 212 1.1 jdolecek 213 1.46 christos int 214 1.46 christos ptyfs_inactive(void *v) 215 1.46 christos { 216 1.53 riastrad struct vop_inactive_v2_args /* { 217 1.46 christos struct vnode *a_vp; 218 1.46 christos bool *a_recycle; 219 1.46 christos } */ *ap = v; 220 1.46 christos struct vnode *vp = ap->a_vp; 221 1.46 christos struct ptyfsnode *ptyfs = VTOPTYFS(vp); 222 1.46 christos 223 1.48 hannken if (ptyfs->ptyfs_type == PTYFSptc) 224 1.48 hannken ptyfs_clr_active(vp->v_mount, ptyfs->ptyfs_pty); 225 1.53 riastrad 226 1.51 hannken return 0; 227 1.46 christos } 228 1.46 christos 229 1.1 jdolecek /* 230 1.1 jdolecek * Return POSIX pathconf information applicable to special devices. 231 1.1 jdolecek */ 232 1.1 jdolecek int 233 1.1 jdolecek ptyfs_pathconf(void *v) 234 1.1 jdolecek { 235 1.1 jdolecek struct vop_pathconf_args /* { 236 1.1 jdolecek struct vnode *a_vp; 237 1.1 jdolecek int a_name; 238 1.1 jdolecek register_t *a_retval; 239 1.1 jdolecek } */ *ap = v; 240 1.1 jdolecek 241 1.1 jdolecek switch (ap->a_name) { 242 1.1 jdolecek case _PC_LINK_MAX: 243 1.1 jdolecek *ap->a_retval = LINK_MAX; 244 1.1 jdolecek return 0; 245 1.1 jdolecek case _PC_MAX_CANON: 246 1.1 jdolecek *ap->a_retval = MAX_CANON; 247 1.1 jdolecek return 0; 248 1.1 jdolecek case _PC_MAX_INPUT: 249 1.1 jdolecek *ap->a_retval = MAX_INPUT; 250 1.1 jdolecek return 0; 251 1.1 jdolecek case _PC_PIPE_BUF: 252 1.1 jdolecek *ap->a_retval = PIPE_BUF; 253 1.1 jdolecek return 0; 254 1.1 jdolecek case _PC_CHOWN_RESTRICTED: 255 1.1 jdolecek *ap->a_retval = 1; 256 1.1 jdolecek return 0; 257 1.1 jdolecek case _PC_VDISABLE: 258 1.1 jdolecek *ap->a_retval = _POSIX_VDISABLE; 259 1.1 jdolecek return 0; 260 1.1 jdolecek case _PC_SYNC_IO: 261 1.1 jdolecek *ap->a_retval = 1; 262 1.1 jdolecek return 0; 263 1.1 jdolecek default: 264 1.60 christos return genfs_pathconf(ap); 265 1.1 jdolecek } 266 1.1 jdolecek } 267 1.1 jdolecek 268 1.1 jdolecek /* 269 1.1 jdolecek * _print is used for debugging. 270 1.1 jdolecek * just print a readable description 271 1.1 jdolecek * of (vp). 272 1.1 jdolecek */ 273 1.1 jdolecek int 274 1.1 jdolecek ptyfs_print(void *v) 275 1.1 jdolecek { 276 1.1 jdolecek struct vop_print_args /* { 277 1.1 jdolecek struct vnode *a_vp; 278 1.1 jdolecek } */ *ap = v; 279 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp); 280 1.1 jdolecek 281 1.1 jdolecek printf("tag VT_PTYFS, type %d, pty %d\n", 282 1.1 jdolecek ptyfs->ptyfs_type, ptyfs->ptyfs_pty); 283 1.1 jdolecek return 0; 284 1.1 jdolecek } 285 1.1 jdolecek 286 1.1 jdolecek /* 287 1.42 christos * support advisory locking on pty nodes 288 1.42 christos */ 289 1.42 christos int 290 1.42 christos ptyfs_advlock(void *v) 291 1.42 christos { 292 1.42 christos struct vop_print_args /* { 293 1.42 christos struct vnode *a_vp; 294 1.42 christos } */ *ap = v; 295 1.42 christos struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp); 296 1.42 christos 297 1.42 christos switch (ptyfs->ptyfs_type) { 298 1.42 christos case PTYFSpts: 299 1.42 christos case PTYFSptc: 300 1.42 christos return spec_advlock(v); 301 1.42 christos default: 302 1.42 christos return EOPNOTSUPP; 303 1.42 christos } 304 1.42 christos } 305 1.42 christos 306 1.42 christos /* 307 1.1 jdolecek * Invent attributes for ptyfsnode (vp) and store 308 1.1 jdolecek * them in (vap). 309 1.1 jdolecek * Directories lengths are returned as zero since 310 1.1 jdolecek * any real length would require the genuine size 311 1.1 jdolecek * to be computed, and nothing cares anyway. 312 1.1 jdolecek * 313 1.1 jdolecek * this is relatively minimal for ptyfs. 314 1.1 jdolecek */ 315 1.1 jdolecek int 316 1.1 jdolecek ptyfs_getattr(void *v) 317 1.1 jdolecek { 318 1.1 jdolecek struct vop_getattr_args /* { 319 1.1 jdolecek struct vnode *a_vp; 320 1.1 jdolecek struct vattr *a_vap; 321 1.14 elad kauth_cred_t a_cred; 322 1.1 jdolecek } */ *ap = v; 323 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp); 324 1.1 jdolecek struct vattr *vap = ap->a_vap; 325 1.1 jdolecek 326 1.9 christos PTYFS_ITIMES(ptyfs, NULL, NULL, NULL); 327 1.1 jdolecek 328 1.1 jdolecek /* start by zeroing out the attributes */ 329 1.33 pooka vattr_null(vap); 330 1.1 jdolecek 331 1.1 jdolecek /* next do all the common fields */ 332 1.1 jdolecek vap->va_type = ap->a_vp->v_type; 333 1.4 atatat vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 334 1.1 jdolecek vap->va_fileid = ptyfs->ptyfs_fileno; 335 1.1 jdolecek vap->va_gen = 0; 336 1.1 jdolecek vap->va_flags = 0; 337 1.1 jdolecek vap->va_blocksize = PAGE_SIZE; 338 1.1 jdolecek 339 1.1 jdolecek vap->va_atime = ptyfs->ptyfs_atime; 340 1.1 jdolecek vap->va_mtime = ptyfs->ptyfs_mtime; 341 1.1 jdolecek vap->va_ctime = ptyfs->ptyfs_ctime; 342 1.1 jdolecek vap->va_birthtime = ptyfs->ptyfs_birthtime; 343 1.1 jdolecek vap->va_mode = ptyfs->ptyfs_mode; 344 1.1 jdolecek vap->va_flags = ptyfs->ptyfs_flags; 345 1.1 jdolecek vap->va_uid = ptyfs->ptyfs_uid; 346 1.1 jdolecek vap->va_gid = ptyfs->ptyfs_gid; 347 1.1 jdolecek 348 1.1 jdolecek switch (ptyfs->ptyfs_type) { 349 1.1 jdolecek case PTYFSpts: 350 1.1 jdolecek case PTYFSptc: 351 1.1 jdolecek if (pty_isfree(ptyfs->ptyfs_pty, 1)) 352 1.1 jdolecek return ENOENT; 353 1.5 atatat vap->va_bytes = vap->va_size = 0; 354 1.7 perry vap->va_rdev = ap->a_vp->v_rdev; 355 1.42 christos vap->va_nlink = 1; 356 1.1 jdolecek break; 357 1.1 jdolecek case PTYFSroot: 358 1.1 jdolecek vap->va_rdev = 0; 359 1.1 jdolecek vap->va_bytes = vap->va_size = DEV_BSIZE; 360 1.42 christos vap->va_nlink = 2; 361 1.1 jdolecek break; 362 1.1 jdolecek default: 363 1.1 jdolecek return EOPNOTSUPP; 364 1.1 jdolecek } 365 1.1 jdolecek 366 1.1 jdolecek return 0; 367 1.1 jdolecek } 368 1.1 jdolecek 369 1.1 jdolecek /*ARGSUSED*/ 370 1.1 jdolecek int 371 1.1 jdolecek ptyfs_setattr(void *v) 372 1.1 jdolecek { 373 1.1 jdolecek struct vop_setattr_args /* { 374 1.1 jdolecek struct vnodeop_desc *a_desc; 375 1.1 jdolecek struct vnode *a_vp; 376 1.1 jdolecek struct vattr *a_vap; 377 1.14 elad kauth_cred_t a_cred; 378 1.1 jdolecek } */ *ap = v; 379 1.1 jdolecek struct vnode *vp = ap->a_vp; 380 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 381 1.1 jdolecek struct vattr *vap = ap->a_vap; 382 1.14 elad kauth_cred_t cred = ap->a_cred; 383 1.26 pooka struct lwp *l = curlwp; 384 1.1 jdolecek int error; 385 1.39 elad kauth_action_t action = KAUTH_VNODE_WRITE_FLAGS; 386 1.39 elad bool changing_sysflags = false; 387 1.1 jdolecek 388 1.57 christos if (vap->va_size != VNOVALSIZE) { 389 1.1 jdolecek switch (ptyfs->ptyfs_type) { 390 1.1 jdolecek case PTYFSroot: 391 1.1 jdolecek return EISDIR; 392 1.1 jdolecek case PTYFSpts: 393 1.1 jdolecek case PTYFSptc: 394 1.1 jdolecek break; 395 1.1 jdolecek default: 396 1.1 jdolecek return EINVAL; 397 1.1 jdolecek } 398 1.1 jdolecek } 399 1.1 jdolecek 400 1.57 christos if (vap->va_flags != VNOVALFLAGS) { 401 1.1 jdolecek if (vp->v_mount->mnt_flag & MNT_RDONLY) 402 1.1 jdolecek return EROFS; 403 1.39 elad 404 1.20 elad /* Immutable and append-only flags are not supported on ptyfs. */ 405 1.20 elad if (vap->va_flags & (IMMUTABLE | APPEND)) 406 1.20 elad return EINVAL; 407 1.39 elad 408 1.39 elad /* Snapshot flag cannot be set or cleared */ 409 1.39 elad if ((vap->va_flags & SF_SNAPSHOT) != (ptyfs->ptyfs_flags & SF_SNAPSHOT)) 410 1.39 elad return EPERM; 411 1.39 elad 412 1.39 elad if ((ptyfs->ptyfs_flags & SF_SETTABLE) != (vap->va_flags & SF_SETTABLE)) { 413 1.39 elad changing_sysflags = true; 414 1.39 elad action |= KAUTH_VNODE_WRITE_SYSFLAGS; 415 1.39 elad } 416 1.39 elad 417 1.39 elad error = kauth_authorize_vnode(cred, action, vp, NULL, 418 1.59 christos genfs_can_chflags(vp, cred, ptyfs->ptyfs_uid, 419 1.39 elad changing_sysflags)); 420 1.39 elad if (error) 421 1.39 elad return error; 422 1.39 elad 423 1.39 elad if (changing_sysflags) { 424 1.1 jdolecek ptyfs->ptyfs_flags = vap->va_flags; 425 1.1 jdolecek } else { 426 1.1 jdolecek ptyfs->ptyfs_flags &= SF_SETTABLE; 427 1.1 jdolecek ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE); 428 1.1 jdolecek } 429 1.40 christos ptyfs->ptyfs_status |= PTYFS_CHANGE; 430 1.1 jdolecek } 431 1.20 elad 432 1.1 jdolecek /* 433 1.1 jdolecek * Go through the fields and update iff not VNOVAL. 434 1.1 jdolecek */ 435 1.1 jdolecek if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 436 1.1 jdolecek if (vp->v_mount->mnt_flag & MNT_RDONLY) 437 1.1 jdolecek return EROFS; 438 1.16 ad error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); 439 1.1 jdolecek if (error) 440 1.1 jdolecek return error; 441 1.1 jdolecek } 442 1.1 jdolecek 443 1.1 jdolecek if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 444 1.1 jdolecek vap->va_birthtime.tv_sec != VNOVAL) { 445 1.1 jdolecek if (vp->v_mount->mnt_flag & MNT_RDONLY) 446 1.1 jdolecek return EROFS; 447 1.1 jdolecek if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0) 448 1.1 jdolecek return EPERM; 449 1.39 elad error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp, 450 1.59 christos NULL, genfs_can_chtimes(vp, cred, ptyfs->ptyfs_uid, 451 1.59 christos vap->va_vaflags)); 452 1.30 elad if (error) 453 1.1 jdolecek return (error); 454 1.1 jdolecek if (vap->va_atime.tv_sec != VNOVAL) 455 1.1 jdolecek if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) 456 1.40 christos ptyfs->ptyfs_status |= PTYFS_ACCESS; 457 1.37 christos if (vap->va_mtime.tv_sec != VNOVAL) { 458 1.40 christos ptyfs->ptyfs_status |= PTYFS_CHANGE | PTYFS_MODIFY; 459 1.37 christos if (vp->v_mount->mnt_flag & MNT_RELATIME) 460 1.40 christos ptyfs->ptyfs_status |= PTYFS_ACCESS; 461 1.37 christos } 462 1.1 jdolecek if (vap->va_birthtime.tv_sec != VNOVAL) 463 1.1 jdolecek ptyfs->ptyfs_birthtime = vap->va_birthtime; 464 1.40 christos ptyfs->ptyfs_status |= PTYFS_CHANGE; 465 1.11 yamt error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0); 466 1.1 jdolecek if (error) 467 1.1 jdolecek return error; 468 1.1 jdolecek } 469 1.1 jdolecek if (vap->va_mode != (mode_t)VNOVAL) { 470 1.1 jdolecek if (vp->v_mount->mnt_flag & MNT_RDONLY) 471 1.1 jdolecek return EROFS; 472 1.1 jdolecek if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 && 473 1.1 jdolecek (vap->va_mode & 474 1.1 jdolecek (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH))) 475 1.1 jdolecek return EPERM; 476 1.16 ad error = ptyfs_chmod(vp, vap->va_mode, cred, l); 477 1.1 jdolecek if (error) 478 1.1 jdolecek return error; 479 1.1 jdolecek } 480 1.1 jdolecek return 0; 481 1.1 jdolecek } 482 1.1 jdolecek 483 1.1 jdolecek /* 484 1.1 jdolecek * Change the mode on a file. 485 1.1 jdolecek * Inode must be locked before calling. 486 1.1 jdolecek */ 487 1.1 jdolecek static int 488 1.16 ad ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l) 489 1.1 jdolecek { 490 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 491 1.1 jdolecek int error; 492 1.1 jdolecek 493 1.39 elad error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp, 494 1.59 christos NULL, genfs_can_chmod(vp, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid, 495 1.59 christos mode)); 496 1.28 elad if (error) 497 1.28 elad return (error); 498 1.28 elad 499 1.1 jdolecek ptyfs->ptyfs_mode &= ~ALLPERMS; 500 1.1 jdolecek ptyfs->ptyfs_mode |= (mode & ALLPERMS); 501 1.1 jdolecek return 0; 502 1.1 jdolecek } 503 1.1 jdolecek 504 1.1 jdolecek /* 505 1.1 jdolecek * Perform chown operation on inode ip; 506 1.1 jdolecek * inode must be locked prior to call. 507 1.1 jdolecek */ 508 1.1 jdolecek static int 509 1.14 elad ptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, 510 1.16 ad struct lwp *l) 511 1.1 jdolecek { 512 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 513 1.28 elad int error; 514 1.1 jdolecek 515 1.1 jdolecek if (uid == (uid_t)VNOVAL) 516 1.1 jdolecek uid = ptyfs->ptyfs_uid; 517 1.1 jdolecek if (gid == (gid_t)VNOVAL) 518 1.1 jdolecek gid = ptyfs->ptyfs_gid; 519 1.28 elad 520 1.39 elad error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp, 521 1.59 christos NULL, genfs_can_chown(vp, cred, ptyfs->ptyfs_uid, ptyfs->ptyfs_gid, 522 1.39 elad uid, gid)); 523 1.28 elad if (error) 524 1.28 elad return (error); 525 1.1 jdolecek 526 1.1 jdolecek ptyfs->ptyfs_gid = gid; 527 1.1 jdolecek ptyfs->ptyfs_uid = uid; 528 1.1 jdolecek return 0; 529 1.1 jdolecek } 530 1.1 jdolecek 531 1.1 jdolecek /* 532 1.1 jdolecek * implement access checking. 533 1.1 jdolecek * 534 1.1 jdolecek * actually, the check for super-user is slightly 535 1.1 jdolecek * broken since it will allow read access to write-only 536 1.1 jdolecek * objects. this doesn't cause any particular trouble 537 1.1 jdolecek * but does mean that the i/o entry points need to check 538 1.1 jdolecek * that the operation really does make sense. 539 1.1 jdolecek */ 540 1.1 jdolecek int 541 1.1 jdolecek ptyfs_access(void *v) 542 1.1 jdolecek { 543 1.1 jdolecek struct vop_access_args /* { 544 1.1 jdolecek struct vnode *a_vp; 545 1.59 christos accmode_t a_accmode; 546 1.14 elad kauth_cred_t a_cred; 547 1.1 jdolecek } */ *ap = v; 548 1.1 jdolecek struct vattr va; 549 1.1 jdolecek int error; 550 1.1 jdolecek 551 1.26 pooka if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0) 552 1.1 jdolecek return error; 553 1.1 jdolecek 554 1.39 elad return kauth_authorize_vnode(ap->a_cred, 555 1.59 christos KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode), 556 1.59 christos ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred, va.va_uid, 557 1.59 christos va.va_gid, va.va_mode, NULL, ap->a_accmode)); 558 1.1 jdolecek } 559 1.1 jdolecek 560 1.1 jdolecek /* 561 1.1 jdolecek * lookup. this is incredibly complicated in the 562 1.1 jdolecek * general case, however for most pseudo-filesystems 563 1.1 jdolecek * very little needs to be done. 564 1.1 jdolecek * 565 1.1 jdolecek * Locking isn't hard here, just poorly documented. 566 1.1 jdolecek * 567 1.7 perry * If we're looking up ".", just vref the parent & return it. 568 1.1 jdolecek * 569 1.1 jdolecek * If we're looking up "..", unlock the parent, and lock "..". If everything 570 1.19 chs * went ok, try to re-lock the parent. We do this to prevent lock races. 571 1.19 chs * 572 1.19 chs * For anything else, get the needed node. 573 1.1 jdolecek * 574 1.1 jdolecek * We try to exit with the parent locked in error cases. 575 1.1 jdolecek */ 576 1.1 jdolecek int 577 1.1 jdolecek ptyfs_lookup(void *v) 578 1.1 jdolecek { 579 1.43 hannken struct vop_lookup_v2_args /* { 580 1.1 jdolecek struct vnode * a_dvp; 581 1.1 jdolecek struct vnode ** a_vpp; 582 1.1 jdolecek struct componentname * a_cnp; 583 1.1 jdolecek } */ *ap = v; 584 1.1 jdolecek struct componentname *cnp = ap->a_cnp; 585 1.1 jdolecek struct vnode **vpp = ap->a_vpp; 586 1.1 jdolecek struct vnode *dvp = ap->a_dvp; 587 1.1 jdolecek const char *pname = cnp->cn_nameptr; 588 1.1 jdolecek struct ptyfsnode *ptyfs; 589 1.19 chs int pty, error; 590 1.1 jdolecek 591 1.1 jdolecek *vpp = NULL; 592 1.1 jdolecek 593 1.1 jdolecek if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 594 1.1 jdolecek return EROFS; 595 1.1 jdolecek 596 1.1 jdolecek if (cnp->cn_namelen == 1 && *pname == '.') { 597 1.1 jdolecek *vpp = dvp; 598 1.33 pooka vref(dvp); 599 1.1 jdolecek return 0; 600 1.1 jdolecek } 601 1.1 jdolecek 602 1.1 jdolecek ptyfs = VTOPTYFS(dvp); 603 1.1 jdolecek switch (ptyfs->ptyfs_type) { 604 1.1 jdolecek case PTYFSroot: 605 1.1 jdolecek /* 606 1.1 jdolecek * Shouldn't get here with .. in the root node. 607 1.1 jdolecek */ 608 1.7 perry if (cnp->cn_flags & ISDOTDOT) 609 1.1 jdolecek return EIO; 610 1.1 jdolecek 611 1.1 jdolecek pty = atoi(pname, cnp->cn_namelen); 612 1.48 hannken if (pty < 0 || ptyfs_next_active(dvp->v_mount, pty) != pty) 613 1.1 jdolecek break; 614 1.48 hannken error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty); 615 1.43 hannken if (error) 616 1.43 hannken return error; 617 1.48 hannken if (ptyfs_next_active(dvp->v_mount, pty) != pty) { 618 1.49 hannken vrele(*vpp); 619 1.48 hannken *vpp = NULL; 620 1.48 hannken return ENOENT; 621 1.48 hannken } 622 1.43 hannken return 0; 623 1.1 jdolecek 624 1.1 jdolecek default: 625 1.1 jdolecek return ENOTDIR; 626 1.1 jdolecek } 627 1.1 jdolecek 628 1.1 jdolecek return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS; 629 1.1 jdolecek } 630 1.1 jdolecek 631 1.1 jdolecek /* 632 1.1 jdolecek * readdir returns directory entries from ptyfsnode (vp). 633 1.1 jdolecek * 634 1.1 jdolecek * the strategy here with ptyfs is to generate a single 635 1.1 jdolecek * directory entry at a time (struct dirent) and then 636 1.68 andvar * copy that out to userland using uiomove. a more efficient 637 1.1 jdolecek * though more complex implementation, would try to minimize 638 1.1 jdolecek * the number of calls to uiomove(). for ptyfs, this is 639 1.1 jdolecek * hardly worth the added code complexity. 640 1.1 jdolecek * 641 1.1 jdolecek * this should just be done through read() 642 1.1 jdolecek */ 643 1.1 jdolecek int 644 1.1 jdolecek ptyfs_readdir(void *v) 645 1.1 jdolecek { 646 1.1 jdolecek struct vop_readdir_args /* { 647 1.1 jdolecek struct vnode *a_vp; 648 1.1 jdolecek struct uio *a_uio; 649 1.14 elad kauth_cred_t a_cred; 650 1.1 jdolecek int *a_eofflag; 651 1.1 jdolecek off_t **a_cookies; 652 1.1 jdolecek int *a_ncookies; 653 1.1 jdolecek } */ *ap = v; 654 1.1 jdolecek struct uio *uio = ap->a_uio; 655 1.24 rumble struct dirent *dp; 656 1.1 jdolecek struct ptyfsnode *ptyfs; 657 1.1 jdolecek off_t i; 658 1.1 jdolecek int error; 659 1.1 jdolecek off_t *cookies = NULL; 660 1.1 jdolecek int ncookies; 661 1.1 jdolecek struct vnode *vp; 662 1.48 hannken int n, nc = 0; 663 1.1 jdolecek 664 1.1 jdolecek vp = ap->a_vp; 665 1.1 jdolecek ptyfs = VTOPTYFS(vp); 666 1.1 jdolecek 667 1.1 jdolecek if (uio->uio_resid < UIO_MX) 668 1.1 jdolecek return EINVAL; 669 1.1 jdolecek if (uio->uio_offset < 0) 670 1.1 jdolecek return EINVAL; 671 1.1 jdolecek 672 1.24 rumble dp = malloc(sizeof(struct dirent), M_PTYFSTMP, M_WAITOK | M_ZERO); 673 1.24 rumble 674 1.1 jdolecek error = 0; 675 1.1 jdolecek i = uio->uio_offset; 676 1.24 rumble dp->d_reclen = UIO_MX; 677 1.1 jdolecek ncookies = uio->uio_resid / UIO_MX; 678 1.1 jdolecek 679 1.25 rumble if (ptyfs->ptyfs_type != PTYFSroot) { 680 1.25 rumble error = ENOTDIR; 681 1.25 rumble goto out; 682 1.25 rumble } 683 1.1 jdolecek 684 1.25 rumble if (i >= npty) 685 1.25 rumble goto out; 686 1.1 jdolecek 687 1.25 rumble if (ap->a_ncookies) { 688 1.55 riastrad ncookies = uimin(ncookies, (npty + 2 - i)); 689 1.25 rumble cookies = malloc(ncookies * sizeof (off_t), 690 1.25 rumble M_TEMP, M_WAITOK); 691 1.25 rumble *ap->a_cookies = cookies; 692 1.25 rumble } 693 1.25 rumble 694 1.69 riastrad for (; i < 2 && uio->uio_resid >= UIO_MX; i++) { 695 1.25 rumble /* `.' and/or `..' */ 696 1.62 christos dp->d_fileno = PTYFS_FILENO(PTYFSroot, 0); 697 1.25 rumble dp->d_namlen = i + 1; 698 1.25 rumble (void)memcpy(dp->d_name, "..", dp->d_namlen); 699 1.25 rumble dp->d_name[i + 1] = '\0'; 700 1.25 rumble dp->d_type = DT_DIR; 701 1.25 rumble if ((error = uiomove(dp, UIO_MX, uio)) != 0) 702 1.25 rumble goto out; 703 1.25 rumble if (cookies) 704 1.25 rumble *cookies++ = i + 1; 705 1.25 rumble nc++; 706 1.25 rumble } 707 1.48 hannken while (uio->uio_resid >= UIO_MX) { 708 1.25 rumble /* check for used ptys */ 709 1.48 hannken n = ptyfs_next_active(vp->v_mount, i - 2); 710 1.48 hannken if (n < 0) 711 1.48 hannken break; 712 1.62 christos dp->d_fileno = PTYFS_FILENO(PTYFSpts, n); 713 1.25 rumble dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name), 714 1.48 hannken "%lld", (long long)(n)); 715 1.25 rumble dp->d_type = DT_CHR; 716 1.25 rumble if ((error = uiomove(dp, UIO_MX, uio)) != 0) 717 1.25 rumble goto out; 718 1.48 hannken i = n + 3; 719 1.25 rumble if (cookies) 720 1.48 hannken *cookies++ = i; 721 1.25 rumble nc++; 722 1.25 rumble } 723 1.25 rumble 724 1.25 rumble out: 725 1.25 rumble /* not pertinent in error cases */ 726 1.25 rumble ncookies = nc; 727 1.1 jdolecek 728 1.1 jdolecek if (ap->a_ncookies) { 729 1.1 jdolecek if (error) { 730 1.1 jdolecek if (cookies) 731 1.1 jdolecek free(*ap->a_cookies, M_TEMP); 732 1.1 jdolecek *ap->a_ncookies = 0; 733 1.1 jdolecek *ap->a_cookies = NULL; 734 1.1 jdolecek } else 735 1.1 jdolecek *ap->a_ncookies = ncookies; 736 1.1 jdolecek } 737 1.1 jdolecek uio->uio_offset = i; 738 1.24 rumble free(dp, M_PTYFSTMP); 739 1.1 jdolecek return error; 740 1.1 jdolecek } 741 1.1 jdolecek 742 1.1 jdolecek int 743 1.1 jdolecek ptyfs_open(void *v) 744 1.1 jdolecek { 745 1.1 jdolecek struct vop_open_args /* { 746 1.1 jdolecek struct vnode *a_vp; 747 1.1 jdolecek int a_mode; 748 1.14 elad kauth_cred_t a_cred; 749 1.1 jdolecek } */ *ap = v; 750 1.1 jdolecek struct vnode *vp = ap->a_vp; 751 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 752 1.1 jdolecek 753 1.1 jdolecek switch (ptyfs->ptyfs_type) { 754 1.1 jdolecek case PTYFSpts: 755 1.1 jdolecek case PTYFSptc: 756 1.1 jdolecek return spec_open(v); 757 1.1 jdolecek case PTYFSroot: 758 1.1 jdolecek return 0; 759 1.1 jdolecek default: 760 1.1 jdolecek return EINVAL; 761 1.1 jdolecek } 762 1.1 jdolecek } 763 1.1 jdolecek 764 1.1 jdolecek int 765 1.1 jdolecek ptyfs_close(void *v) 766 1.1 jdolecek { 767 1.1 jdolecek struct vop_close_args /* { 768 1.1 jdolecek struct vnode *a_vp; 769 1.1 jdolecek int a_fflag; 770 1.14 elad kauth_cred_t a_cred; 771 1.1 jdolecek } */ *ap = v; 772 1.1 jdolecek struct vnode *vp = ap->a_vp; 773 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 774 1.7 perry 775 1.35 rmind mutex_enter(vp->v_interlock); 776 1.58 ad if (vrefcnt(vp) > 1) 777 1.9 christos PTYFS_ITIMES(ptyfs, NULL, NULL, NULL); 778 1.35 rmind mutex_exit(vp->v_interlock); 779 1.1 jdolecek 780 1.1 jdolecek switch (ptyfs->ptyfs_type) { 781 1.1 jdolecek case PTYFSpts: 782 1.1 jdolecek case PTYFSptc: 783 1.1 jdolecek return spec_close(v); 784 1.1 jdolecek case PTYFSroot: 785 1.1 jdolecek return 0; 786 1.1 jdolecek default: 787 1.1 jdolecek return EINVAL; 788 1.1 jdolecek } 789 1.1 jdolecek } 790 1.1 jdolecek 791 1.1 jdolecek int 792 1.1 jdolecek ptyfs_read(void *v) 793 1.1 jdolecek { 794 1.1 jdolecek struct vop_read_args /* { 795 1.1 jdolecek struct vnode *a_vp; 796 1.1 jdolecek struct uio *a_uio; 797 1.1 jdolecek int a_ioflag; 798 1.14 elad kauth_cred_t a_cred; 799 1.1 jdolecek } */ *ap = v; 800 1.10 simonb struct timespec ts; 801 1.1 jdolecek struct vnode *vp = ap->a_vp; 802 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 803 1.1 jdolecek int error; 804 1.1 jdolecek 805 1.38 njoly if (vp->v_type == VDIR) 806 1.38 njoly return EISDIR; 807 1.38 njoly 808 1.40 christos ptyfs->ptyfs_status |= PTYFS_ACCESS; 809 1.10 simonb /* hardclock() resolution is good enough for ptyfs */ 810 1.15 kardel getnanotime(&ts); 811 1.11 yamt (void)ptyfs_update(vp, &ts, &ts, 0); 812 1.10 simonb 813 1.1 jdolecek switch (ptyfs->ptyfs_type) { 814 1.1 jdolecek case PTYFSpts: 815 1.1 jdolecek case PTYFSptc: 816 1.34 hannken VOP_UNLOCK(vp); 817 1.23 ad error = cdev_read(vp->v_rdev, ap->a_uio, ap->a_ioflag); 818 1.1 jdolecek vn_lock(vp, LK_RETRY|LK_EXCLUSIVE); 819 1.1 jdolecek return error; 820 1.1 jdolecek default: 821 1.1 jdolecek return EOPNOTSUPP; 822 1.1 jdolecek } 823 1.1 jdolecek } 824 1.1 jdolecek 825 1.1 jdolecek int 826 1.1 jdolecek ptyfs_write(void *v) 827 1.1 jdolecek { 828 1.1 jdolecek struct vop_write_args /* { 829 1.1 jdolecek struct vnode *a_vp; 830 1.1 jdolecek struct uio *a_uio; 831 1.1 jdolecek int a_ioflag; 832 1.14 elad kauth_cred_t a_cred; 833 1.1 jdolecek } */ *ap = v; 834 1.10 simonb struct timespec ts; 835 1.1 jdolecek struct vnode *vp = ap->a_vp; 836 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 837 1.10 simonb int error; 838 1.1 jdolecek 839 1.40 christos ptyfs->ptyfs_status |= PTYFS_MODIFY; 840 1.15 kardel getnanotime(&ts); 841 1.11 yamt (void)ptyfs_update(vp, &ts, &ts, 0); 842 1.10 simonb 843 1.1 jdolecek switch (ptyfs->ptyfs_type) { 844 1.1 jdolecek case PTYFSpts: 845 1.1 jdolecek case PTYFSptc: 846 1.34 hannken VOP_UNLOCK(vp); 847 1.23 ad error = cdev_write(vp->v_rdev, ap->a_uio, ap->a_ioflag); 848 1.1 jdolecek vn_lock(vp, LK_RETRY|LK_EXCLUSIVE); 849 1.1 jdolecek return error; 850 1.1 jdolecek default: 851 1.1 jdolecek return EOPNOTSUPP; 852 1.1 jdolecek } 853 1.1 jdolecek } 854 1.1 jdolecek 855 1.1 jdolecek int 856 1.1 jdolecek ptyfs_ioctl(void *v) 857 1.1 jdolecek { 858 1.1 jdolecek struct vop_ioctl_args /* { 859 1.1 jdolecek struct vnode *a_vp; 860 1.1 jdolecek u_long a_command; 861 1.1 jdolecek void *a_data; 862 1.1 jdolecek int a_fflag; 863 1.14 elad kauth_cred_t a_cred; 864 1.1 jdolecek } */ *ap = v; 865 1.1 jdolecek struct vnode *vp = ap->a_vp; 866 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 867 1.1 jdolecek 868 1.1 jdolecek switch (ptyfs->ptyfs_type) { 869 1.1 jdolecek case PTYFSpts: 870 1.1 jdolecek case PTYFSptc: 871 1.23 ad return cdev_ioctl(vp->v_rdev, ap->a_command, 872 1.26 pooka ap->a_data, ap->a_fflag, curlwp); 873 1.1 jdolecek default: 874 1.1 jdolecek return EOPNOTSUPP; 875 1.1 jdolecek } 876 1.1 jdolecek } 877 1.1 jdolecek 878 1.1 jdolecek int 879 1.1 jdolecek ptyfs_poll(void *v) 880 1.1 jdolecek { 881 1.1 jdolecek struct vop_poll_args /* { 882 1.1 jdolecek struct vnode *a_vp; 883 1.1 jdolecek int a_events; 884 1.1 jdolecek } */ *ap = v; 885 1.1 jdolecek struct vnode *vp = ap->a_vp; 886 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 887 1.1 jdolecek 888 1.1 jdolecek switch (ptyfs->ptyfs_type) { 889 1.1 jdolecek case PTYFSpts: 890 1.1 jdolecek case PTYFSptc: 891 1.26 pooka return cdev_poll(vp->v_rdev, ap->a_events, curlwp); 892 1.1 jdolecek default: 893 1.1 jdolecek return genfs_poll(v); 894 1.1 jdolecek } 895 1.1 jdolecek } 896 1.1 jdolecek 897 1.1 jdolecek int 898 1.1 jdolecek ptyfs_kqfilter(void *v) 899 1.1 jdolecek { 900 1.1 jdolecek struct vop_kqfilter_args /* { 901 1.1 jdolecek struct vnode *a_vp; 902 1.1 jdolecek struct knote *a_kn; 903 1.1 jdolecek } */ *ap = v; 904 1.1 jdolecek struct vnode *vp = ap->a_vp; 905 1.1 jdolecek struct ptyfsnode *ptyfs = VTOPTYFS(vp); 906 1.1 jdolecek 907 1.1 jdolecek switch (ptyfs->ptyfs_type) { 908 1.1 jdolecek case PTYFSpts: 909 1.1 jdolecek case PTYFSptc: 910 1.23 ad return cdev_kqfilter(vp->v_rdev, ap->a_kn); 911 1.1 jdolecek default: 912 1.1 jdolecek return genfs_kqfilter(v); 913 1.1 jdolecek } 914 1.1 jdolecek } 915 1.1 jdolecek 916 1.11 yamt static int 917 1.11 yamt ptyfs_update(struct vnode *vp, const struct timespec *acc, 918 1.18 christos const struct timespec *mod, int flags) 919 1.1 jdolecek { 920 1.11 yamt struct ptyfsnode *ptyfs = VTOPTYFS(vp); 921 1.1 jdolecek 922 1.11 yamt if (vp->v_mount->mnt_flag & MNT_RDONLY) 923 1.1 jdolecek return 0; 924 1.1 jdolecek 925 1.11 yamt PTYFS_ITIMES(ptyfs, acc, mod, NULL); 926 1.1 jdolecek return 0; 927 1.1 jdolecek } 928 1.1 jdolecek 929 1.8 christos void 930 1.8 christos ptyfs_itimes(struct ptyfsnode *ptyfs, const struct timespec *acc, 931 1.8 christos const struct timespec *mod, const struct timespec *cre) 932 1.8 christos { 933 1.15 kardel struct timespec now; 934 1.15 kardel 935 1.40 christos KASSERT(ptyfs->ptyfs_status & (PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY)); 936 1.8 christos 937 1.15 kardel getnanotime(&now); 938 1.40 christos if (ptyfs->ptyfs_status & PTYFS_ACCESS) { 939 1.8 christos if (acc == NULL) 940 1.15 kardel acc = &now; 941 1.8 christos ptyfs->ptyfs_atime = *acc; 942 1.8 christos } 943 1.40 christos if (ptyfs->ptyfs_status & PTYFS_MODIFY) { 944 1.8 christos if (mod == NULL) 945 1.15 kardel mod = &now; 946 1.8 christos ptyfs->ptyfs_mtime = *mod; 947 1.8 christos } 948 1.40 christos if (ptyfs->ptyfs_status & PTYFS_CHANGE) { 949 1.8 christos if (cre == NULL) 950 1.15 kardel cre = &now; 951 1.9 christos ptyfs->ptyfs_ctime = *cre; 952 1.8 christos } 953 1.40 christos ptyfs->ptyfs_status &= ~(PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY); 954 1.1 jdolecek } 955 1.7 perry 956 1.1 jdolecek /* 957 1.1 jdolecek * convert decimal ascii to int 958 1.1 jdolecek */ 959 1.1 jdolecek static int 960 1.1 jdolecek atoi(const char *b, size_t len) 961 1.1 jdolecek { 962 1.1 jdolecek int p = 0; 963 1.1 jdolecek 964 1.1 jdolecek while (len--) { 965 1.1 jdolecek char c = *b++; 966 1.1 jdolecek if (c < '0' || c > '9') 967 1.1 jdolecek return -1; 968 1.1 jdolecek p = 10 * p + (c - '0'); 969 1.1 jdolecek } 970 1.1 jdolecek 971 1.1 jdolecek return p; 972 1.1 jdolecek } 973