Annotation of sys/miscfs/portal/portal_vnops.c, Revision 1.1.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