Annotation of src/sys/fs/ptyfs/ptyfs_vnops.c, Revision 1.12.4.1
1.12.4.1! rpaulo 1: /* $NetBSD: ptyfs_vnops.c,v 1.16 2006/07/23 22:06:10 ad Exp $ */
1.1 jdolecek 2:
3: /*
4: * Copyright (c) 1993, 1995
5: * The Regents of the University of California. All rights reserved.
6: *
7: * This code is derived from software contributed 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: * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
35: */
36:
37: /*
38: * Copyright (c) 1993 Jan-Simon Pendry
39: *
40: * This code is derived from software contributed to Berkeley by
41: * Jan-Simon Pendry.
42: *
43: * Redistribution and use in source and binary forms, with or without
44: * modification, are permitted provided that the following conditions
45: * are met:
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.
58: *
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
69: * SUCH DAMAGE.
70: *
71: * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
72: */
73:
74: /*
75: * ptyfs vnode interface
76: */
77:
78: #include <sys/cdefs.h>
1.12.4.1! rpaulo 79: __KERNEL_RCSID(0, "$NetBSD: ptyfs_vnops.c,v 1.16 2006/07/23 22:06:10 ad Exp $");
1.1 jdolecek 80:
81: #include <sys/param.h>
82: #include <sys/systm.h>
83: #include <sys/time.h>
84: #include <sys/kernel.h>
85: #include <sys/file.h>
86: #include <sys/filedesc.h>
87: #include <sys/proc.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>
95: #include <sys/stat.h>
96: #include <sys/conf.h>
97: #include <sys/tty.h>
98: #include <sys/pty.h>
1.12.4.1! rpaulo 99: #include <sys/kauth.h>
1.1 jdolecek 100:
101: #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
102:
103: #include <machine/reg.h>
104:
1.2 jdolecek 105: #include <fs/ptyfs/ptyfs.h>
1.1 jdolecek 106: #include <miscfs/genfs/genfs.h>
107: #include <miscfs/specfs/specdev.h>
108:
109: /*
110: * Vnode Operations.
111: *
112: */
113:
114: int ptyfs_lookup (void *);
115: #define ptyfs_create genfs_eopnotsupp
116: #define ptyfs_mknod genfs_eopnotsupp
117: int ptyfs_open (void *);
118: int ptyfs_close (void *);
119: int ptyfs_access (void *);
120: int ptyfs_getattr (void *);
121: int ptyfs_setattr (void *);
122: int ptyfs_read (void *);
123: int ptyfs_write (void *);
124: #define ptyfs_fcntl genfs_fcntl
125: int ptyfs_ioctl (void *);
126: int ptyfs_poll (void *);
127: int ptyfs_kqfilter (void *);
128: #define ptyfs_revoke genfs_revoke
129: #define ptyfs_mmap genfs_eopnotsupp
130: #define ptyfs_fsync genfs_nullop
131: #define ptyfs_seek genfs_nullop
132: #define ptyfs_remove genfs_eopnotsupp
133: #define ptyfs_link genfs_abortop
134: #define ptyfs_rename genfs_eopnotsupp
135: #define ptyfs_mkdir genfs_eopnotsupp
136: #define ptyfs_rmdir genfs_eopnotsupp
137: #define ptyfs_symlink genfs_abortop
138: int ptyfs_readdir (void *);
139: #define ptyfs_readlink genfs_eopnotsupp
140: #define ptyfs_abortop genfs_abortop
141: int ptyfs_reclaim (void *);
142: #define ptyfs_lock genfs_lock
143: #define ptyfs_unlock genfs_unlock
144: #define ptyfs_bmap genfs_badop
145: #define ptyfs_strategy genfs_badop
146: int ptyfs_print (void *);
147: int ptyfs_pathconf (void *);
148: #define ptyfs_islocked genfs_islocked
149: #define ptyfs_advlock genfs_einval
150: #define ptyfs_bwrite genfs_eopnotsupp
151: #define ptyfs_putpages genfs_null_putpages
152:
1.11 yamt 153: static int ptyfs_update(struct vnode *, const struct timespec *,
154: const struct timespec *, int);
1.12.4.1! rpaulo 155: static int ptyfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
! 156: struct lwp *);
! 157: static int ptyfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
1.1 jdolecek 158: static int atoi(const char *, size_t);
159:
160: extern const struct cdevsw pts_cdevsw, ptc_cdevsw;
161:
162: /*
163: * ptyfs vnode operations.
164: */
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 */
1.6 christos 195: { &vop_inactive_desc, spec_inactive }, /* inactive */
1.1 jdolecek 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 */
207: { NULL, NULL }
208: };
209: const struct vnodeopv_desc ptyfs_vnodeop_opv_desc =
210: { &ptyfs_vnodeop_p, ptyfs_vnodeop_entries };
211:
212: /*
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.
218: */
219: int
220: ptyfs_reclaim(void *v)
221: {
222: struct vop_reclaim_args /* {
223: struct vnode *a_vp;
224: } */ *ap = v;
225: return ptyfs_freevp(ap->a_vp);
226: }
227:
228: /*
229: * Return POSIX pathconf information applicable to special devices.
230: */
231: int
232: ptyfs_pathconf(void *v)
233: {
234: struct vop_pathconf_args /* {
235: struct vnode *a_vp;
236: int a_name;
237: register_t *a_retval;
238: } */ *ap = v;
239:
240: switch (ap->a_name) {
241: case _PC_LINK_MAX:
242: *ap->a_retval = LINK_MAX;
243: return 0;
244: case _PC_MAX_CANON:
245: *ap->a_retval = MAX_CANON;
246: return 0;
247: case _PC_MAX_INPUT:
248: *ap->a_retval = MAX_INPUT;
249: return 0;
250: case _PC_PIPE_BUF:
251: *ap->a_retval = PIPE_BUF;
252: return 0;
253: case _PC_CHOWN_RESTRICTED:
254: *ap->a_retval = 1;
255: return 0;
256: case _PC_VDISABLE:
257: *ap->a_retval = _POSIX_VDISABLE;
258: return 0;
259: case _PC_SYNC_IO:
260: *ap->a_retval = 1;
261: return 0;
262: default:
263: return EINVAL;
264: }
265: }
266:
267: /*
268: * _print is used for debugging.
269: * just print a readable description
270: * of (vp).
271: */
272: int
273: ptyfs_print(void *v)
274: {
275: struct vop_print_args /* {
276: struct vnode *a_vp;
277: } */ *ap = v;
278: struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
279:
280: printf("tag VT_PTYFS, type %d, pty %d\n",
281: ptyfs->ptyfs_type, ptyfs->ptyfs_pty);
282: return 0;
283: }
284:
285: /*
286: * Invent attributes for ptyfsnode (vp) and store
287: * them in (vap).
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.
291: *
292: * this is relatively minimal for ptyfs.
293: */
294: int
295: ptyfs_getattr(void *v)
296: {
297: struct vop_getattr_args /* {
298: struct vnode *a_vp;
299: struct vattr *a_vap;
1.12.4.1! rpaulo 300: kauth_cred_t a_cred;
1.12 christos 301: struct lwp *a_l;
1.1 jdolecek 302: } */ *ap = v;
303: struct ptyfsnode *ptyfs = VTOPTYFS(ap->a_vp);
304: struct vattr *vap = ap->a_vap;
305:
1.9 christos 306: PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
1.1 jdolecek 307:
308: /* start by zeroing out the attributes */
309: VATTR_NULL(vap);
310:
311: /* next do all the common fields */
312: vap->va_type = ap->a_vp->v_type;
1.4 atatat 313: vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.1 jdolecek 314: vap->va_fileid = ptyfs->ptyfs_fileno;
315: vap->va_gen = 0;
316: vap->va_flags = 0;
317: vap->va_nlink = 1;
318: vap->va_blocksize = PAGE_SIZE;
319:
320: vap->va_atime = ptyfs->ptyfs_atime;
321: vap->va_mtime = ptyfs->ptyfs_mtime;
322: vap->va_ctime = ptyfs->ptyfs_ctime;
323: vap->va_birthtime = ptyfs->ptyfs_birthtime;
324: vap->va_mode = ptyfs->ptyfs_mode;
325: vap->va_flags = ptyfs->ptyfs_flags;
326: vap->va_uid = ptyfs->ptyfs_uid;
327: vap->va_gid = ptyfs->ptyfs_gid;
328:
329: switch (ptyfs->ptyfs_type) {
330: case PTYFSpts:
331: case PTYFSptc:
332: if (pty_isfree(ptyfs->ptyfs_pty, 1))
333: return ENOENT;
1.5 atatat 334: vap->va_bytes = vap->va_size = 0;
1.7 perry 335: vap->va_rdev = ap->a_vp->v_rdev;
1.1 jdolecek 336: break;
337: case PTYFSroot:
338: vap->va_rdev = 0;
339: vap->va_bytes = vap->va_size = DEV_BSIZE;
340: break;
341:
342: default:
343: return EOPNOTSUPP;
344: }
345:
346: return 0;
347: }
348:
349: /*ARGSUSED*/
350: int
351: ptyfs_setattr(void *v)
352: {
353: struct vop_setattr_args /* {
354: struct vnodeop_desc *a_desc;
355: struct vnode *a_vp;
356: struct vattr *a_vap;
1.12.4.1! rpaulo 357: kauth_cred_t a_cred;
1.12 christos 358: struct lwp *a_l;
1.1 jdolecek 359: } */ *ap = v;
360: struct vnode *vp = ap->a_vp;
361: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
362: struct vattr *vap = ap->a_vap;
1.12.4.1! rpaulo 363: kauth_cred_t cred = ap->a_cred;
1.12 christos 364: struct lwp *l = ap->a_l;
1.1 jdolecek 365: int error;
366:
367: if (vap->va_size != VNOVAL) {
368: switch (ptyfs->ptyfs_type) {
369: case PTYFSroot:
370: return EISDIR;
371: case PTYFSpts:
372: case PTYFSptc:
373: break;
374: default:
375: return EINVAL;
376: }
377: }
378:
379: if (vap->va_flags != VNOVAL) {
380: if (vp->v_mount->mnt_flag & MNT_RDONLY)
381: return EROFS;
1.12.4.1! rpaulo 382: if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
! 383: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
! 384: &l->l_acflag)) != 0)
1.1 jdolecek 385: return error;
1.12.4.1! rpaulo 386: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) {
1.1 jdolecek 387: if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) &&
388: securelevel > 0)
389: return EPERM;
390: /* Snapshot flag cannot be set or cleared */
1.7 perry 391: if ((vap->va_flags & SF_SNAPSHOT) !=
1.1 jdolecek 392: (ptyfs->ptyfs_flags & SF_SNAPSHOT))
393: return EPERM;
394: ptyfs->ptyfs_flags = vap->va_flags;
395: } else {
396: if ((ptyfs->ptyfs_flags & (SF_IMMUTABLE | SF_APPEND)) ||
397: (vap->va_flags & UF_SETTABLE) != vap->va_flags)
398: return EPERM;
399: if ((ptyfs->ptyfs_flags & SF_SETTABLE) !=
400: (vap->va_flags & SF_SETTABLE))
401: return EPERM;
402: ptyfs->ptyfs_flags &= SF_SETTABLE;
403: ptyfs->ptyfs_flags |= (vap->va_flags & UF_SETTABLE);
404: }
405: ptyfs->ptyfs_flag |= PTYFS_CHANGE;
406: if (vap->va_flags & (IMMUTABLE | APPEND))
407: return 0;
408: }
409: if (ptyfs->ptyfs_flags & (IMMUTABLE | APPEND))
410: return EPERM;
411: /*
412: * Go through the fields and update iff not VNOVAL.
413: */
414: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
415: if (vp->v_mount->mnt_flag & MNT_RDONLY)
416: return EROFS;
417: if (ptyfs->ptyfs_type == PTYFSroot)
418: return EPERM;
1.12.4.1! rpaulo 419: error = ptyfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1 jdolecek 420: if (error)
421: return error;
422: }
423:
424: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
425: vap->va_birthtime.tv_sec != VNOVAL) {
426: if (vp->v_mount->mnt_flag & MNT_RDONLY)
427: return EROFS;
428: if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0)
429: return EPERM;
1.12.4.1! rpaulo 430: if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
! 431: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
! 432: &l->l_acflag)) &&
1.7 perry 433: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
1.12 christos 434: (error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0))
1.1 jdolecek 435: return (error);
436: if (vap->va_atime.tv_sec != VNOVAL)
437: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
438: ptyfs->ptyfs_flag |= PTYFS_ACCESS;
439: if (vap->va_mtime.tv_sec != VNOVAL)
440: ptyfs->ptyfs_flag |= PTYFS_CHANGE | PTYFS_MODIFY;
441: if (vap->va_birthtime.tv_sec != VNOVAL)
442: ptyfs->ptyfs_birthtime = vap->va_birthtime;
443: ptyfs->ptyfs_flag |= PTYFS_CHANGE;
1.11 yamt 444: error = ptyfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
1.1 jdolecek 445: if (error)
446: return error;
447: }
448: if (vap->va_mode != (mode_t)VNOVAL) {
449: if (vp->v_mount->mnt_flag & MNT_RDONLY)
450: return EROFS;
451: if (ptyfs->ptyfs_type == PTYFSroot)
452: return EPERM;
453: if ((ptyfs->ptyfs_flags & SF_SNAPSHOT) != 0 &&
454: (vap->va_mode &
455: (S_IXUSR|S_IWUSR|S_IXGRP|S_IWGRP|S_IXOTH|S_IWOTH)))
456: return EPERM;
1.12.4.1! rpaulo 457: error = ptyfs_chmod(vp, vap->va_mode, cred, l);
1.1 jdolecek 458: if (error)
459: return error;
460: }
461: VN_KNOTE(vp, NOTE_ATTRIB);
462: return 0;
463: }
464:
465: /*
466: * Change the mode on a file.
467: * Inode must be locked before calling.
468: */
469: static int
1.12.4.1! rpaulo 470: ptyfs_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred, struct lwp *l)
1.1 jdolecek 471: {
472: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
473: int error;
474:
1.12.4.1! rpaulo 475: if (kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid &&
! 476: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
! 477: &l->l_acflag)) != 0)
1.1 jdolecek 478: return error;
479: ptyfs->ptyfs_mode &= ~ALLPERMS;
480: ptyfs->ptyfs_mode |= (mode & ALLPERMS);
481: return 0;
482: }
483:
484: /*
485: * Perform chown operation on inode ip;
486: * inode must be locked prior to call.
487: */
488: static int
1.12.4.1! rpaulo 489: ptyfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
! 490: struct lwp *l)
1.1 jdolecek 491: {
492: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.12.4.1! rpaulo 493: int error, ismember = 0;
1.1 jdolecek 494:
495: if (uid == (uid_t)VNOVAL)
496: uid = ptyfs->ptyfs_uid;
497: if (gid == (gid_t)VNOVAL)
498: gid = ptyfs->ptyfs_gid;
499: /*
500: * If we don't own the file, are trying to change the owner
501: * of the file, or are not a member of the target group,
502: * the caller's credentials must imply super-user privilege
503: * or the call fails.
504: */
1.12.4.1! rpaulo 505: if ((kauth_cred_geteuid(cred) != ptyfs->ptyfs_uid || uid != ptyfs->ptyfs_uid ||
1.1 jdolecek 506: (gid != ptyfs->ptyfs_gid &&
1.12.4.1! rpaulo 507: !(kauth_cred_getegid(cred) == gid ||
! 508: (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 && ismember)))) &&
! 509: ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
! 510: &l->l_acflag)) != 0))
1.1 jdolecek 511: return error;
512:
513: ptyfs->ptyfs_gid = gid;
514: ptyfs->ptyfs_uid = uid;
515: return 0;
516: }
517:
518: /*
519: * implement access checking.
520: *
521: * actually, the check for super-user is slightly
522: * broken since it will allow read access to write-only
523: * objects. this doesn't cause any particular trouble
524: * but does mean that the i/o entry points need to check
525: * that the operation really does make sense.
526: */
527: int
528: ptyfs_access(void *v)
529: {
530: struct vop_access_args /* {
531: struct vnode *a_vp;
532: int a_mode;
1.12.4.1! rpaulo 533: kauth_cred_t a_cred;
1.12 christos 534: struct lwp *a_l;
1.1 jdolecek 535: } */ *ap = v;
536: struct vattr va;
537: int error;
538:
1.12 christos 539: if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_l)) != 0)
1.1 jdolecek 540: return error;
541:
542: return vaccess(va.va_type, va.va_mode,
543: va.va_uid, va.va_gid, ap->a_mode, ap->a_cred);
544: }
545:
546: /*
547: * lookup. this is incredibly complicated in the
548: * general case, however for most pseudo-filesystems
549: * very little needs to be done.
550: *
551: * Locking isn't hard here, just poorly documented.
552: *
1.7 perry 553: * If we're looking up ".", just vref the parent & return it.
1.1 jdolecek 554: *
555: * If we're looking up "..", unlock the parent, and lock "..". If everything
556: * went ok, and we're on the last component and the caller requested the
557: * parent locked, try to re-lock the parent. We do this to prevent lock
558: * races.
559: *
560: * For anything else, get the needed node. Then unlock the parent if not
561: * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the
562: * parent in the .. case).
563: *
564: * We try to exit with the parent locked in error cases.
565: */
566: int
567: ptyfs_lookup(void *v)
568: {
569: struct vop_lookup_args /* {
570: struct vnode * a_dvp;
571: struct vnode ** a_vpp;
572: struct componentname * a_cnp;
573: } */ *ap = v;
574: struct componentname *cnp = ap->a_cnp;
575: struct vnode **vpp = ap->a_vpp;
576: struct vnode *dvp = ap->a_dvp;
577: const char *pname = cnp->cn_nameptr;
578: struct ptyfsnode *ptyfs;
579: int pty, error, wantpunlock;
580:
581: *vpp = NULL;
582: cnp->cn_flags &= ~PDIRUNLOCK;
583:
584: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
585: return EROFS;
586:
587: if (cnp->cn_namelen == 1 && *pname == '.') {
588: *vpp = dvp;
589: VREF(dvp);
590: return 0;
591: }
592:
593: wantpunlock = ~cnp->cn_flags & (LOCKPARENT | ISLASTCN);
594: ptyfs = VTOPTYFS(dvp);
595: switch (ptyfs->ptyfs_type) {
596: case PTYFSroot:
597: /*
598: * Shouldn't get here with .. in the root node.
599: */
1.7 perry 600: if (cnp->cn_flags & ISDOTDOT)
1.1 jdolecek 601: return EIO;
602:
603: pty = atoi(pname, cnp->cn_namelen);
604:
605: if (pty < 0 || pty >= npty || pty_isfree(pty, 1))
606: break;
607:
608: error = ptyfs_allocvp(dvp->v_mount, vpp, PTYFSpts, pty,
1.12 christos 609: curlwp);
1.1 jdolecek 610: if (error == 0 && wantpunlock) {
611: VOP_UNLOCK(dvp, 0);
612: cnp->cn_flags |= PDIRUNLOCK;
613: }
614: return error;
615:
616: default:
617: return ENOTDIR;
618: }
619:
620: return cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS;
621: }
622:
623: /*
624: * readdir returns directory entries from ptyfsnode (vp).
625: *
626: * the strategy here with ptyfs is to generate a single
627: * directory entry at a time (struct dirent) and then
628: * copy that out to userland using uiomove. a more efficent
629: * though more complex implementation, would try to minimize
630: * the number of calls to uiomove(). for ptyfs, this is
631: * hardly worth the added code complexity.
632: *
633: * this should just be done through read()
634: */
635: int
636: ptyfs_readdir(void *v)
637: {
638: struct vop_readdir_args /* {
639: struct vnode *a_vp;
640: struct uio *a_uio;
1.12.4.1! rpaulo 641: kauth_cred_t a_cred;
1.1 jdolecek 642: int *a_eofflag;
643: off_t **a_cookies;
644: int *a_ncookies;
645: } */ *ap = v;
646: struct uio *uio = ap->a_uio;
647: struct dirent d;
648: struct ptyfsnode *ptyfs;
649: off_t i;
650: int error;
651: off_t *cookies = NULL;
652: int ncookies;
653: struct vnode *vp;
654: int nc = 0;
655:
656: vp = ap->a_vp;
657: ptyfs = VTOPTYFS(vp);
658:
659: if (uio->uio_resid < UIO_MX)
660: return EINVAL;
661: if (uio->uio_offset < 0)
662: return EINVAL;
663:
664: error = 0;
665: i = uio->uio_offset;
666: (void)memset(&d, 0, sizeof(d));
667: d.d_reclen = UIO_MX;
668: ncookies = uio->uio_resid / UIO_MX;
669:
670: switch (ptyfs->ptyfs_type) {
671: case PTYFSroot: /* root */
672:
673: if (i >= npty)
674: return 0;
675:
676: if (ap->a_ncookies) {
677: ncookies = min(ncookies, (npty + 2 - i));
678: cookies = malloc(ncookies * sizeof (off_t),
679: M_TEMP, M_WAITOK);
680: *ap->a_cookies = cookies;
681: }
682:
683: for (; i < 2; i++) {
684: switch (i) {
685: case 0: /* `.' */
686: case 1: /* `..' */
687: d.d_fileno = PTYFS_FILENO(0, PTYFSroot);
688: d.d_namlen = i + 1;
689: (void)memcpy(d.d_name, "..", d.d_namlen);
690: d.d_name[i + 1] = '\0';
691: d.d_type = DT_DIR;
692: break;
693: }
694: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
695: break;
696: if (cookies)
697: *cookies++ = i + 1;
698: nc++;
699: }
700: if (error) {
701: ncookies = nc;
702: break;
703: }
704: for (; uio->uio_resid >= UIO_MX && i < npty; i++) {
705: /* check for used ptys */
706: if (pty_isfree(i - 2, 1))
707: continue;
708:
709: d.d_fileno = PTYFS_FILENO(i - 2, PTYFSpts);
710: d.d_namlen = snprintf(d.d_name, sizeof(d.d_name),
711: "%lld", (long long)(i - 2));
712: d.d_type = DT_CHR;
713: if ((error = uiomove(&d, UIO_MX, uio)) != 0)
714: break;
715: if (cookies)
716: *cookies++ = i + 1;
717: nc++;
718: }
719: ncookies = nc;
720: break;
721:
722: default:
723: error = ENOTDIR;
724: break;
725: }
726:
727: if (ap->a_ncookies) {
728: if (error) {
729: if (cookies)
730: free(*ap->a_cookies, M_TEMP);
731: *ap->a_ncookies = 0;
732: *ap->a_cookies = NULL;
733: } else
734: *ap->a_ncookies = ncookies;
735: }
736: uio->uio_offset = i;
737: return error;
738: }
739:
740: int
741: ptyfs_open(void *v)
742: {
743: struct vop_open_args /* {
744: struct vnode *a_vp;
745: int a_mode;
1.12.4.1! rpaulo 746: kauth_cred_t a_cred;
1.12 christos 747: struct lwp *a_l;
1.1 jdolecek 748: } */ *ap = v;
749: struct vnode *vp = ap->a_vp;
750: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
751:
752: ptyfs->ptyfs_flag |= PTYFS_CHANGE|PTYFS_ACCESS;
753: switch (ptyfs->ptyfs_type) {
754: case PTYFSpts:
755: case PTYFSptc:
756: return spec_open(v);
757: case PTYFSroot:
758: return 0;
759: default:
760: return EINVAL;
761: }
762: }
763:
764: int
765: ptyfs_close(void *v)
766: {
767: struct vop_close_args /* {
768: struct vnode *a_vp;
769: int a_fflag;
1.12.4.1! rpaulo 770: kauth_cred_t a_cred;
1.12 christos 771: struct lwp *a_l;
1.1 jdolecek 772: } */ *ap = v;
773: struct vnode *vp = ap->a_vp;
774: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.7 perry 775:
1.12.4.1! rpaulo 776: simple_lock(&vp->v_interlock);
! 777: if (vp->v_usecount > 1)
1.9 christos 778: PTYFS_ITIMES(ptyfs, NULL, NULL, NULL);
1.12.4.1! rpaulo 779: simple_unlock(&vp->v_interlock);
1.1 jdolecek 780:
781: switch (ptyfs->ptyfs_type) {
782: case PTYFSpts:
783: case PTYFSptc:
784: return spec_close(v);
785: case PTYFSroot:
786: return 0;
787: default:
788: return EINVAL;
789: }
790: }
791:
792: int
793: ptyfs_read(void *v)
794: {
795: struct vop_read_args /* {
796: struct vnode *a_vp;
797: struct uio *a_uio;
798: int a_ioflag;
1.12.4.1! rpaulo 799: kauth_cred_t a_cred;
1.1 jdolecek 800: } */ *ap = v;
1.10 simonb 801: struct timespec ts;
1.1 jdolecek 802: struct vnode *vp = ap->a_vp;
803: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
804: int error;
805:
806: ptyfs->ptyfs_flag |= PTYFS_ACCESS;
1.10 simonb 807: /* hardclock() resolution is good enough for ptyfs */
1.12.4.1! rpaulo 808: getnanotime(&ts);
1.11 yamt 809: (void)ptyfs_update(vp, &ts, &ts, 0);
1.10 simonb 810:
1.1 jdolecek 811: switch (ptyfs->ptyfs_type) {
812: case PTYFSpts:
813: VOP_UNLOCK(vp, 0);
814: error = (*pts_cdevsw.d_read)(vp->v_rdev, ap->a_uio,
815: ap->a_ioflag);
816: vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
817: return error;
818: case PTYFSptc:
819: VOP_UNLOCK(vp, 0);
820: error = (*ptc_cdevsw.d_read)(vp->v_rdev, ap->a_uio,
821: ap->a_ioflag);
822: vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
823: return error;
824: default:
825: return EOPNOTSUPP;
826: }
827: }
828:
829: int
830: ptyfs_write(void *v)
831: {
832: struct vop_write_args /* {
833: struct vnode *a_vp;
834: struct uio *a_uio;
835: int a_ioflag;
1.12.4.1! rpaulo 836: kauth_cred_t a_cred;
1.1 jdolecek 837: } */ *ap = v;
1.10 simonb 838: struct timespec ts;
1.1 jdolecek 839: struct vnode *vp = ap->a_vp;
840: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.10 simonb 841: int error;
1.1 jdolecek 842:
843: ptyfs->ptyfs_flag |= PTYFS_MODIFY;
1.12.4.1! rpaulo 844: getnanotime(&ts);
1.11 yamt 845: (void)ptyfs_update(vp, &ts, &ts, 0);
1.10 simonb 846:
1.1 jdolecek 847: switch (ptyfs->ptyfs_type) {
848: case PTYFSpts:
849: VOP_UNLOCK(vp, 0);
850: error = (*pts_cdevsw.d_write)(vp->v_rdev, ap->a_uio,
851: ap->a_ioflag);
852: vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
853: return error;
854: case PTYFSptc:
855: VOP_UNLOCK(vp, 0);
856: error = (*ptc_cdevsw.d_write)(vp->v_rdev, ap->a_uio,
857: ap->a_ioflag);
858: vn_lock(vp, LK_RETRY|LK_EXCLUSIVE);
859: return error;
860: default:
861: return EOPNOTSUPP;
862: }
863: }
864:
865: int
866: ptyfs_ioctl(void *v)
867: {
868: struct vop_ioctl_args /* {
869: struct vnode *a_vp;
870: u_long a_command;
871: void *a_data;
872: int a_fflag;
1.12.4.1! rpaulo 873: kauth_cred_t a_cred;
1.12 christos 874: struct lwp *a_l;
1.1 jdolecek 875: } */ *ap = v;
876: struct vnode *vp = ap->a_vp;
877: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
878:
879: switch (ptyfs->ptyfs_type) {
880: case PTYFSpts:
881: return (*pts_cdevsw.d_ioctl)(vp->v_rdev, ap->a_command,
1.12 christos 882: ap->a_data, ap->a_fflag, ap->a_l);
1.1 jdolecek 883: case PTYFSptc:
884: return (*ptc_cdevsw.d_ioctl)(vp->v_rdev, ap->a_command,
1.12 christos 885: ap->a_data, ap->a_fflag, ap->a_l);
1.1 jdolecek 886: default:
887: return EOPNOTSUPP;
888: }
889: }
890:
891: int
892: ptyfs_poll(void *v)
893: {
894: struct vop_poll_args /* {
895: struct vnode *a_vp;
896: int a_events;
1.12 christos 897: struct lwp *a_l;
1.1 jdolecek 898: } */ *ap = v;
899: struct vnode *vp = ap->a_vp;
900: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
901:
902: switch (ptyfs->ptyfs_type) {
903: case PTYFSpts:
1.12 christos 904: return (*pts_cdevsw.d_poll)(vp->v_rdev, ap->a_events, ap->a_l);
1.1 jdolecek 905: case PTYFSptc:
1.12 christos 906: return (*ptc_cdevsw.d_poll)(vp->v_rdev, ap->a_events, ap->a_l);
1.1 jdolecek 907: default:
908: return genfs_poll(v);
909: }
910: }
911:
912: int
913: ptyfs_kqfilter(void *v)
914: {
915: struct vop_kqfilter_args /* {
916: struct vnode *a_vp;
917: struct knote *a_kn;
918: } */ *ap = v;
919: struct vnode *vp = ap->a_vp;
920: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
921:
922: switch (ptyfs->ptyfs_type) {
923: case PTYFSpts:
924: return (*pts_cdevsw.d_kqfilter)(vp->v_rdev, ap->a_kn);
925: case PTYFSptc:
926: return (*ptc_cdevsw.d_kqfilter)(vp->v_rdev, ap->a_kn);
927: default:
928: return genfs_kqfilter(v);
929: }
930: }
931:
1.11 yamt 932: static int
933: ptyfs_update(struct vnode *vp, const struct timespec *acc,
934: const struct timespec *mod, int flags)
1.1 jdolecek 935: {
1.11 yamt 936: struct ptyfsnode *ptyfs = VTOPTYFS(vp);
1.1 jdolecek 937:
1.11 yamt 938: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1.1 jdolecek 939: return 0;
940:
1.11 yamt 941: PTYFS_ITIMES(ptyfs, acc, mod, NULL);
1.1 jdolecek 942: return 0;
943: }
944:
1.8 christos 945: void
946: ptyfs_itimes(struct ptyfsnode *ptyfs, const struct timespec *acc,
947: const struct timespec *mod, const struct timespec *cre)
948: {
1.12.4.1! rpaulo 949: struct timespec now;
! 950:
1.9 christos 951: KASSERT(ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY));
1.12.4.1! rpaulo 952:
! 953: getnanotime(&now);
1.8 christos 954: if (ptyfs->ptyfs_flag & (PTYFS_ACCESS|PTYFS_MODIFY)) {
955: if (acc == NULL)
1.12.4.1! rpaulo 956: acc = &now;
1.8 christos 957: ptyfs->ptyfs_atime = *acc;
958: }
1.1 jdolecek 959: if (ptyfs->ptyfs_flag & PTYFS_MODIFY) {
1.8 christos 960: if (mod == NULL)
1.12.4.1! rpaulo 961: mod = &now;
1.8 christos 962: ptyfs->ptyfs_mtime = *mod;
963: }
964: if (ptyfs->ptyfs_flag & PTYFS_CHANGE) {
965: if (cre == NULL)
1.12.4.1! rpaulo 966: cre = &now;
1.9 christos 967: ptyfs->ptyfs_ctime = *cre;
1.8 christos 968: }
1.9 christos 969: ptyfs->ptyfs_flag &= ~(PTYFS_ACCESS|PTYFS_CHANGE|PTYFS_MODIFY);
1.1 jdolecek 970: }
1.7 perry 971:
1.1 jdolecek 972: /*
973: * convert decimal ascii to int
974: */
975: static int
976: atoi(const char *b, size_t len)
977: {
978: int p = 0;
979:
980: while (len--) {
981: char c = *b++;
982: if (c < '0' || c > '9')
983: return -1;
984: p = 10 * p + (c - '0');
985: }
986:
987: return p;
988: }
CVSweb <webmaster@jp.NetBSD.org>