Annotation of sys/xfs/xfs_syscalls-common.c, Revision 1.1
1.1 ! nbrk 1: /*
! 2: * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan
! 3: * (Royal Institute of Technology, Stockholm, Sweden).
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: *
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: *
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * 3. Neither the name of the Institute nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: */
! 33:
! 34: #include <xfs/xfs_locl.h>
! 35:
! 36: RCSID("$arla: xfs_syscalls-common.c,v 1.72 2003/01/19 20:53:49 lha Exp $");
! 37:
! 38: /*
! 39: * NNPFS system calls.
! 40: */
! 41:
! 42: #include <xfs/xfs_syscalls.h>
! 43: #include <xfs/xfs_message.h>
! 44: #include <xfs/xfs_fs.h>
! 45: #include <xfs/xfs_dev.h>
! 46: #include <xfs/xfs_node.h>
! 47: #include <xfs/xfs_vfsops.h>
! 48: #include <xfs/xfs_deb.h>
! 49:
! 50: /* Misc syscalls */
! 51: #ifdef HAVE_SYS_IOCCOM_H
! 52: #include <sys/ioccom.h>
! 53: #elif defined(HAVE_SYS_IOCTL_H)
! 54: #include <sys/ioctl.h>
! 55: #endif
! 56: /*
! 57: * XXX - horrible kludge. If we are openbsd and not building an lkm,
! 58: * then use their headerfile.
! 59: */
! 60: #if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(_LKM)
! 61: #define NNPFS_NOT_LKM 1
! 62: #elif defined(__FreeBSD__) && !defined(KLD_MODULE)
! 63: #define NNPFS_NOT_LKM 1
! 64: #endif
! 65:
! 66: #ifdef NNPFS_NOT_LKM
! 67: #include <xfs/xfs_pioctl.h>
! 68: #else
! 69: #include <kafs.h>
! 70: #endif
! 71:
! 72: int (*old_setgroups_func)(syscall_d_thread_t *p, void *v, register_t *retval);
! 73:
! 74: #if defined(__FreeBSD__) && __FreeBSD_version >= 500026
! 75: /*
! 76: * XXX This is wrong
! 77: */
! 78: static struct ucred *
! 79: xfs_crcopy(struct ucred *cr)
! 80: {
! 81: struct ucred *ncr;
! 82:
! 83: if (crshared(cr)) {
! 84: ncr = crdup(cr);
! 85: crfree(cr);
! 86: return ncr;
! 87: }
! 88: return cr;
! 89: }
! 90: #else
! 91: #define xfs_crcopy crcopy
! 92: #endif
! 93:
! 94:
! 95: /*
! 96: * the syscall entry point
! 97: */
! 98:
! 99: #ifdef NNPFS_NOT_LKM
! 100: int
! 101: sys_xfspioctl(syscall_d_thread_t *proc, void *varg, register_t *return_value)
! 102: #else
! 103: int
! 104: xfspioctl(syscall_d_thread_t *proc, void *varg, register_t *return_value)
! 105: #endif
! 106: {
! 107: #ifdef NNPFS_NOT_LKM
! 108: struct sys_xfspioctl_args *arg = (struct sys_xfspioctl_args *) varg;
! 109: #else
! 110: struct sys_pioctl_args *arg = (struct sys_pioctl_args *) varg;
! 111: #endif
! 112: int error = EINVAL;
! 113:
! 114: switch (SCARG(arg, operation)) {
! 115: case AFSCALL_PIOCTL:
! 116: error = xfs_pioctl_call(syscall_thread_to_thread(proc),
! 117: varg, return_value);
! 118: break;
! 119: case AFSCALL_SETPAG:
! 120: #ifdef HAVE_FREEBSD_THREAD
! 121: error = xfs_setpag_call(&xfs_thread_to_cred(proc));
! 122: #else
! 123: error = xfs_setpag_call(&xfs_proc_to_cred(syscall_thread_to_thread(proc)));
! 124: #endif
! 125: break;
! 126: default:
! 127: NNPFSDEB(XDEBSYS, ("Unimplemeted xfspioctl: %d\n",
! 128: SCARG(arg, operation)));
! 129: error = EINVAL;
! 130: break;
! 131: }
! 132:
! 133: return error;
! 134: }
! 135:
! 136: /*
! 137: * Def pag:
! 138: * 33536 <= g0 <= 34560
! 139: * 32512 <= g1 <= 48896
! 140: */
! 141:
! 142: #define NNPFS_PAG1_LLIM 33536
! 143: #define NNPFS_PAG1_ULIM 34560
! 144: #define NNPFS_PAG2_LLIM 32512
! 145: #define NNPFS_PAG2_ULIM 48896
! 146:
! 147: static gid_t pag_part_one = NNPFS_PAG1_LLIM;
! 148: static gid_t pag_part_two = NNPFS_PAG2_LLIM;
! 149:
! 150: /*
! 151: * Is `cred' member of a PAG?
! 152: */
! 153:
! 154: static int
! 155: xfs_is_pag(struct ucred *cred)
! 156: {
! 157: /* The first group is the gid of the user ? */
! 158:
! 159: if (cred->cr_ngroups >= 3 &&
! 160: cred->cr_groups[1] >= NNPFS_PAG1_LLIM &&
! 161: cred->cr_groups[1] <= NNPFS_PAG1_ULIM &&
! 162: cred->cr_groups[2] >= NNPFS_PAG2_LLIM &&
! 163: cred->cr_groups[2] <= NNPFS_PAG2_ULIM)
! 164: return 1;
! 165: else
! 166: return 0;
! 167: }
! 168:
! 169: /*
! 170: * Return the pag used by `cred'
! 171: */
! 172:
! 173: xfs_pag_t
! 174: xfs_get_pag(struct ucred *cred)
! 175: {
! 176: if (xfs_is_pag(cred)) {
! 177:
! 178: return (((cred->cr_groups[1] << 16) & 0xFFFF0000) |
! 179: ((cred->cr_groups[2] & 0x0000FFFF)));
! 180:
! 181: } else
! 182: return cred->cr_uid; /* XXX */
! 183: }
! 184:
! 185: /*
! 186: * Set the pag in `ret_cred' and return a new cred.
! 187: */
! 188:
! 189: static int
! 190: store_pag (struct ucred **ret_cred, gid_t part1, gid_t part2)
! 191: {
! 192: struct ucred *cred = *ret_cred;
! 193:
! 194: if (!xfs_is_pag (cred)) {
! 195: int i;
! 196:
! 197: if (cred->cr_ngroups + 2 >= NGROUPS)
! 198: return E2BIG;
! 199:
! 200: cred = xfs_crcopy (cred);
! 201:
! 202: for (i = cred->cr_ngroups - 1; i > 0; i--) {
! 203: cred->cr_groups[i + 2] = cred->cr_groups[i];
! 204: }
! 205: cred->cr_ngroups += 2;
! 206: } else {
! 207: cred = xfs_crcopy (cred);
! 208: }
! 209: cred->cr_groups[1] = part1;
! 210: cred->cr_groups[2] = part2;
! 211: *ret_cred = cred;
! 212:
! 213: return 0;
! 214: }
! 215:
! 216: /*
! 217: * Acquire a new pag in `ret_cred'
! 218: */
! 219:
! 220: int
! 221: xfs_setpag_call(struct ucred **ret_cred)
! 222: {
! 223: int ret;
! 224:
! 225: ret = store_pag (ret_cred, pag_part_one, pag_part_two++);
! 226: if (ret)
! 227: return ret;
! 228:
! 229: if (pag_part_two > NNPFS_PAG2_ULIM) {
! 230: pag_part_one++;
! 231: pag_part_two = NNPFS_PAG2_LLIM;
! 232: }
! 233: return 0;
! 234: }
! 235:
! 236: #ifndef NNPFS_NOT_LKM
! 237: /*
! 238: * remove a pag
! 239: */
! 240:
! 241: static int
! 242: xfs_unpag (struct ucred *cred)
! 243: {
! 244: while (xfs_is_pag (cred)) {
! 245: int i;
! 246:
! 247: for (i = 0; i < cred->cr_ngroups - 2; ++i)
! 248: cred->cr_groups[i] = cred->cr_groups[i+2];
! 249: cred->cr_ngroups -= 2;
! 250: }
! 251: return 0;
! 252: }
! 253:
! 254: /*
! 255: * A wrapper around setgroups that preserves the pag.
! 256: */
! 257:
! 258: int
! 259: xfs_setgroups (syscall_d_thread_t *p,
! 260: void *varg,
! 261: register_t *retval)
! 262: {
! 263: struct xfs_setgroups_args *uap = (struct xfs_setgroups_args *)varg;
! 264: #ifdef HAVE_FREEBSD_THREAD
! 265: struct ucred **cred = &xfs_thread_to_cred(p);
! 266: #else
! 267: struct ucred **cred = &xfs_proc_to_cred(syscall_thread_to_thread(p));
! 268: #endif
! 269:
! 270: if (xfs_is_pag (*cred)) {
! 271: gid_t part1, part2;
! 272: int ret;
! 273:
! 274: if (SCARG(uap,gidsetsize) + 2 > NGROUPS)
! 275: return EINVAL;
! 276:
! 277: part1 = (*cred)->cr_groups[1];
! 278: part2 = (*cred)->cr_groups[2];
! 279: ret = (*old_setgroups_func) (p, uap, retval);
! 280: if (ret)
! 281: return ret;
! 282: return store_pag (cred, part1, part2);
! 283: } else {
! 284: int ret;
! 285:
! 286: ret = (*old_setgroups_func) (p, uap, retval);
! 287: /* don't support setting a PAG */
! 288: if (xfs_is_pag (*cred)) {
! 289: xfs_unpag (*cred);
! 290: return EINVAL;
! 291: }
! 292: return ret;
! 293: }
! 294: }
! 295: #endif /* !NNPFS_NOT_LKM */
! 296:
! 297: /*
! 298: * Return the vnode corresponding to `pathptr'
! 299: */
! 300:
! 301: static int
! 302: lookup_node (const char *pathptr,
! 303: int follow_links_p,
! 304: struct vnode **res,
! 305: d_thread_t *proc)
! 306: {
! 307: int error;
! 308: char path[MAXPATHLEN];
! 309: #ifdef __osf__
! 310: struct nameidata *ndp = &u.u_nd;
! 311: #else
! 312: struct nameidata nd, *ndp = &nd;
! 313: #endif
! 314: struct vnode *vp;
! 315: size_t count;
! 316:
! 317: NNPFSDEB(XDEBSYS, ("xfs_syscall: looking up: %lx\n",
! 318: (unsigned long)pathptr));
! 319:
! 320: error = copyinstr((char *) pathptr, path, MAXPATHLEN, &count);
! 321:
! 322: NNPFSDEB(XDEBSYS, ("xfs_syscall: looking up: %s, error: %d\n", path, error));
! 323:
! 324: if (error)
! 325: return error;
! 326:
! 327: NDINIT(ndp, LOOKUP,
! 328: follow_links_p ? FOLLOW : 0,
! 329: UIO_SYSSPACE, path, proc);
! 330:
! 331: error = namei(ndp);
! 332:
! 333: if (error != 0) {
! 334: NNPFSDEB(XDEBSYS, ("xfs_syscall: error during namei: %d\n", error));
! 335: return EINVAL;
! 336: }
! 337:
! 338: vp = ndp->ni_vp;
! 339:
! 340: *res = vp;
! 341: return 0;
! 342: }
! 343:
! 344: /*
! 345: * implement xfs fhget in a way that should be compatible with the native
! 346: * getfh
! 347: */
! 348:
! 349: static int
! 350: getfh_compat (d_thread_t *p,
! 351: struct ViceIoctl *vice_ioctl,
! 352: struct vnode *vp)
! 353: {
! 354: /* This is to be same as getfh */
! 355: fhandle_t fh;
! 356: int error;
! 357:
! 358: bzero((caddr_t)&fh, sizeof(fh));
! 359: fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
! 360: #if __osf__
! 361: VFS_VPTOFH(vp, &fh.fh_fid, error);
! 362: #else
! 363: error = VFS_VPTOFH(vp, &fh.fh_fid);
! 364: #endif
! 365: if (error)
! 366: return error;
! 367:
! 368: if (vice_ioctl->out_size < sizeof(fh))
! 369: return EINVAL;
! 370:
! 371: return copyout((caddr_t)&fh, vice_ioctl->out, sizeof (fh));
! 372: }
! 373:
! 374: /*
! 375: * implement xfs fhget by combining (dev, ino, generation)
! 376: */
! 377:
! 378: #ifndef __OpenBSD__
! 379: static int
! 380: trad_fhget (d_thread_t *p,
! 381: struct ViceIoctl *vice_ioctl,
! 382: struct vnode *vp)
! 383: {
! 384: int error;
! 385: struct mount *mnt;
! 386: struct vattr vattr;
! 387: size_t len;
! 388: struct xfs_fhandle_t xfs_handle;
! 389: struct xfs_fh_args fh_args;
! 390:
! 391: #ifdef HAVE_FREEBSD_THREAD
! 392: xfs_vop_getattr(vp, &vattr, xfs_thread_to_cred(p), p, error);
! 393: #else
! 394: xfs_vop_getattr(vp, &vattr, xfs_proc_to_cred(p), p, error);
! 395: #endif
! 396: if (error)
! 397: return error;
! 398:
! 399: mnt = vp->v_mount;
! 400:
! 401: SCARG(&fh_args, fsid) = mnt->mnt_stat.f_fsid;
! 402: SCARG(&fh_args, fileid) = vattr.va_fileid;
! 403: SCARG(&fh_args, gen) = vattr.va_gen;
! 404:
! 405: xfs_handle.len = sizeof(fh_args);
! 406: memcpy (xfs_handle.fhdata, &fh_args, sizeof(fh_args));
! 407: len = sizeof(xfs_handle);
! 408:
! 409: if (vice_ioctl->out_size < len)
! 410: return EINVAL;
! 411:
! 412: error = copyout (&xfs_handle, vice_ioctl->out, len);
! 413: if (error) {
! 414: NNPFSDEB(XDEBSYS, ("fhget_call: copyout failed: %d\n", error));
! 415: }
! 416: return error;
! 417: }
! 418: #endif /* ! __OpenBSD__ */
! 419:
! 420: /*
! 421: * return file handle of `vp' in vice_ioctl->out
! 422: * vp is vrele:d
! 423: */
! 424:
! 425: static int
! 426: fhget_call (d_thread_t *p,
! 427: struct ViceIoctl *vice_ioctl,
! 428: struct vnode *vp)
! 429: {
! 430: int error;
! 431:
! 432: NNPFSDEB(XDEBSYS, ("fhget_call\n"));
! 433:
! 434: if (vp == NULL)
! 435: return EBADF;
! 436:
! 437: #if defined(__APPLE__) || defined(__osf__)
! 438: error = EINVAL; /* XXX: Leaks vnodes if fhget/fhopen is used */
! 439: goto out;
! 440: #endif
! 441:
! 442: error = xfs_suser (p);
! 443: if (error)
! 444: goto out;
! 445:
! 446: #if (defined(HAVE_GETFH) && defined(HAVE_FHOPEN)) || defined(__osf__)
! 447: error = getfh_compat (p, vice_ioctl, vp);
! 448: #else
! 449: error = trad_fhget (p, vice_ioctl, vp);
! 450: #endif /* HAVE_GETFH && HAVE_FHOPEN */
! 451: out:
! 452: vrele(vp);
! 453: return error;
! 454: }
! 455:
! 456: /*
! 457: * open the file specified in `vice_ioctl->in'
! 458: */
! 459:
! 460: static int
! 461: fhopen_call (d_thread_t *p,
! 462: struct ViceIoctl *vice_ioctl,
! 463: struct vnode *vp,
! 464: int flags,
! 465: register_t *retval)
! 466: {
! 467:
! 468: NNPFSDEB(XDEBSYS, ("fhopen_call: flags = %d\n", flags));
! 469:
! 470: if (vp != NULL) {
! 471: vrele (vp);
! 472: return EINVAL;
! 473: }
! 474:
! 475: #if defined(__APPLE__) || defined(__osf__)
! 476: return EINVAL; /* XXX: Leaks vnodes if fhget/fhopen is used */
! 477: #endif
! 478:
! 479: return xfs_fhopen (p,
! 480: (struct xfs_fhandle_t *)vice_ioctl->in,
! 481: flags,
! 482: retval);
! 483: }
! 484:
! 485: /*
! 486: * Send the pioctl to arlad
! 487: */
! 488:
! 489: static int
! 490: remote_pioctl (d_thread_t *p,
! 491: struct sys_pioctl_args *arg,
! 492: struct ViceIoctl *vice_ioctl,
! 493: struct vnode *vp)
! 494: {
! 495: int error = 0;
! 496: struct xfs_message_pioctl *msg = NULL;
! 497: struct xfs_message_wakeup_data *msg2;
! 498:
! 499: msg = malloc(sizeof(struct xfs_message_symlink), M_TEMP, M_WAITOK);
! 500: if (msg == NULL) {
! 501: error = ENOMEM;
! 502: goto done;
! 503: }
! 504: memset(msg, 0, sizeof(*msg));
! 505:
! 506: if (vp != NULL) {
! 507: struct xfs_node *xn;
! 508:
! 509: if (vp->v_tag != VT_XFS) {
! 510: NNPFSDEB(XDEBSYS, ("xfs_syscall: file is not in afs\n"));
! 511: vrele(vp);
! 512: error = EINVAL;
! 513: goto done;
! 514: }
! 515:
! 516: xn = VNODE_TO_XNODE(vp);
! 517:
! 518: msg->handle = xn->handle;
! 519: vrele(vp);
! 520: }
! 521:
! 522: if (vice_ioctl->in_size < 0) {
! 523: printf("xfs: remote pioctl: got a negative data size: opcode: %d",
! 524: SCARG(arg, a_opcode));
! 525: error = EINVAL;
! 526: goto done;
! 527: }
! 528:
! 529: if (vice_ioctl->in_size > NNPFS_MSG_MAX_DATASIZE) {
! 530: printf("xfs_pioctl_call: got a humongous in packet: opcode: %d",
! 531: SCARG(arg, a_opcode));
! 532: error = EINVAL;
! 533: goto done;
! 534: }
! 535: if (vice_ioctl->in_size != 0) {
! 536: error = copyin(vice_ioctl->in, msg->msg, vice_ioctl->in_size);
! 537: if (error)
! 538: goto done;
! 539: }
! 540:
! 541: msg->header.opcode = NNPFS_MSG_PIOCTL;
! 542: msg->header.size = sizeof(*msg);
! 543: msg->opcode = SCARG(arg, a_opcode);
! 544:
! 545: msg->insize = vice_ioctl->in_size;
! 546: msg->outsize = vice_ioctl->out_size;
! 547: #ifdef HAVE_FREEBSD_THREAD
! 548: msg->cred.uid = xfs_thread_to_euid(p);
! 549: msg->cred.pag = xfs_get_pag(xfs_thread_to_cred(p));
! 550: #else
! 551: msg->cred.uid = xfs_proc_to_euid(p);
! 552: msg->cred.pag = xfs_get_pag(xfs_proc_to_cred(p));
! 553: #endif
! 554:
! 555: error = xfs_message_rpc(0, &(msg->header), sizeof(*msg), p); /* XXX */
! 556: msg2 = (struct xfs_message_wakeup_data *) msg;
! 557:
! 558: if (error == 0)
! 559: error = msg2->error;
! 560: if (error == ENODEV)
! 561: error = EINVAL;
! 562:
! 563: if (error == 0 && msg2->header.opcode == NNPFS_MSG_WAKEUP_DATA) {
! 564: int len;
! 565:
! 566: len = msg2->len;
! 567: if (len > vice_ioctl->out_size)
! 568: len = vice_ioctl->out_size;
! 569: if (len > NNPFS_MSG_MAX_DATASIZE)
! 570: len = NNPFS_MSG_MAX_DATASIZE;
! 571: if (len < 0)
! 572: len = 0;
! 573:
! 574: error = copyout(msg2->msg, vice_ioctl->out, len);
! 575: }
! 576: done:
! 577: free(msg, M_TEMP);
! 578: return error;
! 579: }
! 580:
! 581: static int
! 582: xfs_debug (d_thread_t *p,
! 583: struct ViceIoctl *vice_ioctl)
! 584: {
! 585: int32_t flags;
! 586: int error;
! 587:
! 588: if (vice_ioctl->in_size != 0) {
! 589: if (vice_ioctl->in_size < sizeof(int32_t))
! 590: return EINVAL;
! 591:
! 592: error = xfs_suser (p);
! 593: if (error)
! 594: return error;
! 595:
! 596: error = copyin (vice_ioctl->in,
! 597: &flags,
! 598: sizeof(flags));
! 599: if (error)
! 600: return error;
! 601:
! 602: xfsdeb = flags;
! 603: }
! 604:
! 605: if (vice_ioctl->out_size != 0) {
! 606: if (vice_ioctl->out_size < sizeof(int32_t))
! 607: return EINVAL;
! 608:
! 609: error = copyout (&xfsdeb,
! 610: vice_ioctl->out,
! 611: sizeof(int32_t));
! 612: if (error)
! 613: return error;
! 614: }
! 615:
! 616: return 0;
! 617: }
! 618:
! 619:
! 620: /*
! 621: * Handle `pioctl'
! 622: */
! 623:
! 624: int
! 625: xfs_pioctl_call(d_thread_t *proc,
! 626: struct sys_pioctl_args *arg,
! 627: register_t *return_value)
! 628: {
! 629: int error;
! 630: struct ViceIoctl vice_ioctl;
! 631: char *pathptr;
! 632: struct vnode *vp = NULL;
! 633:
! 634: NNPFSDEB(XDEBSYS, ("xfs_syscall(%d, %lx, %d, %lx, %d)\n",
! 635: SCARG(arg, operation),
! 636: (unsigned long)SCARG(arg, a_pathP),
! 637: SCARG(arg, a_opcode),
! 638: (unsigned long)SCARG(arg, a_paramsP),
! 639: SCARG(arg, a_followSymlinks)));
! 640:
! 641: /* Copy in the data structure for us */
! 642:
! 643: error = copyin(SCARG(arg, a_paramsP),
! 644: &vice_ioctl,
! 645: sizeof(vice_ioctl));
! 646:
! 647: if (error)
! 648: return error;
! 649:
! 650: pathptr = SCARG(arg, a_pathP);
! 651:
! 652: if (pathptr != NULL) {
! 653: error = lookup_node (pathptr, SCARG(arg, a_followSymlinks), &vp,
! 654: proc);
! 655: if(error)
! 656: return error;
! 657: }
! 658:
! 659: switch (SCARG(arg, a_opcode)) {
! 660: case VIOC_FHGET :
! 661: return fhget_call (proc, &vice_ioctl, vp);
! 662: case VIOC_FHOPEN :
! 663: return fhopen_call (proc, &vice_ioctl, vp,
! 664: SCARG(arg, a_followSymlinks), return_value);
! 665: case VIOC_XFSDEBUG :
! 666: if (vp != NULL)
! 667: vrele (vp);
! 668: return xfs_debug (proc, &vice_ioctl);
! 669: default :
! 670: NNPFSDEB(XDEBSYS, ("a_opcode = %x\n", SCARG(arg, a_opcode)));
! 671: return remote_pioctl (proc, arg, &vice_ioctl, vp);
! 672: }
! 673: }
CVSweb