root/xfs/xfs_syscalls-common.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xfs_crcopy
  2. sys_xfspioctl
  3. xfs_is_pag
  4. xfs_get_pag
  5. store_pag
  6. xfs_setpag_call
  7. xfs_unpag
  8. xfs_setgroups
  9. lookup_node
  10. getfh_compat
  11. trad_fhget
  12. fhget_call
  13. fhopen_call
  14. remote_pioctl
  15. xfs_debug
  16. xfs_pioctl_call

    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 }

/* [<][>][^][v][top][bottom][index][help] */