Annotation of sys/miscfs/portal/portal_vnops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: portal_vnops.c,v 1.24 2007/06/18 08:30:07 jasper Exp $ */
! 2: /* $NetBSD: portal_vnops.c,v 1.17 1996/02/13 13:12:57 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1992, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * This code is derived from software donated to Berkeley by
! 9: * Jan-Simon Pendry.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * from: Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp
! 36: * @(#)portal_vnops.c 8.8 (Berkeley) 1/21/94
! 37: */
! 38:
! 39: /*
! 40: * Portal Filesystem
! 41: */
! 42:
! 43: #include <sys/param.h>
! 44: #include <sys/systm.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/types.h>
! 47: #include <sys/time.h>
! 48: #include <sys/proc.h>
! 49: #include <sys/filedesc.h>
! 50: #include <sys/vnode.h>
! 51: #include <sys/file.h>
! 52: #include <sys/stat.h>
! 53: #include <sys/mount.h>
! 54: #include <sys/malloc.h>
! 55: #include <sys/namei.h>
! 56: #include <sys/mbuf.h>
! 57: #include <sys/poll.h>
! 58: #include <sys/socket.h>
! 59: #include <sys/socketvar.h>
! 60: #include <sys/un.h>
! 61: #include <sys/unpcb.h>
! 62: #include <sys/syscallargs.h>
! 63: #include <miscfs/portal/portal.h>
! 64:
! 65: static int portal_fileid = PORTAL_ROOTFILEID+1;
! 66:
! 67: static void portal_closefd(struct proc *, int);
! 68: static int portal_connect(struct socket *, struct socket *);
! 69:
! 70:
! 71: int portal_badop(void *);
! 72:
! 73: int portal_lookup(void *);
! 74: #define portal_create eopnotsupp
! 75: #define portal_mknod eopnotsupp
! 76: int portal_open(void *);
! 77: #define portal_close nullop
! 78: #define portal_access nullop
! 79: int portal_getattr(void *);
! 80: int portal_setattr(void *);
! 81: #define portal_read eopnotsupp
! 82: #define portal_write eopnotsupp
! 83: #define portal_ioctl (int (*)(void *))enoioctl
! 84: #define portal_fsync nullop
! 85: #define portal_remove eopnotsupp
! 86: int portal_link(void *);
! 87: #define portal_rename eopnotsupp
! 88: #define portal_mkdir eopnotsupp
! 89: #define portal_rmdir eopnotsupp
! 90: int portal_symlink(void *);
! 91: int portal_readdir(void *);
! 92: #define portal_revoke vop_generic_revoke
! 93: #define portal_readlink eopnotsupp
! 94: int portal_inactive(void *);
! 95: int portal_reclaim(void *);
! 96: #define portal_lock vop_generic_lock
! 97: #define portal_unlock vop_generic_unlock
! 98: #define portal_bmap portal_badop
! 99: #define portal_strategy portal_badop
! 100: int portal_print(void *);
! 101: #define portal_islocked vop_generic_islocked
! 102: int portal_pathconf(void *);
! 103: #define portal_advlock eopnotsupp
! 104: #define portal_bwrite eopnotsupp
! 105: int portal_poll(void *);
! 106:
! 107: int (**portal_vnodeop_p)(void *);
! 108: struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
! 109: { &vop_default_desc, vn_default_error },
! 110: { &vop_lookup_desc, portal_lookup }, /* lookup */
! 111: { &vop_create_desc, portal_create }, /* create */
! 112: { &vop_mknod_desc, portal_mknod }, /* mknod */
! 113: { &vop_open_desc, portal_open }, /* open */
! 114: { &vop_close_desc, portal_close }, /* close */
! 115: { &vop_access_desc, portal_access }, /* access */
! 116: { &vop_getattr_desc, portal_getattr }, /* getattr */
! 117: { &vop_setattr_desc, portal_setattr }, /* setattr */
! 118: { &vop_read_desc, portal_read }, /* read */
! 119: { &vop_write_desc, portal_write }, /* write */
! 120: { &vop_ioctl_desc, portal_ioctl }, /* ioctl */
! 121: { &vop_poll_desc, portal_poll }, /* poll */
! 122: { &vop_revoke_desc, portal_revoke }, /* revoke */
! 123: { &vop_fsync_desc, portal_fsync }, /* fsync */
! 124: { &vop_remove_desc, portal_remove }, /* remove */
! 125: { &vop_link_desc, portal_link }, /* link */
! 126: { &vop_rename_desc, portal_rename }, /* rename */
! 127: { &vop_mkdir_desc, portal_mkdir }, /* mkdir */
! 128: { &vop_rmdir_desc, portal_rmdir }, /* rmdir */
! 129: { &vop_symlink_desc, portal_symlink }, /* symlink */
! 130: { &vop_readdir_desc, portal_readdir }, /* readdir */
! 131: { &vop_readlink_desc, portal_readlink }, /* readlink */
! 132: { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
! 133: { &vop_inactive_desc, portal_inactive }, /* inactive */
! 134: { &vop_reclaim_desc, portal_reclaim }, /* reclaim */
! 135: { &vop_lock_desc, portal_lock }, /* lock */
! 136: { &vop_unlock_desc, portal_unlock }, /* unlock */
! 137: { &vop_bmap_desc, portal_bmap }, /* bmap */
! 138: { &vop_strategy_desc, portal_strategy }, /* strategy */
! 139: { &vop_print_desc, portal_print }, /* print */
! 140: { &vop_islocked_desc, portal_islocked }, /* islocked */
! 141: { &vop_pathconf_desc, portal_pathconf }, /* pathconf */
! 142: { &vop_advlock_desc, portal_advlock }, /* advlock */
! 143: { &vop_bwrite_desc, portal_bwrite }, /* bwrite */
! 144: { NULL, NULL }
! 145: };
! 146: struct vnodeopv_desc portal_vnodeop_opv_desc =
! 147: { &portal_vnodeop_p, portal_vnodeop_entries };
! 148:
! 149: static void
! 150: portal_closefd(struct proc *p, int fd)
! 151: {
! 152: struct sys_close_args /* {
! 153: syscallarg(int) fd;
! 154: } */ ua;
! 155: register_t retval[2];
! 156: int error;
! 157:
! 158: SCARG(&ua, fd) = fd;
! 159: error = sys_close(p, &ua, retval);
! 160: /*
! 161: * We should never get an error, and there isn't anything
! 162: * we could do if we got one, so just print a message.
! 163: */
! 164: if (error)
! 165: printf("portal_closefd: error = %d\n", error);
! 166: }
! 167:
! 168: /*
! 169: * vp is the current namei directory
! 170: * cnp is the name to locate in that directory...
! 171: */
! 172: int
! 173: portal_lookup(void *v)
! 174: {
! 175: struct vop_lookup_args *ap = v;
! 176: struct componentname *cnp = ap->a_cnp;
! 177: struct vnode **vpp = ap->a_vpp;
! 178: struct vnode *dvp = ap->a_dvp;
! 179: char *pname = cnp->cn_nameptr;
! 180: struct proc *p = cnp->cn_proc;
! 181: struct portalnode *pt;
! 182: int error;
! 183: struct vnode *fvp = 0;
! 184: char *path;
! 185: int size;
! 186:
! 187: *vpp = NULLVP;
! 188:
! 189: if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
! 190: return (EROFS);
! 191:
! 192: if (cnp->cn_namelen == 1 && *pname == '.') {
! 193: *vpp = dvp;
! 194: VREF(dvp);
! 195: return (0);
! 196: }
! 197:
! 198: error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp);
! 199: if (error)
! 200: goto bad;
! 201: fvp->v_type = VREG;
! 202: MALLOC(fvp->v_data, void *, sizeof(struct portalnode), M_TEMP,
! 203: M_WAITOK);
! 204:
! 205: pt = VTOPORTAL(fvp);
! 206: /*
! 207: * Save all of the remaining pathname and
! 208: * advance the namei next pointer to the end
! 209: * of the string.
! 210: */
! 211: for (size = 0, path = pname; *path; path++)
! 212: size++;
! 213: cnp->cn_consume = size - cnp->cn_namelen;
! 214:
! 215: pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
! 216: pt->pt_size = size+1;
! 217: bcopy(pname, pt->pt_arg, pt->pt_size);
! 218: pt->pt_fileid = portal_fileid++;
! 219:
! 220: *vpp = fvp;
! 221: VOP_LOCK(fvp, LK_EXCLUSIVE, p);
! 222: /*
! 223: * As we are the last component of the path name, fix up
! 224: * the locking on the directory node.
! 225: */
! 226: if ((cnp->cn_flags & LOCKPARENT) == 0) {
! 227: VOP_UNLOCK(dvp, 0, p);
! 228: cnp->cn_flags |= PDIRUNLOCK;
! 229: }
! 230: return (0);
! 231:
! 232: bad:;
! 233: if (fvp)
! 234: vrele(fvp);
! 235: return (error);
! 236: }
! 237:
! 238: static int
! 239: portal_connect(struct socket *so, struct socket *so2)
! 240: {
! 241: /* from unp_connect, bypassing the namei stuff... */
! 242: struct socket *so3;
! 243: struct unpcb *unp2;
! 244: struct unpcb *unp3;
! 245:
! 246: if (so2 == 0)
! 247: return (ECONNREFUSED);
! 248:
! 249: if (so->so_type != so2->so_type)
! 250: return (EPROTOTYPE);
! 251:
! 252: if ((so2->so_options & SO_ACCEPTCONN) == 0)
! 253: return (ECONNREFUSED);
! 254:
! 255: if ((so3 = sonewconn(so2, 0)) == 0)
! 256: return (ECONNREFUSED);
! 257:
! 258: unp2 = sotounpcb(so2);
! 259: unp3 = sotounpcb(so3);
! 260: if (unp2->unp_addr)
! 261: unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
! 262:
! 263: so2 = so3;
! 264:
! 265:
! 266: return (unp_connect2(so, so2));
! 267: }
! 268:
! 269: int
! 270: portal_open(void *v)
! 271: {
! 272: struct vop_open_args *ap = v;
! 273: struct socket *so = 0;
! 274: struct portalnode *pt;
! 275: struct proc *p = ap->a_p;
! 276: struct vnode *vp = ap->a_vp;
! 277: int s;
! 278: struct uio auio;
! 279: struct iovec aiov[2];
! 280: int res;
! 281: struct mbuf *cm = 0;
! 282: struct cmsghdr *cmsg;
! 283: int newfds;
! 284: int *ip;
! 285: int fd;
! 286: int error;
! 287: int len;
! 288: struct portalmount *fmp;
! 289: struct file *fp;
! 290: struct portal_cred pcred;
! 291:
! 292: /*
! 293: * Nothing to do when opening the root node.
! 294: */
! 295: if (vp->v_flag & VROOT)
! 296: return (0);
! 297:
! 298: /*
! 299: * Can't be opened unless the caller is set up
! 300: * to deal with the side effects. Check for this
! 301: * by testing whether the p_dupfd has been set.
! 302: */
! 303: if (p->p_dupfd >= 0)
! 304: return (ENODEV);
! 305:
! 306: pt = VTOPORTAL(vp);
! 307: fmp = VFSTOPORTAL(vp->v_mount);
! 308:
! 309: /*
! 310: * Create a new socket.
! 311: */
! 312: error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);
! 313: if (error)
! 314: goto bad;
! 315:
! 316: /*
! 317: * Reserve some buffer space
! 318: */
! 319: res = pt->pt_size + sizeof(pcred) + 512; /* XXX */
! 320: error = soreserve(so, res, res);
! 321: if (error)
! 322: goto bad;
! 323:
! 324: /*
! 325: * Kick off connection
! 326: */
! 327: s = splsoftnet();
! 328: error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
! 329: splx(s);
! 330: if (error)
! 331: goto bad;
! 332:
! 333: /*
! 334: * Wait for connection to complete
! 335: */
! 336: /*
! 337: * XXX: Since the mount point is holding a reference on the
! 338: * underlying server socket, it is not easy to find out whether
! 339: * the server process is still running. To handle this problem
! 340: * we loop waiting for the new socket to be connected (something
! 341: * which will only happen if the server is still running) or for
! 342: * the reference count on the server socket to drop to 1, which
! 343: * will happen if the server dies. Sleep for 5 second intervals
! 344: * and keep polling the reference count. XXX.
! 345: */
! 346: s = splsoftnet();
! 347: while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
! 348: if (fmp->pm_server->f_count == 1) {
! 349: error = ECONNREFUSED;
! 350: splx(s);
! 351: goto bad;
! 352: }
! 353: (void) tsleep(&so->so_timeo, PSOCK, "portalcon", 5 * hz);
! 354: }
! 355: splx(s);
! 356:
! 357: if (so->so_error) {
! 358: error = so->so_error;
! 359: goto bad;
! 360: }
! 361:
! 362: /*
! 363: * Set miscellaneous flags
! 364: */
! 365: so->so_rcv.sb_timeo = 0;
! 366: so->so_snd.sb_timeo = 0;
! 367: so->so_rcv.sb_flags |= SB_NOINTR;
! 368: so->so_snd.sb_flags |= SB_NOINTR;
! 369:
! 370:
! 371: pcred.pcr_flag = ap->a_mode;
! 372: pcred.pcr_uid = ap->a_cred->cr_uid;
! 373: pcred.pcr_gid = ap->a_cred->cr_gid;
! 374: pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
! 375: bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
! 376: aiov[0].iov_base = &pcred;
! 377: aiov[0].iov_len = sizeof(pcred);
! 378: aiov[1].iov_base = pt->pt_arg;
! 379: aiov[1].iov_len = pt->pt_size;
! 380: auio.uio_iov = aiov;
! 381: auio.uio_iovcnt = 2;
! 382: auio.uio_rw = UIO_WRITE;
! 383: auio.uio_segflg = UIO_SYSSPACE;
! 384: auio.uio_procp = p;
! 385: auio.uio_offset = 0;
! 386: auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
! 387:
! 388: error = sosend(so, (struct mbuf *) 0, &auio,
! 389: (struct mbuf *) 0, (struct mbuf *) 0, 0);
! 390: if (error)
! 391: goto bad;
! 392:
! 393: len = auio.uio_resid = sizeof(int);
! 394: do {
! 395: struct mbuf *m = 0;
! 396: int flags = MSG_WAITALL;
! 397: fdpunlock(p->p_fd);
! 398: error = soreceive(so, (struct mbuf **) 0, &auio,
! 399: &m, &cm, &flags);
! 400: fdplock(p->p_fd);
! 401: if (error)
! 402: goto bad;
! 403:
! 404: /*
! 405: * Grab an error code from the mbuf.
! 406: */
! 407: if (m) {
! 408: m = m_pullup(m, sizeof(int)); /* Needed? */
! 409: if (m) {
! 410: error = *(mtod(m, int *));
! 411: m_freem(m);
! 412: } else {
! 413: error = EINVAL;
! 414: }
! 415: } else {
! 416: if (cm == 0) {
! 417: error = ECONNRESET; /* XXX */
! 418: #ifdef notdef
! 419: break;
! 420: #endif
! 421: }
! 422: }
! 423: } while (cm == 0 && auio.uio_resid == len && !error);
! 424:
! 425: if (cm == 0)
! 426: goto bad;
! 427:
! 428: if (auio.uio_resid) {
! 429: error = 0;
! 430: #ifdef notdef
! 431: error = EMSGSIZE;
! 432: goto bad;
! 433: #endif
! 434: }
! 435:
! 436: /*
! 437: * XXX: Break apart the control message, and retrieve the
! 438: * received file descriptor. Note that more than one descriptor
! 439: * may have been received, or that the rights chain may have more
! 440: * than a single mbuf in it. What to do?
! 441: */
! 442: cmsg = mtod(cm, struct cmsghdr *);
! 443: newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
! 444: if (newfds == 0) {
! 445: error = ECONNREFUSED;
! 446: goto bad;
! 447: }
! 448: /*
! 449: * At this point the rights message consists of a control message
! 450: * header, followed by a data region containing a vector of
! 451: * integer file descriptors. The fds were allocated by the action
! 452: * of receiving the control message.
! 453: */
! 454: ip = (int *)(cmsg + 1);
! 455: fd = *ip++;
! 456: if (newfds > 1) {
! 457: /*
! 458: * Close extra fds.
! 459: */
! 460: int i;
! 461: printf("portal_open: %d extra fds\n", newfds - 1);
! 462: for (i = 1; i < newfds; i++) {
! 463: portal_closefd(p, *ip);
! 464: ip++;
! 465: }
! 466: }
! 467:
! 468: /*
! 469: * Check that the mode the file is being opened for is a subset
! 470: * of the mode of the existing descriptor.
! 471: */
! 472: if ((fp = fd_getfile(p->p_fd, fd)) == NULL) {
! 473: error = EBADF;
! 474: goto bad;
! 475: }
! 476: if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
! 477: portal_closefd(p, fd);
! 478: error = EACCES;
! 479: goto bad;
! 480: }
! 481:
! 482: /*
! 483: * Save the dup fd in the proc structure then return the
! 484: * special error code (ENXIO) which causes magic things to
! 485: * happen in vn_open. The whole concept is, well, hmmm.
! 486: */
! 487: p->p_dupfd = fd;
! 488: error = ENXIO;
! 489:
! 490: bad:;
! 491: /*
! 492: * And discard the control message.
! 493: */
! 494: if (cm) {
! 495: m_freem(cm);
! 496: }
! 497:
! 498: if (so) {
! 499: soshutdown(so, 2);
! 500: soclose(so);
! 501: }
! 502: return (error);
! 503: }
! 504:
! 505: int
! 506: portal_getattr(void *v)
! 507: {
! 508: struct vop_getattr_args *ap = v;
! 509: struct vnode *vp = ap->a_vp;
! 510: struct vattr *vap = ap->a_vap;
! 511:
! 512: bzero(vap, sizeof(*vap));
! 513: vattr_null(vap);
! 514: vap->va_uid = 0;
! 515: vap->va_gid = 0;
! 516: vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
! 517: vap->va_size = DEV_BSIZE;
! 518: vap->va_blocksize = DEV_BSIZE;
! 519: getnanotime(&vap->va_atime);
! 520: vap->va_mtime = vap->va_atime;
! 521: vap->va_ctime = vap->va_atime;
! 522: vap->va_gen = 0;
! 523: vap->va_flags = 0;
! 524: vap->va_rdev = 0;
! 525: /* vap->va_qbytes = 0; */
! 526: vap->va_bytes = 0;
! 527: /* vap->va_qsize = 0; */
! 528: if (vp->v_flag & VROOT) {
! 529: vap->va_type = VDIR;
! 530: vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
! 531: S_IRGRP|S_IWGRP|S_IXGRP|
! 532: S_IROTH|S_IWOTH|S_IXOTH;
! 533: vap->va_nlink = 2;
! 534: vap->va_fileid = 2;
! 535: } else {
! 536: vap->va_type = VREG;
! 537: vap->va_mode = S_IRUSR|S_IWUSR|
! 538: S_IRGRP|S_IWGRP|
! 539: S_IROTH|S_IWOTH;
! 540: vap->va_nlink = 1;
! 541: vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
! 542: }
! 543: return (0);
! 544: }
! 545:
! 546: int
! 547: portal_setattr(void *v)
! 548: {
! 549: struct vop_setattr_args *ap = v;
! 550:
! 551: /*
! 552: * Can't mess with the root vnode
! 553: */
! 554: if (ap->a_vp->v_flag & VROOT)
! 555: return (EACCES);
! 556:
! 557: if (ap->a_vap->va_flags != VNOVAL)
! 558: return (EOPNOTSUPP);
! 559:
! 560: return (0);
! 561: }
! 562:
! 563: /*
! 564: * Fake readdir, just return empty directory.
! 565: * It is hard to deal with '.' and '..' so don't bother.
! 566: */
! 567: /*ARGSUSED*/
! 568: int
! 569: portal_readdir(void *v)
! 570: {
! 571: return (0);
! 572: }
! 573:
! 574: /*ARGSUSED*/
! 575: int
! 576: portal_inactive(void *v)
! 577: {
! 578: struct vop_inactive_args *ap = v;
! 579:
! 580: VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
! 581: return (0);
! 582: }
! 583:
! 584: int
! 585: portal_reclaim(void *v)
! 586: {
! 587: struct vop_reclaim_args *ap = v;
! 588: struct portalnode *pt = VTOPORTAL(ap->a_vp);
! 589:
! 590: if (pt->pt_arg) {
! 591: free(pt->pt_arg, M_TEMP);
! 592: pt->pt_arg = 0;
! 593: }
! 594: FREE(ap->a_vp->v_data, M_TEMP);
! 595: ap->a_vp->v_data = 0;
! 596:
! 597: return (0);
! 598: }
! 599:
! 600: /*
! 601: * Return POSIX pathconf information applicable to special devices.
! 602: */
! 603: int
! 604: portal_pathconf(void *v)
! 605: {
! 606: struct vop_pathconf_args *ap = v;
! 607:
! 608: switch (ap->a_name) {
! 609: case _PC_LINK_MAX:
! 610: *ap->a_retval = LINK_MAX;
! 611: return (0);
! 612: case _PC_MAX_CANON:
! 613: *ap->a_retval = MAX_CANON;
! 614: return (0);
! 615: case _PC_MAX_INPUT:
! 616: *ap->a_retval = MAX_INPUT;
! 617: return (0);
! 618: case _PC_PIPE_BUF:
! 619: *ap->a_retval = PIPE_BUF;
! 620: return (0);
! 621: case _PC_CHOWN_RESTRICTED:
! 622: *ap->a_retval = 1;
! 623: return (0);
! 624: case _PC_VDISABLE:
! 625: *ap->a_retval = _POSIX_VDISABLE;
! 626: return (0);
! 627: default:
! 628: return (EINVAL);
! 629: }
! 630: /* NOTREACHED */
! 631: }
! 632:
! 633: /*
! 634: * Print out the contents of a Portal vnode.
! 635: */
! 636: /* ARGSUSED */
! 637: int
! 638: portal_print(void *v)
! 639: {
! 640: printf("tag VT_PORTAL, portal vnode\n");
! 641: return (0);
! 642: }
! 643:
! 644: int
! 645: portal_link(void *v)
! 646: {
! 647: struct vop_link_args *ap = v;
! 648:
! 649: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
! 650: vput(ap->a_dvp);
! 651: return (EROFS);
! 652: }
! 653:
! 654: int
! 655: portal_symlink(void *v)
! 656: {
! 657: struct vop_symlink_args *ap = v;
! 658:
! 659: VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
! 660: vput(ap->a_dvp);
! 661: return (EROFS);
! 662: }
! 663:
! 664: int
! 665: portal_badop(void *v)
! 666: {
! 667: panic ("portal: bad op");
! 668: return (0);
! 669: }
! 670:
! 671: int
! 672: portal_poll(void *v)
! 673: {
! 674: struct vop_poll_args *ap = v;
! 675:
! 676: return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
! 677: }
CVSweb