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