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