"Fossies" - the Fresh Open Source Software Archive

Member "coda-6.9.5/coda-src/venus/vproc_pioctl.cc" (6 Oct 2008, 47291 Bytes) of package /linux/misc/old/coda-6.9.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vproc_pioctl.cc" see the Fossies "Dox" file reference documentation.

    1 /* BLURB gpl
    2 
    3                            Coda File System
    4                               Release 6
    5 
    6           Copyright (c) 1987-2003 Carnegie Mellon University
    7                   Additional copyrights listed below
    8 
    9 This  code  is  distributed "AS IS" without warranty of any kind under
   10 the terms of the GNU General Public Licence Version 2, as shown in the
   11 file  LICENSE.  The  technical and financial  contributors to Coda are
   12 listed in the file CREDITS.
   13 
   14                         Additional copyrights
   15               Copyright (c) 2002-2003 Intel Corporation
   16 
   17 #*/
   18 
   19 /*
   20  *
   21  *    Implementation of the Venus Pioctl interface.
   22  *
   23  *    Pioctls find their way through the VFS interface as vproc::ioctl calls.
   24  *    The code to handle pioctls has been collected here for convenience.
   25  *
   26  */
   27 
   28 #ifdef __cplusplus
   29 extern "C" {
   30 #endif
   31 
   32 #ifdef HAVE_CONFIG_H
   33 #include <config.h>
   34 #endif
   35 
   36 #include <stdio.h>
   37 #include <errno.h>
   38 #include "coda_string.h"
   39 #include <unistd.h>
   40 #include <stdlib.h>
   41 
   42 #include <auth2.h>
   43 #include <prs.h>
   44 #include <rpc2/rpc2.h>
   45 #include <lka.h>
   46 #include <vice.h>
   47 
   48 #ifdef __cplusplus
   49 }
   50 #endif
   51 
   52 /* from vicedep */
   53 #include <venusioctl.h>
   54 /* from venus */
   55 #include "comm.h"
   56 #include "fso.h"
   57 #include "hdb.h"
   58 #include "local.h"
   59 #include "user.h"
   60 #include "venusstats.h"
   61 #include "venus.private.h"
   62 #include "venusvol.h"
   63 #include "vproc.h"
   64 #include "worker.h"
   65 #include "realmdb.h"
   66 
   67 
   68 /* local-repair modification */
   69 void vproc::do_ioctl(VenusFid *fid, unsigned char nr, struct ViceIoctl *data)
   70 {
   71     /*
   72      *    We partition the ioctls into 3 categories:
   73      *      O - those on a particular object
   74      *      V - those on a volume as a whole
   75      *      F - those on the (Coda) filesystem as a whole
   76      */
   77     switch(nr) {
   78     /* Object-based. */
   79     case _VIOCSETAL:
   80     case _VIOCGETAL:
   81     case _VIOCFLUSH:
   82     case _VIOCPREFETCH:
   83     case _VIOC_ADD_MT_PT:
   84     case _VIOC_AFS_DELETE_MT_PT:
   85     case _VIOC_AFS_STAT_MT_PT:
   86     case _VIOC_GETPFID:
   87     case _VIOC_SETVV:
   88         {
   89         fsobj *f = 0;
   90 
   91         int volmode = (nr == _VIOCSETAL || nr == _VIOC_ADD_MT_PT ||
   92                nr == _VIOC_AFS_DELETE_MT_PT || nr == _VIOC_SETVV)
   93           ? VM_MUTATING : VM_OBSERVING;
   94         int rcrights = RC_STATUS;
   95         if (nr == _VIOC_ADD_MT_PT || nr == _VIOC_AFS_DELETE_MT_PT)
   96         rcrights |= RC_DATA;
   97 
   98         for (;;) {
   99             Begin_VFS(fid, CODA_IOCTL, volmode);
  100         if (u.u_error) break;
  101 
  102         u.u_error = FSDB->Get(&f, fid, u.u_uid, rcrights);
  103         if (u.u_error) goto O_FreeLocks;
  104 
  105         switch(nr) {
  106             case _VIOCSETAL:
  107             {
  108             /* Verify that target is a directory. */
  109             if (!f->IsDir())
  110                 { u.u_error = ENOTDIR; break; }
  111 
  112             /* Verify that we have administer permission. */
  113             /* No.  This must be checked at the server to
  114                            allow System:Administrators to */
  115             /* always change ACLs.  Alternatively, we
  116                            could have venus cache the identity */
  117             /* of administrators. */
  118             /* u.u_error = f->Access(PRSFS_ADMINISTER, C_A_F_OK, u.u_uid); if (u.u_error) break; */
  119 
  120             /* Do the operation. */
  121             RPC2_CountedBS acl;
  122             acl.SeqLen = strlen((char *) data->in) + 1;
  123             if (acl.SeqLen > V_MAXACLLEN)
  124                 { u.u_error = EINVAL; break; }
  125             acl.SeqBody = (RPC2_ByteSeq)(char *) data->in;
  126             f->PromoteLock();
  127             u.u_error = f->SetACL(&acl, u.u_uid);
  128 
  129             break;
  130             }
  131 
  132             case _VIOCGETAL:
  133             {
  134             /* Verify that target is a directory. */
  135             if (!f->IsDir())
  136                 { u.u_error = ENOTDIR; break; }
  137 
  138             /* Verify that we have lookup permission. */
  139             /* No.  This must be checked at the server to
  140                            allow System:Administrators to */
  141             /* always change ACLs.  Alternatively, we
  142                            could have venus cache the identity */
  143             /* of administrators. */
  144 /*
  145              u.u_error = f->Access(PRSFS_LOOKUP, C_A_F_OK, u.u_uid);
  146              if (u.u_error) break;
  147 */
  148 
  149             /* Do the operation. */
  150             RPC2_BoundedBS acl;
  151             acl.MaxSeqLen = V_MAXACLLEN;
  152             acl.SeqLen = 0;
  153             acl.SeqBody = (RPC2_ByteSeq)data->out;
  154             acl.SeqBody[0] = 0;
  155             f->PromoteLock();
  156             u.u_error = f->GetACL(&acl, u.u_uid);
  157             if (u.u_error) break;
  158 
  159             data->out_size = (short) (acl.SeqLen == 0 ? 1 : acl.SeqLen);
  160             break;
  161             }
  162 
  163             case _VIOCFLUSH:
  164             {
  165             FSDB->Put(&f);
  166 
  167             /* This is drastic, but I'm having trouble getting rid of */
  168             /* MiniCache vnodes that have the "wrong" type! -JJK */
  169             (void)k_Purge(fid, 1);
  170 
  171             f = FSDB->Find(fid);
  172             if (f != 0) {
  173                 u.u_error = f->Flush();
  174                 Recov_SetBound(DMFP);
  175                 f = 0;
  176             }
  177 
  178             break;
  179             }
  180 
  181             case _VIOCPREFETCH:
  182             {
  183 /*
  184  *           if (type == VPT_Worker)
  185  *               if (!((worker *)this)->returned)
  186  *               ((worker *)this)->Return(0);
  187  */
  188             /* return early to user */
  189             if (type == VPT_Worker) {
  190                 worker *w = (worker *)this;
  191                 union outputArgs *out;
  192                 out = (union outputArgs *)w->msg->msg_buf;
  193                 out->coda_ioctl.data =
  194                 (char *)sizeof(struct coda_ioctl_out);
  195                 out->coda_ioctl.len = 0;
  196                 out->coda_ioctl.oh.result = 0;
  197                 w->Return(w->msg, sizeof (struct coda_ioctl_out));
  198             }
  199 
  200             /* Release and reacquire the target (data this time). */
  201             FSDB->Put(&f);
  202             u.u_error = FSDB->Get(&f, fid, u.u_uid, RC_DATA);
  203 
  204             break;
  205             }
  206 
  207             case _VIOC_ADD_MT_PT:
  208             {
  209             /* A mount-link is virtually identical to a symlink.
  210              * In fact Coda stores mount-links as symlinks on the
  211              * server. The only visible differences are that the
  212              * mount-link has a Unix modemask of 0644, while a
  213              * symlink has 0777. A mountpoint's contents always
  214              * start with '#', '@' (or '%'?)
  215              *
  216              * This code is almost identical to vproc::symlink in
  217              * vproc_vfscalls. -JH
  218              */
  219             fsobj *target_fso = NULL;
  220             char contents[CODA_MAXNAMLEN+1];
  221             char *link_name = (char *) data->in;
  222             char *arg = strchr(link_name, '/');
  223 
  224             if (!arg) { u.u_error = EINVAL; break; };
  225             *arg = '\0'; arg++;
  226 
  227             /* Disallow special names. */
  228             verifyname(link_name, NAME_NO_DOTS | NAME_NO_CONFLICT);
  229             if (u.u_error) break;
  230 
  231             /* Verify that parent is a directory. */
  232             if (!f->IsDir()) { u.u_error = ENOTDIR; break; }
  233 
  234             /* Verify that the target doesn't exist. */
  235             u.u_error = f->Lookup(&target_fso, NULL, link_name,
  236                           u.u_uid, CLU_CASE_SENSITIVE);
  237             FSDB->Put(&target_fso);
  238             if (u.u_error == 0) { u.u_error = EEXIST; break; }
  239             if (u.u_error != ENOENT) { break; }
  240             u.u_error = 0;
  241 
  242             /* Verify that we have insert permission. */
  243             u.u_error = f->Access(PRSFS_INSERT, C_A_F_OK, u.u_uid);
  244             if (u.u_error) { break; }
  245 
  246             /*
  247              * Regular mount-links start with a '#', optionally
  248              * followed by a volume name (current path is used in
  249              * case the volume name is not specified), optionally
  250              * followed by '@' and a realm/domain name (the realm
  251              * of the parent volume is used if this is not
  252              * specified), and end with a single '.'.
  253              *
  254              * The ending character doesn't seem too important, it
  255              * looks like the '.' was added mostly because of the
  256              * buggy implementation of TryToCover which strips the
  257              * last character of the volume name.
  258              *
  259              * There are references in the code that indicate there
  260              * used to be mount-links that started with '%'. I
  261              * don't know what they were used for.
  262              *
  263              * Internally, Venus creates mount-links starting with
  264              * '@', followed by a Fid (volume.vnode.unique),
  265              * optionally followed by '@' and a realm/domain name.
  266              * These are used for conflicts and during repair to
  267              * mount a specific object in the fake repair volume.
  268              *
  269              * -JH
  270              *
  271              * Additionally, collapsing an expanded object that
  272              * was previously a mount point modifies the old mount-
  273              * link to start with '$'. This is to avoid problems
  274              * with ignoring dangling symlinks within
  275              * TryToCover, and is never visible to the user. - Adam
  276              */
  277             /* make it a 'magic' mount name */
  278             snprintf(contents, CODA_MAXNAMLEN,  "#%s.", arg);
  279             contents[CODA_MAXNAMLEN] = '\0';
  280 
  281             /* Do the operation. */
  282             f->PromoteLock();
  283             u.u_error = f->Symlink(contents, link_name, u.u_uid,
  284                            0644, FSDB->StdPri());
  285             if (u.u_error) { break; }
  286             /* set vattr fields? */
  287 
  288             /* Send a downcall to the kernel to get rid of any
  289              * negative name cache entries for the newly created
  290              * object */
  291             k_Purge(fid, 0);
  292             break;
  293             }
  294 
  295             case _VIOC_AFS_DELETE_MT_PT:
  296             {
  297             fsobj *target_fso = 0;
  298             char *target_name = (char *) data->in;
  299 
  300             /* Disallow deletion of special names. */
  301             verifyname(target_name, NAME_NO_DOTS | NAME_NO_CONFLICT);
  302             if (u.u_error) break;
  303 
  304             /* Verify that parent is a directory. */
  305             if (!f->IsDir())
  306                 { u.u_error = ENOTDIR; break; }
  307 
  308             /* Get the target object. */
  309             u.u_error = f->Lookup(&target_fso, NULL, target_name,
  310                           u.u_uid, CLU_CASE_SENSITIVE);
  311             if (u.u_error) break;
  312 
  313             /* Verify that target is a mount point (either valid or dangling). */
  314             if (!target_fso->IsMtPt() && !target_fso->IsMTLink()) {
  315                 FSDB->Put(&target_fso);
  316                 u.u_error = ENOTDIR;
  317                 break;
  318             }
  319 
  320             /* Verify that we have delete permission for the parent. */
  321             u.u_error = f->Access(PRSFS_DELETE, C_A_F_OK, u.u_uid);
  322             if (u.u_error) {
  323                 FSDB->Put(&target_fso);
  324                 break;
  325             }
  326 
  327             /* We only remove MTLinks, not valid MtPts! */
  328             if (target_fso->IsMtPt()) {
  329                 Recov_BeginTrans();
  330                 fsobj *root_fso = target_fso->u.root;
  331                 FSO_ASSERT(target_fso,
  332                        root_fso && root_fso->u.mtpoint == target_fso);
  333                 root_fso->UnmountRoot();
  334                 target_fso->UncoverMtPt();
  335                 Recov_EndTrans(MAXFP);
  336             }
  337 
  338             /* Do the remove. */
  339             f->PromoteLock();
  340             target_fso->PromoteLock();
  341             u.u_error = f->Remove(target_name, target_fso, u.u_uid);
  342 
  343             /* Get rid of anything cached in the kernel relating to
  344              * the removed volume and it's children */
  345             k_Purge(&target_fso->fid, 1);
  346 
  347             FSDB->Put(&target_fso);
  348             break;
  349             }
  350 
  351             case _VIOC_AFS_STAT_MT_PT:
  352             {
  353             fsobj *target_fso = 0;
  354             char *target_name = (char *) data->in;
  355             int out_size = 0;   /* needed since data->out_size is a short! */
  356             verifyname(target_name, NAME_NO_DOTS);
  357 
  358             /* Verify that parent is a directory. */
  359             if (!f->IsDir()) {
  360                 u.u_error = ENOTDIR;
  361                 break;
  362             }
  363 
  364             /* Get the target object. */
  365             u.u_error = f->Lookup(&target_fso, NULL, target_name,
  366                           u.u_uid, CLU_CASE_SENSITIVE);
  367             if (u.u_error) {
  368                 FSDB->Put(&target_fso);
  369                 break;
  370             }
  371 
  372             /* Verify that target is a mount point (either valid or dangling). */
  373             if (!target_fso->IsMtPt() && !target_fso->IsMTLink())
  374                 { u.u_error = ENOTDIR; FSDB->Put(&target_fso); break; }
  375 
  376             /*Verify that we have read permission for it. */
  377             u.u_error = target_fso->Access(PRSFS_LOOKUP, C_A_F_OK, u.u_uid);
  378             if (u.u_error) { FSDB->Put(&target_fso); break; }
  379 
  380             /* Retrieve the link contents from the cache. */
  381             u.u_error = target_fso->Readlink((char *)data->out,
  382                              CODA_MAXPATHLEN,
  383                              &out_size, u.u_uid);
  384             if (u.u_error) {
  385                 FSDB->Put(&target_fso);
  386                 break;
  387             }
  388 
  389             /* Make link a proper string. */
  390             data->out_size = out_size;
  391             ((char *)data->out) [data->out_size] = 0;
  392             (data->out_size)++;
  393 
  394             FSDB->Put(&target_fso);
  395             break;
  396             }
  397 
  398             case _VIOC_GETPFID:
  399             {
  400             if (data->in_size <= sizeof(VenusFid) || 
  401                 *((char *)data->in + data->in_size - 1) != '\0')
  402                 { u.u_error = EINVAL; break; }
  403 
  404             ViceFid fid;
  405             memcpy(&fid, data->in, sizeof(ViceFid));
  406             char *realmname = (char *)data->in + sizeof(ViceFid);
  407             Realm *realm = REALMDB->GetRealm(realmname);
  408 
  409             VenusFid vfid;
  410             MakeVenusFid(&vfid, realm->Id(), &fid);
  411 
  412             FSDB->Put(&f);
  413 
  414             u.u_error = FSDB->Get(&f, &vfid, u.u_uid, RC_STATUS);
  415             if (u.u_error) break;
  416 
  417             /* if we're at a mount point, back up over it. */
  418             if (f->IsRoot()) {
  419                 if (f->u.mtpoint == 0) 
  420                 { u.u_error = ENOENT; break; }
  421 
  422                 VenusFid mtptfid = f->u.mtpoint->fid;
  423                 FSDB->Put(&f);
  424                 u.u_error = FSDB->Get(&f, &mtptfid, u.u_uid, RC_STATUS);
  425                 if (u.u_error) break;
  426                 }
  427 
  428             /* Copy out the parent fid. */
  429             memcpy(data->out, MakeViceFid(&f->pfid), sizeof(ViceFid));
  430             data->out_size = (short)sizeof(ViceFid);
  431 
  432             break;
  433             }
  434 
  435             case _VIOC_SETVV:
  436             {
  437             if (data->in_size != (int)sizeof(ViceVersionVector))
  438                 { u.u_error = EINVAL; break; }
  439 
  440             f->PromoteLock();
  441             u.u_error = f->SetVV((ViceVersionVector *)data->in, u.u_uid);
  442 
  443             break;
  444             }
  445         }
  446 O_FreeLocks:
  447         FSDB->Put(&f);
  448         int retry_call = 0;
  449         End_VFS(&retry_call);
  450         if (!retry_call) break;
  451         }
  452         }
  453         return;
  454 
  455     /* Object-based. Allowing access to inconsistent objects. */
  456     case _VIOC_ENABLEREPAIR:
  457     case _VIOC_DISABLEREPAIR:
  458         case _VIOC_EXPANDOBJECT:
  459         case _VIOC_COLLAPSEOBJECT:
  460         case _VIOC_REPAIR:
  461     case _VIOC_FLUSHASR:
  462     case _VIOC_GETFID:
  463         {
  464         fsobj *f = 0;
  465 
  466         int volmode =
  467           (nr == _VIOC_EXPANDOBJECT || nr == _VIOC_ENABLEREPAIR ||
  468            nr == _VIOC_COLLAPSEOBJECT || nr == _VIOC_DISABLEREPAIR ||
  469            nr == _VIOC_REPAIR)
  470           ? VM_MUTATING : VM_OBSERVING;
  471 
  472         int rcrights = RC_STATUS;
  473 
  474         if (nr == _VIOC_EXPANDOBJECT || nr == _VIOC_ENABLEREPAIR ||
  475         nr == _VIOC_COLLAPSEOBJECT || nr == _VIOC_DISABLEREPAIR ||
  476         nr == _VIOC_REPAIR)
  477           rcrights |= RC_DATA;
  478 
  479         for (;;) {
  480         Begin_VFS(fid, CODA_IOCTL, volmode);
  481         if (u.u_error) break;
  482 
  483         u.u_error = FSDB->Get(&f, fid, u.u_uid, RC_STATUS,
  484                       NULL, NULL, NULL, 1);
  485         if (u.u_error && u.u_error != EINCONS) goto OI_FreeLocks;
  486 
  487         switch(nr) {
  488 
  489         case _VIOC_ENABLEREPAIR:
  490         case _VIOC_EXPANDOBJECT:
  491           {
  492             f->PromoteLock();
  493             u.u_error = f->ExpandObject();
  494 
  495             /* Make sure the kernel drops the symlink */
  496             (void)k_Purge(fid, 1);
  497             (void)k_Purge(&f->pfid, 1);
  498             break;
  499           }
  500 
  501         case _VIOC_DISABLEREPAIR:
  502           u.u_error = 0;
  503         case _VIOC_COLLAPSEOBJECT:
  504           {
  505               f->PromoteLock();
  506               u.u_error = f->CollapseObject();
  507 
  508               /* Make sure the kernel drops the subtree */
  509               (void)k_Purge(&f->fid, 1);
  510               (void)k_Purge(&f->pfid, 1);
  511               break;
  512           }
  513 
  514           /*
  515             BEGIN_HTML
  516             <a name="dorepair"><strong> dorepair handler </strong></a>
  517             END_HTML
  518           */
  519         case _VIOC_REPAIR:
  520           {
  521             if (f->IsLocalObj()) {
  522               int rc;
  523               fsobj *fakedir = f;
  524 
  525               /* find the expanded object */
  526               f = NULL;
  527               rc = fakedir->Lookup(&f, NULL, LOCALCACHE, u.u_uid,
  528                     CLU_CASE_SENSITIVE | CLU_TRAVERSE_MTPT, 1);
  529               if(rc)
  530             rc = fakedir->Lookup(&f, NULL, LOCALCACHE_HIDDEN,
  531                u.u_uid, CLU_CASE_SENSITIVE | CLU_TRAVERSE_MTPT, 1);
  532               if(rc) {
  533             LOG(0, ("VIOC_REPAIR: Lookup() failed for LOCALCACHE:%d\n", rc));
  534             break;
  535               }
  536               else
  537             CODA_ASSERT(f);
  538 
  539               LOG(0, ("VIOC_REPAIR: called on expanded directory (%s)! redirecting to localcache (%s)\n", FID_(&fakedir->fid), FID_(&f->fid)));
  540 
  541               FSDB->Put(&fakedir);
  542             }
  543 
  544 #ifdef TIMING
  545             gettimeofday(&u.u_tv1, 0); u.u_tv2.tv_sec = 0;
  546 #endif
  547             /* whether we need this depends on the granularity of repair calls */
  548             volent *v = 0;
  549             if ((u.u_error = VDB->Get(&v, MakeVolid(&f->fid)))) break;
  550 
  551             int entered = 0;
  552             if ((u.u_error = v->Enter(volmode, u.u_uid)) != 0)
  553               CODA_ASSERT("V_FreeLocks!\n");//goto V_FreeLocks;
  554             entered = 1;
  555 
  556             /* Try to repair target object. */
  557 #define RepairFile  ((char *)data->in)
  558 #define startp      (data->out)
  559 #define RWVols      ((VolumeId *)(startp))
  560 #define ReturnCodes ((int *)(RWVols + VSG_MEMBERS))
  561 #define endp        ((char *)(ReturnCodes + VSG_MEMBERS))
  562             data->out_size = (endp - startp);
  563 
  564                     u.u_error = EOPNOTSUPP;
  565 
  566             if(v->IsReplicated()) {
  567               VenusFid fid = f->fid;
  568               LOG(0, ("VIOC_REPAIR calling repvol::Repair (%s)\n",
  569                   FID_(&f->fid)));
  570               FSDB->Put(&f);
  571               u.u_error = ((repvol *)v)->Repair(&fid, RepairFile,
  572                             u.u_uid, RWVols,
  573                             ReturnCodes);
  574             }
  575             else
  576               LOG(0, ("VIOC_REPAIR: non-replicated volume!\n"));
  577 
  578             LOG(0, ("VIOC_REPAIR: repvol::Repair returns %d\n",
  579                 u.u_error));
  580 #undef  RepairFile
  581 #undef  startp
  582 #undef  RWVols
  583 #undef  ReturnCodes
  584 #undef  endp
  585             if (entered) v->Exit(volmode, u.u_uid);
  586             float elapsed = 0.0;
  587 #ifdef TIMING
  588 
  589             gettimeofday(&u.u_tv2, 0);
  590             elapsed = SubTimes(&(u.u_tv2), &(u.u_tv1));
  591 #endif
  592 
  593             VDB->Put(&v);
  594             break;
  595           }
  596 
  597         case _VIOC_FLUSHASR:
  598             /* This function used to be built around FSDB->Find, which
  599              * did no locking. Now we use FSDB->Get, which does do
  600              * locking. Hopefully this is better, and nothing breaks.
  601              * --JH */
  602             {
  603             /* ASR flush operation allowed only for files */
  604             LOG(100, ("Going to reset lastresolved time for %s\n", FID_(fid)));
  605             u.u_error = f->SetLastResolved(0);
  606             break;
  607             }
  608 
  609         case _VIOC_GETFID:
  610             {
  611             if (!(data->in_size == 0 || data->in_size == sizeof(int))) {
  612             u.u_error = EINVAL;
  613             break;
  614             }
  615             /* Backup and use volroot's mount point if directed. */
  616             if (data->in_size == sizeof(int) && *(int *)data->in != 0) {
  617             if (!FID_IsVolRoot(&f->fid) || f->u.mtpoint == 0) {
  618                 u.u_error = EINVAL;
  619                 break;
  620             }
  621 
  622             VenusFid mtptfid = f->u.mtpoint->fid;
  623             FSDB->Put(&f);
  624             u.u_error = FSDB->Get(&f, &mtptfid, u.u_uid, RC_STATUS,
  625                           NULL, NULL, NULL, 1);
  626             if (u.u_error) break;
  627             }
  628 
  629             struct GetFid {
  630             ViceFid fid;
  631             ViceVersionVector vv;
  632             char realm[MAXHOSTNAMELEN+1];
  633             } *cp;
  634             cp = (struct GetFid *)data->out;
  635 
  636             /* Copy out the fid. */
  637             memcpy(&cp->fid, MakeViceFid(&f->fid), sizeof(ViceFid));
  638 
  639             /* Copy out the VV. This will be garbage unless the
  640              * object is replicated! */
  641             memcpy(&cp->vv, &f->stat.VV, sizeof(ViceVersionVector));
  642 
  643             strcpy(cp->realm, f->vol->realm->Name());
  644 
  645             data->out_size = sizeof(struct GetFid);
  646             break;
  647             }
  648         }
  649 OI_FreeLocks:
  650         if(f)
  651           FSDB->Put(&f);
  652         int retry_call = 0;
  653         End_VFS(&retry_call);
  654         if (!retry_call) break;
  655         }
  656         }
  657         return;
  658 
  659     /* Volume-based. */
  660     case _VIOCGETVOLSTAT:
  661     case _VIOCSETVOLSTAT:
  662     case _VIOCWHEREIS:
  663     case _VIOC_FLUSHVOLUME:
  664     case _VIOC_GETSERVERSTATS:
  665     case _VIOC_CHECKPOINTML:
  666     case _VIOC_PURGEML:
  667     case _VIOC_WD:
  668     case _VIOC_ENABLEASR:
  669     case _VIOC_DISABLEASR: 
  670     case _VIOC_LISTCACHE_VOLUME:
  671     case _VIOC_SYNCCACHE:
  672     case _VIOC_REDIR:
  673     case _VIOC_REP_CMD:
  674 
  675         {
  676 #ifdef TIMING
  677         gettimeofday(&u.u_tv1, 0); u.u_tv2.tv_sec = 0;
  678 #endif
  679         volent *v = 0;
  680         if ((u.u_error = VDB->Get(&v, MakeVolid(fid)))) break;
  681 
  682         int volmode = ((nr == _VIOC_PURGEML || nr == _VIOC_REP_CMD) ?
  683                VM_MUTATING : VM_OBSERVING);
  684         int entered = 0;
  685         if ((u.u_error = v->Enter(volmode, u.u_uid)) != 0)
  686         goto V_FreeLocks;
  687         entered = 1;
  688 
  689         switch(nr) {
  690             case _VIOC_LISTCACHE_VOLUME:
  691                 {
  692               /* List cache status */
  693               struct listcache_in {
  694             char fname[23];     /* "/tmp/_Venus_List_Cache" */
  695             int  first_volume;
  696             int  long_format;
  697             int  valid;
  698               } *data_in;
  699 
  700               /* Check whether specified volume is a mount point */
  701               fsobj *f = FSDB->Find(fid);
  702               if (f == 0) {
  703             MarinerLog("Specified volume is not valid fsobj.");
  704             u.u_error = EINVAL;
  705             break;
  706               }
  707               if ( !f->IsRoot() && !f->IsMtPt() ) {
  708             MarinerLog("Specified volume is not a mount point.");
  709             u.u_error = EINVAL;
  710             break;
  711               }
  712 
  713               /* Do ListCache */
  714               data_in = (struct listcache_in *)data->in;
  715               char *venus_file = data_in->fname;
  716               FILE *fp;
  717               if (data_in->first_volume)
  718             fp = fopen(venus_file, "w+");
  719               else
  720             fp = fopen(venus_file, "a+");
  721               if (fp == NULL) {
  722             MarinerLog("Cannot open file: %s\n", venus_file);
  723             u.u_error = errno;
  724             break;
  725               }
  726               v->ListCache(fp, data_in->long_format, data_in->valid);
  727               fflush(fp);
  728               fclose(fp);
  729               if ( chmod(venus_file, 00666) < 0 ) {
  730             MarinerLog("Cannot chmod file: %s\n", venus_file);
  731             u.u_error = errno;
  732               }
  733               break;
  734             }
  735             
  736         case _VIOCGETVOLSTAT:
  737             {
  738             /* Volume status block. */
  739             VolumeStatus volstat;
  740 
  741             /* Volume name. */
  742             char name[V_MAXVOLNAMELEN];
  743             RPC2_BoundedBS Name;
  744             Name.SeqBody = (RPC2_ByteSeq)name;
  745             Name.MaxSeqLen = V_MAXVOLNAMELEN;
  746             Name.SeqLen = 0;
  747 
  748             /* Offline message for this volume. */
  749             char offlinemsg[256];
  750             RPC2_BoundedBS OfflineMsg;
  751             OfflineMsg.SeqBody = (RPC2_ByteSeq)offlinemsg;
  752             OfflineMsg.MaxSeqLen = 256;
  753             OfflineMsg.SeqLen = 0;
  754 
  755             /* Message of the day for this volume. */
  756             char motd[256];
  757             RPC2_BoundedBS MOTD;
  758             MOTD.SeqBody = (RPC2_ByteSeq)motd;
  759             MOTD.MaxSeqLen = 256;
  760             MOTD.SeqLen = 0;
  761 
  762             VolumeStateType conn_state;
  763             unsigned int    age, hogtime;
  764             int             conflict, cml_count;
  765             uint64_t        cml_bytes;
  766             int         local_only = 0;
  767             if (data->in_size == sizeof(int) &&
  768             *(int *)data->in == 1)
  769             local_only = 1;
  770 
  771             /* Retrieve the volume status from the server(s). */
  772             u.u_error = v->GetVolStat(&volstat, &Name, &conn_state,
  773                           &age, &hogtime,
  774                           &conflict, &cml_count,
  775                           &cml_bytes,
  776                           &OfflineMsg, &MOTD, u.u_uid,
  777                           local_only);
  778             if (u.u_error) break;
  779 
  780             /* Format is (status, name, conn_state, conflict,
  781                cml_count, offlinemsg, motd, age, hogtime) */
  782             /* First we make sure we won't overflow data->out */
  783             if ( (sizeof(VolumeStatus) + /* volstat */
  784              strlen(name) + 1 + /* name */
  785              sizeof(int) + /* conn_state */
  786              sizeof(int) + /* conflict */
  787              sizeof(int) + /* cml_count */
  788              strlen(offlinemsg) + 1 + /* offlinemsg */
  789              strlen(motd) + 1 + /* motd */
  790              sizeof(unsigned int) + /* age */
  791              sizeof(unsigned int) + /* hogtime */
  792              sizeof(uint64_t))  /* cml_bytes */
  793              > VC_MAXDATASIZE ) {
  794             LOG(0, ("vproc::do_ioctl: VIOCGETVOLSTAT: buffer is "
  795                 "not large enough to hold the message\n"));
  796             u.u_error = EINVAL;
  797             break;
  798             }
  799             /* then we copy the stuff to the buffer */
  800             char *cp = (char *) data->out;/* Invariant: cp always
  801                              point to next loc. to
  802                              be copied into */
  803             memcpy(cp, &volstat, sizeof(VolumeStatus));
  804             cp += sizeof(VolumeStatus);
  805             strcpy(cp, name); cp += strlen(name) + 1;
  806 
  807             /* do we have to worry about alignment? */
  808             *(int32_t *)cp = (int32_t)conn_state; cp += sizeof(int32_t);
  809             *(int32_t *)cp = (int32_t)conflict;   cp += sizeof(int32_t);
  810             *(int32_t *)cp = (int32_t)cml_count;  cp += sizeof(int32_t);
  811 
  812             strcpy(cp, offlinemsg); cp += strlen(offlinemsg) + 1;
  813             strcpy(cp, motd); cp += strlen(motd) + 1;
  814 
  815             *(uint32_t *)cp = (uint32_t)age;     cp += sizeof(uint32_t);
  816             *(uint32_t *)cp = (uint32_t)hogtime; cp += sizeof(uint32_t);
  817             *(uint64_t *)cp = (uint64_t)cml_bytes;
  818             cp += sizeof(uint64_t);
  819 
  820             data->out_size = (cp - data->out);
  821             break;
  822             }
  823 
  824         case _VIOCSETVOLSTAT:
  825             {
  826             /* Format is (status, name, offlinemsg, motd). */
  827             char *cp = (char *) data->in;
  828 
  829             /* Volume status block. */
  830             VolumeStatus volstat;
  831             memcpy(&volstat, cp, sizeof(VolumeStatus));
  832             cp += sizeof(VolumeStatus);
  833 
  834             /* Volume name. */
  835                     char name[V_MAXVOLNAMELEN];
  836             unsigned int namelen = strlen(cp) + 1;
  837             if (namelen >= V_MAXVOLNAMELEN) { u.u_error = EINVAL; break; }
  838             strcpy(name, cp);
  839 
  840             RPC2_BoundedBS Name;
  841             Name.SeqBody = (RPC2_ByteSeq)name;
  842             Name.MaxSeqLen = V_MAXVOLNAMELEN;
  843 #if 0
  844             /* Avoid setting the volumename, otherwise cfs setquota
  845              * renames all volume replicas to that of their replicated
  846              * parent. This might confuse ViceGetVolumeInfo and leads
  847              * to subtle corruption. --JH */
  848             Name.SeqLen = namelen;
  849 #else
  850             Name.SeqLen = 0;
  851 #endif
  852             cp += namelen;
  853 
  854             /* Offline message for this volume. */
  855             char offlinemsg[256];
  856             unsigned int offlinemsglen = strlen(cp) + 1;
  857             if (offlinemsglen > 256) { u.u_error = EINVAL; break; }
  858             strcpy(offlinemsg, cp);
  859             RPC2_BoundedBS OfflineMsg;
  860             OfflineMsg.SeqBody = (RPC2_ByteSeq)offlinemsg;
  861             OfflineMsg.MaxSeqLen = 256;
  862             OfflineMsg.SeqLen = offlinemsglen;
  863             cp += offlinemsglen;
  864 
  865             /* Message of the day for this volume. */
  866             char motd[256];
  867             unsigned int motdlen = strlen(cp) + 1;
  868             if (motdlen >= 256) { u.u_error = EINVAL; break; }
  869             strcpy(motd, cp);
  870             RPC2_BoundedBS MOTD;
  871             MOTD.SeqBody = (RPC2_ByteSeq)motd;
  872             MOTD.MaxSeqLen = 256;
  873             MOTD.SeqLen = motdlen;
  874 
  875             /* Send the volume status to the server(s). */
  876             u.u_error = v->SetVolStat(&volstat, &Name, &OfflineMsg,
  877                           &MOTD, u.u_uid);
  878             if (u.u_error) break;
  879 
  880             /* Copy all the junk back out. */
  881             /* Format is (status, name, offlinemsg, motd). */
  882             cp = (char *) data->out;
  883             memcpy(cp, &volstat, sizeof(VolumeStatus));
  884             cp += sizeof(VolumeStatus);
  885             strcpy(cp, name);
  886             cp += strlen(name) + 1;
  887             strcpy(cp, offlinemsg);
  888             cp += strlen(offlinemsg) + 1;
  889             strcpy(cp, motd);
  890             cp += strlen(motd) + 1;
  891             data->out_size = (cp - data->out);
  892             break;
  893             }
  894 
  895         case _VIOCWHEREIS:
  896             {
  897                         /* Extract the host array from the vsgent or volent as appropriate. */
  898                         v->GetHosts((struct in_addr *)data->out);
  899                         /* Extract an array if vids from the vsgent or volent as appropriate. */
  900             v->GetVids((VolumeId *)(data->out + (VSG_MEMBERS * sizeof(struct in_addr))));
  901                         data->out_size = VSG_MEMBERS * (sizeof(struct in_addr) + sizeof(VolumeId));
  902                         break;
  903             }
  904 
  905         case _VIOC_FLUSHVOLUME:
  906             {
  907             /* This is drastic, but I'm having trouble getting rid of */
  908             /* MiniCache vnodes that have the "wrong" type! -JJK */
  909             (void)k_Purge();
  910 
  911             FSDB->Flush(MakeVolid(fid));
  912             Recov_SetBound(DMFP);
  913 
  914             break;
  915             }
  916 
  917         case _VIOC_GETSERVERSTATS:
  918             {
  919             /* Extract the host array from the vsgent or volent as appropriate. */
  920             struct in_addr Hosts[VSG_MEMBERS];
  921             v->GetHosts(Hosts);
  922 
  923             /* Count number of hosts to make sure buffer size wouldn't be exceeded. */
  924             int i;
  925             int nHosts = 0;
  926             for (i = 0; i < VSG_MEMBERS; i++)
  927             if (Hosts[i].s_addr) nHosts++;
  928             if (nHosts * (int)sizeof(ViceStatistics) > VC_MAXDATASIZE)
  929             { u.u_error = EINVAL; break; }
  930 
  931             /* Get statistics from each host. */
  932             /* OUT data for hosts that are incommunicado will be zero. */
  933             memset(data->out, 0, nHosts * (int)sizeof(ViceStatistics));
  934             ViceStatistics *Stats = (ViceStatistics *)data->out;
  935             for (i = 0; i < VSG_MEMBERS; i++)
  936             if (Hosts[i].s_addr) {
  937                 srvent *s = GetServer(&Hosts[i], v->GetRealmId());
  938                 (void)s->GetStatistics(Stats);
  939                 PutServer(&s);
  940                 Stats++;
  941             }
  942 
  943             data->out_size = (char *)Stats - data->out;
  944             break;
  945             }
  946 
  947         case _VIOC_CHECKPOINTML:
  948             {
  949             char *ckpdir = (data->in_size == 0 ? 0 : (char *) data->in);
  950                     u.u_error = EOPNOTSUPP;
  951                     if (v->IsReplicated())
  952                         u.u_error = ((repvol *)v)->CheckPointMLEs(u.u_uid, ckpdir);
  953             break;
  954             }
  955 
  956         case _VIOC_PURGEML:
  957             {
  958                     u.u_error = EOPNOTSUPP;
  959                     if (v->IsReplicated())
  960                         u.u_error = ((repvol *)v)->PurgeMLEs(u.u_uid);
  961             break;
  962             }
  963         case _VIOC_WD:
  964             {
  965             /* 
  966              * Begin logging mutations to this volume. 
  967              * This is "pseudo-disconnected" mode, in which
  968              * fetches may be performed but mutations are logged.
  969              */
  970             char *startp = (char *) data->in;
  971 #define agep ((unsigned int *)(startp))
  972 #define timep ((unsigned int *)(agep + 1))
  973                     u.u_error = EOPNOTSUPP;
  974                     if (v->IsReplicated())
  975                         u.u_error = ((repvol *)v)->WriteDisconnect(*agep, *timep); 
  976 #undef timep
  977 #undef agep
  978             break;
  979             }
  980         case _VIOC_ENABLEASR:
  981             {           
  982                         u.u_error = EOPNOTSUPP;
  983                         if (v->IsReplicated())
  984                             u.u_error = ((repvol *)v)->AllowASR(u.u_uid);
  985             break;
  986             }
  987         case _VIOC_DISABLEASR:
  988             {
  989                         u.u_error = EOPNOTSUPP;
  990                         if (v->IsReplicated())
  991                             u.u_error = ((repvol *)v)->DisallowASR(u.u_uid);
  992             break;
  993             }
  994 
  995         case _VIOC_SYNCCACHE:
  996             {
  997                   u.u_error = EOPNOTSUPP;
  998                   if (v->IsReplicated()) {
  999               v->Exit(volmode, u.u_uid);
 1000               entered = 0;
 1001               u.u_error = ((repvol *)v)->SyncCache(NULL);
 1002           }
 1003           break;
 1004               }
 1005 
 1006         case _VIOC_REDIR:
 1007           {
 1008             struct in_addr staging_server;
 1009             if (data->in_size != (int)sizeof(struct in_addr)) {
 1010               u.u_error = EINVAL; break;
 1011             }
 1012             if (!v->IsReplicated()) {
 1013               u.u_error = EINVAL; break;
 1014             }
 1015             
 1016             staging_server = *(struct in_addr *)data->in;
 1017             ((repvol *)v)->SetStagingServer(&staging_server);
 1018             break;
 1019           }
 1020 
 1021         case _VIOC_REP_CMD:
 1022           {
 1023         int rep_cmd;
 1024         CODA_ASSERT(sscanf((char *) data->in, "%d", &rep_cmd) == 1);
 1025         switch (rep_cmd) {
 1026 /*
 1027   BEGIN_HTML
 1028   <a name="beginrepair"><strong> beginrepair handler </strong></a>
 1029   END_HTML
 1030 */
 1031           case REP_CMD_BEGIN:
 1032             {
 1033               /* This ioctl only figures out what type of conflict
 1034                * we are dealing with and verifies the object is
 1035                * expanded correctly. No mutations are performed.
 1036                * The idea of 'beginning repair' is historical, and
 1037                * there is no problem calling this on the same directory
 1038                * or volume many times without an 'endrepair', or
 1039                * attempting any form of repair without calling this
 1040                * first. */
 1041               /*
 1042                *      1 - Local/Global repair session
 1043                *      2 - Server/Server repair session
 1044                *      3 - Both Local/Global and Server/Server
 1045                */
 1046 
 1047               int code = -1, rc;
 1048               fsobj *dir = NULL, *localcache = NULL;
 1049               char *msg;
 1050 
 1051               msg = (char *)data->out;
 1052               if(!msg) {
 1053             LOG(0, ("REP_CMD_BEGIN: (%s) bad data->out parameter\n",
 1054                 FID_(fid)));
 1055             code = -1;
 1056             goto BEGIN_cleanup;
 1057               }
 1058 
 1059               dir = FSDB->Find(fid);
 1060               if(!dir) {
 1061             LOG(0, ("REP_CMD_BEGIN: (%s) <= this object missing!\n",
 1062                 FID_(fid)));
 1063             code = -1;
 1064             goto BEGIN_cleanup;
 1065               }
 1066 
 1067               if(!dir->IsLocalObj()) {
 1068             LOG(0, ("REP_CMD_BEGIN: (%s) not an expanded dir\n",
 1069                 FID_(fid)));
 1070             code = -1;
 1071             goto BEGIN_cleanup;
 1072               }
 1073 
 1074               rc = dir->Lookup(&localcache, fid, LOCALCACHE_HIDDEN,
 1075                        u.u_uid, CLU_CASE_SENSITIVE |
 1076                        CLU_TRAVERSE_MTPT, 1);
 1077 
 1078               if(!localcache)
 1079             rc = dir->Lookup(&localcache, fid, LOCALCACHE,
 1080                      u.u_uid, CLU_CASE_SENSITIVE |
 1081                      CLU_TRAVERSE_MTPT, 1);
 1082               if(!localcache || (rc && rc != EINCONS)) {
 1083             LOG(0, ("REP_CMD_BEGIN: (%s) failed finding localcache "
 1084                 "object.. bad news.\n", FID_(fid)));
 1085             code = -1;
 1086             goto BEGIN_cleanup;
 1087               }
 1088 
 1089               if(localcache->IsFake())
 1090             code = 2;
 1091 
 1092               if(localcache->IsToBeRepaired()) {
 1093             if(code == 2)
 1094               code = 3;
 1095             else
 1096               code = 1;
 1097               }
 1098 
 1099             BEGIN_cleanup:
 1100               if(localcache)
 1101             FSDB->Put(&localcache);
 1102 
 1103               sprintf(msg, "%d", code);
 1104               data->out_size = (short)sizeof((char *) data->out);
 1105 
 1106               u.u_error = 0;
 1107               break;
 1108             }
 1109 /*
 1110   BEGIN_HTML
 1111   <a name="endrepair"><strong> endrepair handler </strong></a>
 1112   END_HTML
 1113 */
 1114           case REP_CMD_END:
 1115             {
 1116               /*
 1117                * This ioctl literally does nothing. The only applicable
 1118                * use might be for unfreezing volumes if mechanisms
 1119                * are implemented to freeze state upon server-server
 1120                * conflict discovery.
 1121                *
 1122                * Even then, that might be better suited to the
 1123                * _VIOC_REPAIR ioctl, which figures out if any repair
 1124                * actually occurred and if it was successful.
 1125                */
 1126               char *msg;
 1127 
 1128               msg = (char *)data->out;
 1129               if(!msg) {
 1130             u.u_error = EINVAL;
 1131             break;
 1132               }
 1133 
 1134               u.u_error = EOPNOTSUPP;
 1135               if(v->IsReplicated()) {
 1136             sprintf(msg, "no action performed\n");
 1137             u.u_error = 0;
 1138               }
 1139 
 1140               data->out_size = (short)strlen(msg) + 1;
 1141               break;
 1142             }
 1143 /*
 1144   BEGIN_HTML
 1145   <a name="checklocal"><strong> checklocal handler </strong></a>
 1146   END_HTML
 1147 */
 1148           case REP_CMD_CHECK:
 1149           {
 1150             char *msg;
 1151             msg = (char *)data->out;
 1152             if(!msg)
 1153               u.u_error = EINVAL;
 1154             else
 1155               u.u_error = EOPNOTSUPP;
 1156             if(msg && v->IsReplicated()) {
 1157               ClientModifyLog *cml = ((repvol *)v)->GetCML();
 1158               cml->CheckCMLHead(msg);
 1159               u.u_error = 0;
 1160             }
 1161             else
 1162               sprintf(msg, "not a replicated volume\n");
 1163 
 1164             data->out_size = (short)strlen(msg) + 1;
 1165             break;
 1166           }
 1167 
 1168 /*
 1169   BEGIN_HTML
 1170   <a name="preservelocal"><strong> preservelocal handler </strong></a>
 1171   END_HTML
 1172 */
 1173         case REP_CMD_PRESERVE:
 1174           {
 1175             char *msg;
 1176             msg = (char *)data->out;
 1177             if(!msg) {
 1178               u.u_error = EINVAL;
 1179               break;
 1180             }
 1181 
 1182             msg[0] = '\0';
 1183             u.u_error = EOPNOTSUPP;
 1184             if(v->IsReplicated()) {
 1185               ClientModifyLog *cml = ((repvol *)v)->GetCML();
 1186               u.u_error = 0;
 1187               cml->PreserveLocalMutation(msg);
 1188             }
 1189 
 1190             data->out_size = (short)strlen(msg) + 1;
 1191             break;
 1192           }
 1193 
 1194 /*
 1195   BEGIN_HTML
 1196   <a name="preservealllocal"><strong> preservealllocal handler </strong></a>
 1197   END_HTML
 1198 */
 1199         case REP_CMD_PRESERVE_ALL:
 1200           {
 1201             char *msg;
 1202             msg = (char *)data->out;
 1203             if(!msg) {
 1204               u.u_error = EINVAL;
 1205               break;
 1206             }
 1207 
 1208             u.u_error = EOPNOTSUPP;
 1209             if(v->IsReplicated()) {
 1210               ClientModifyLog *cml = ((repvol *)v)->GetCML();
 1211               CODA_ASSERT(cml);
 1212               if(!cml) {
 1213             sprintf(msg, "no client modify log on this volume\n");
 1214             data->out_size = (short)strlen(msg) + 1;
 1215             u.u_error = EINVAL;
 1216             break;
 1217               }
 1218               u.u_error = 0;
 1219               cml->PreserveAllLocalMutation(msg);
 1220             }
 1221 
 1222             data->out_size = (short)strlen(msg) + 1;
 1223             break;
 1224           }
 1225 
 1226 /*
 1227   BEGIN_HTML
 1228   <a name="discardlocal"><strong> discardlocal handler </strong></a>
 1229   END_HTML
 1230 */
 1231         case REP_CMD_DISCARD:
 1232           {
 1233             char *msg;
 1234             msg = (char *)data->out;
 1235             if(!msg) {
 1236               u.u_error = EINVAL;
 1237               break;
 1238             }
 1239 
 1240             u.u_error = EOPNOTSUPP;
 1241             if(v->IsReplicated()) {
 1242               ClientModifyLog *cml = ((repvol *)v)->GetCML();
 1243               CODA_ASSERT(cml);
 1244               if(!cml) {
 1245             sprintf(msg, "no client modify log on this volume\n");
 1246             data->out_size = (short)strlen(msg) + 1;
 1247             u.u_error = EINVAL;
 1248             break;
 1249               }
 1250               u.u_error = cml->DiscardLocalMutation(msg);
 1251             }
 1252 
 1253             data->out_size = (short)strlen(msg) + 1;
 1254             break;
 1255           }
 1256 /*
 1257   BEGIN_HTML
 1258   <a name="discardalllocal"><strong> discardalllocal handler </strong></a>
 1259   END_HTML
 1260 */
 1261         case REP_CMD_DISCARD_ALL:
 1262           {
 1263             /* Not supported. Use PURGEML instead. */
 1264             data->out_size = 0;
 1265             u.u_error = EOPNOTSUPP;
 1266             break;
 1267           }
 1268 /*
 1269   BEGIN_HTML
 1270   <a name="listlocal"><strong> listlocal handler </strong></a>
 1271   END_HTML
 1272 */
 1273         case REP_CMD_LIST:
 1274           {
 1275             /* list local mutations belonging to this session */
 1276             char fpath[CODA_MAXPATHLEN];
 1277             int dummy;
 1278 
 1279             sscanf((char *) data->in, "%d %s", &dummy, fpath);
 1280 
 1281             u.u_error = EOPNOTSUPP;
 1282             if(v->IsReplicated()) {
 1283               FILE *fp = fopen(fpath, "w");
 1284               u.u_error = EINVAL; /* EBADF even though not a fd? */
 1285               if (fp) {
 1286             ClientModifyLog *cml = ((repvol *)v)->GetCML();
 1287             CODA_ASSERT(cml);
 1288             int count = cml->ListCML(fp);
 1289             fprintf(fp, "%d entries total in the modify log for volume %s\n", count, v->GetName());
 1290             fflush(fp);
 1291             fclose(fp);
 1292             u.u_error = 0;
 1293               }
 1294             }
 1295             break;
 1296           }
 1297         default:
 1298           eprint("bogus REP_CMD(%d)", rep_cmd);
 1299           break;
 1300         }
 1301           }
 1302         }
 1303 
 1304         V_FreeLocks:
 1305           if (entered) v->Exit(volmode, u.u_uid);
 1306           float elapsed = 0.0;
 1307 #ifdef TIMING
 1308 
 1309           gettimeofday(&u.u_tv2, 0);
 1310           elapsed = SubTimes(&(u.u_tv2), &(u.u_tv1));
 1311 #endif
 1312           VDB->Put(&v);
 1313         if (u.u_error == ERETRY)
 1314           u.u_error = EWOULDBLOCK;
 1315         return;
 1316         }
 1317     /* FS-based. */
 1318     case _VIOCSETTOK:
 1319     case _VIOCGETTOK:
 1320     case _VIOCUNLOG:
 1321     case _VIOCCKSERV:
 1322     case _VIOCCKBACK:
 1323     case _VIOC_VENUSLOG:
 1324     case _VIOC_GETVENUSSTATS:
 1325     case _VIOC_FLUSHCACHE:
 1326     case _VIOC_HDB_ADD:
 1327     case _VIOC_HDB_DELETE:
 1328     case _VIOC_HDB_CLEAR:
 1329     case _VIOC_HDB_LIST:
 1330     case _VIOC_HDB_WALK:
 1331     case _VIOC_HDB_VERIFY:
 1332     case _VIOC_HDB_ENABLE:
 1333     case _VIOC_HDB_DISABLE:
 1334     case _VIOC_CLEARPRIORITIES:
 1335     case _VIOC_WAITFOREVER:
 1336     case _VIOC_GETPATH:
 1337     case _VIOC_TRUNCATELOG:
 1338     case _VIOC_DISCONNECT:
 1339     case _VIOC_RECONNECT:
 1340     case _VIOC_LISTCACHE:
 1341     case _VIOC_GET_MT_PT:
 1342     case _VIOC_WD_ALL:
 1343     case _VIOC_SYNCCACHE_ALL:
 1344     case _VIOC_UNLOADKERNEL:
 1345     case _VIOC_LOOKASIDE:
 1346         {
 1347         switch(nr) {
 1348                 case _VIOC_LOOKASIDE:
 1349                 {
 1350               /* cache lookaside command (cfs lka) */
 1351               memset(data->out, 0, CFS_PIOBUFSIZE);
 1352               LKParseAndExecute((char *)data->in,  
 1353                                   (char *)data->out, CFS_PIOBUFSIZE-1);
 1354               data->out_size = strlen(data->out) + 1; 
 1355               break; /* outmsg has success/failure info */
 1356 
 1357                 }
 1358         case _VIOC_LISTCACHE:
 1359                 {
 1360               /* List cache status */
 1361               struct listcache_in {
 1362             char fname[23];     /* "/tmp/_Venus_List_Cache" */
 1363             int  first_volume;
 1364             int  long_format;
 1365             int  valid;
 1366               } *data_in;
 1367 
 1368               data_in = (struct listcache_in *)data->in;
 1369               char *venus_file = data_in->fname;
 1370 
 1371               FILE *fp;
 1372               if (data_in->first_volume)
 1373             fp = fopen(venus_file, "w+");
 1374               else
 1375             fp = fopen(venus_file, "a+");
 1376               if (fp == NULL) {
 1377             MarinerLog("Cannot open file: %s\n", venus_file);
 1378             u.u_error = errno;
 1379             break;
 1380               }
 1381               VDB->ListCache(fp, data_in->long_format, data_in->valid);
 1382               fflush(fp);
 1383               fclose(fp);
 1384               if ( chmod(venus_file, 00666) < 0 ) {
 1385             MarinerLog("Cannot chmod file: %s\n", venus_file);
 1386             u.u_error = errno;
 1387               }
 1388               break;
 1389             }
 1390         case _VIOC_GET_MT_PT:
 1391                 {
 1392               /* Get mount point pathname */
 1393               if (data->in_size < (int)sizeof(VolumeId) + 1) {
 1394             u.u_error = EINVAL; break;
 1395               }
 1396               Volid volid;
 1397 
 1398               Realm *r = REALMDB->GetRealm((char *)data->in +
 1399                            sizeof(VolumeId));
 1400               volid.Realm = r->Id();
 1401               r->PutRef();
 1402 
 1403               volid.Volume = *(VolumeId *)data->in;
 1404               volent *vv = VDB->Find(&volid);
 1405               if (!vv) {
 1406             MarinerLog("Could not find volume = %x.%x\n",
 1407                    volid.Realm, volid.Volume);
 1408             u.u_error = EINVAL;
 1409             break;
 1410               }
 1411               vv->GetMountPath((char *)data->out, 0);
 1412               vv->release();
 1413               if (STREQ((char *)data->out, "???")) {
 1414             MarinerLog("Could not get mount point path for %x.%x\n",
 1415                    volid.Realm, volid.Volume);
 1416             u.u_error = EINVAL;
 1417             break;
 1418               }
 1419               data->out_size = (short) strlen((char *)data->out)+1;
 1420               break;
 1421             }
 1422         
 1423         case _VIOCSETTOK:
 1424             {
 1425             /* Format of data is (len, secret, len, clear) */
 1426             char *startp = (char *) data->in;
 1427 #define secretlen ((uint32_t *)(startp))
 1428 #define secretp ((SecretToken *)(secretlen + 1))
 1429 #define clearlen ((uint32_t *)(secretp + 1))
 1430 #define clearp ((ClearToken *)(clearlen + 1))
 1431 #define realmp ((char *)(clearp + 1))
 1432 /*
 1433             if (*secretlen != (int)sizeof(SecretToken) ||
 1434             *clearlen != (int)sizeof(ClearToken))
 1435             { u.u_error = EINVAL; break; }
 1436 */
 1437             Realm *realm = REALMDB->GetRealm(realmp);
 1438 
 1439             u.u_error = realm->NewUserToken(u.u_uid, secretp, clearp);
 1440             if (!u.u_error) {
 1441             connent *c = NULL;
 1442             /* attempt to trigger reintegration */
 1443             realm->GetAdmConn(&c);
 1444             PutConn(&c);
 1445             }
 1446             realm->PutRef();
 1447 #undef  secretlen
 1448 #undef  secretp
 1449 #undef  clearlen
 1450 #undef  clearp
 1451 #undef  realmp
 1452             break;
 1453             }
 1454 
 1455         case _VIOCGETTOK:
 1456             {
 1457             /* Format of data is (len, secret, len, clear) */
 1458             char *startp = (char *) data->out;
 1459 #define secretlen ((uint32_t *)(startp))
 1460 #define secretp ((SecretToken *)(secretlen + 1))
 1461 #define clearlen ((uint32_t *)(secretp + 1))
 1462 #define clearp ((ClearToken *)(clearlen + 1))
 1463 #define endp ((char *)(clearp + 1)) 
 1464             Realm *realm = REALMDB->GetRealm(data->in);
 1465             userent *ue = realm->GetUser(u.u_uid);     
 1466             u.u_error = ue->GetTokens(secretp, clearp);
 1467             PutUser(&ue);
 1468             realm->PutRef();
 1469             if (u.u_error) break;
 1470 
 1471             *secretlen = (int)sizeof(SecretToken);
 1472             *clearlen = (int)sizeof(ClearToken);
 1473             data->out_size = (short)(endp - startp);
 1474 #undef  secretlen
 1475 #undef  secretp
 1476 #undef  clearlen
 1477 #undef  clearp
 1478 #undef  endp
 1479             break;
 1480             }
 1481 
 1482         case _VIOCUNLOG:
 1483             {
 1484             Realm *realm = REALMDB->GetRealm(data->in);
 1485             userent *ue = realm->GetUser(u.u_uid);
 1486             ue->Invalidate();
 1487             FSDB->ResetUser(u.u_uid);
 1488             PutUser(&ue);
 1489             realm->PutRef();
 1490 
 1491             break;
 1492             }
 1493 
 1494         case _VIOCCKSERV:
 1495             {
 1496             unsigned int bufsize = 2048; /* XXX - IN/OUT parameter. */
 1497             if (data->in_size == 0) {    /* probe everybody we know */
 1498             ServerProbe();
 1499             DownServers((char *) data->out, &bufsize);
 1500             } else {
 1501             /* probe only those listed. */
 1502             /* format is #hosts, hostaddr, hostaddr, ... */
 1503 #define nservers ((int *)(data->in))
 1504 #define hostids ((struct in_addr *)(nservers + 1))
 1505             DoProbes(*nservers, hostids);
 1506             DownServers(*nservers, hostids, (char *) data->out, &bufsize);
 1507 #undef nservers
 1508 #undef hostids
 1509             }
 1510             data->out_size = bufsize;
 1511             break;
 1512             }
 1513 
 1514         case _VIOCCKBACK:
 1515 /*      case _VIOCCKVOLS:*/
 1516             {
 1517 /*          VDB->CheckVolumes();*/
 1518             FSDB->InvalidateMtPts();
 1519 
 1520             break;
 1521             }
 1522 
 1523         case _VIOC_VENUSLOG:
 1524             {
 1525             if (u.u_uid != V_UID)
 1526             { u.u_error = EACCES; break; }
 1527 
 1528             uint32_t on;
 1529             memcpy(&on, data->in, sizeof(uint32_t));
 1530             on &= 0xff;
 1531             if (on) DebugOn(); else DebugOff();
 1532 
 1533             break;
 1534             }
 1535 
 1536         case _VIOC_GETVENUSSTATS:
 1537             {
 1538             if (sizeof(VenusStatistics) > VC_MAXDATASIZE)
 1539             { u.u_error = EINVAL; break; }
 1540 
 1541             VenusStatistics *Stats = (VenusStatistics *)data->out;
 1542             memset((void *)Stats, 0, (int)sizeof(VenusStatistics));
 1543             Stats->VFSStats = VFSStats;
 1544             Stats->CommStats.RPCOpStats = RPCOpStats;
 1545             GetCSS(&Stats->CommStats.RPCPktStats);
 1546 
 1547             data->out_size = (short)sizeof(VenusStatistics);
 1548             break;
 1549             }
 1550 
 1551         case _VIOC_FLUSHCACHE:
 1552             {
 1553             /* This is drastic, but I'm having trouble getting rid of */
 1554             /* MiniCache vnodes that have the "wrong" type! -JJK */
 1555             (void)k_Purge();
 1556 
 1557             FSDB->Flush();
 1558             Recov_SetBound(DMFP);
 1559 
 1560             break;
 1561             }
 1562 
 1563         case _VIOC_HDB_ADD:
 1564             {
 1565             struct hdb_add_msg *msgp = (struct hdb_add_msg *)data->in;
 1566             if (data->in_size != (int)sizeof(struct hdb_add_msg))
 1567             { u.u_error = EINVAL; break; }
 1568 
 1569             u.u_error = HDBD_Request(HdbAdd, msgp, &u);
 1570 
 1571             break;
 1572             }
 1573 
 1574         case _VIOC_HDB_DELETE:
 1575             {
 1576             struct hdb_delete_msg *msgp = (struct hdb_delete_msg *)data->in;
 1577             if (data->in_size != (int)sizeof(struct hdb_delete_msg))
 1578             { u.u_error = EINVAL; break; }
 1579 
 1580             u.u_error = HDBD_Request(HdbDelete, msgp, &u);
 1581 
 1582             break;
 1583             }
 1584 
 1585         case _VIOC_HDB_CLEAR:
 1586             {
 1587             struct hdb_clear_msg *msgp = (struct hdb_clear_msg *)data->in;
 1588             if (data->in_size != (int)sizeof(struct hdb_clear_msg))
 1589             { u.u_error = EINVAL; break; }
 1590 
 1591             u.u_error = HDBD_Request(HdbClear, msgp, &u);
 1592 
 1593             break;
 1594             }
 1595 
 1596         case _VIOC_HDB_LIST:
 1597             {
 1598             struct hdb_list_msg *msgp = (struct hdb_list_msg *)data->in;
 1599             if (data->in_size != (int)sizeof(struct hdb_list_msg))
 1600             { u.u_error = EINVAL; break; }
 1601 
 1602             u.u_error = HDBD_Request(HdbList, msgp, &u);
 1603 
 1604             break;
 1605             }
 1606 
 1607         case _VIOC_HDB_WALK:
 1608             {
 1609             struct hdb_walk_msg *msgp = (struct hdb_walk_msg *)data->in;
 1610             if (data->in_size != (int)sizeof(struct hdb_walk_msg))
 1611             { u.u_error = EINVAL; break; }
 1612 
 1613             u.u_error = HDBD_Request(HdbWalk, msgp, &u);
 1614 
 1615             break;
 1616             }
 1617 
 1618 
 1619             case _VIOC_HDB_VERIFY:
 1620             {
 1621             struct hdb_verify_msg *msgp = (struct hdb_verify_msg *)data->in;            
 1622             if (data->in_size != (int)sizeof(struct hdb_verify_msg))
 1623             { u.u_error = EINVAL; break; }
 1624 
 1625             u.u_error = HDBD_Request(HdbVerify, msgp, &u);
 1626 
 1627             break;
 1628             }
 1629 
 1630         case _VIOC_HDB_ENABLE:
 1631             {
 1632             struct hdb_walk_msg *msgp = (struct hdb_walk_msg *)data->in;
 1633             if (data->in_size != (int)sizeof(struct hdb_walk_msg))
 1634             { u.u_error = EINVAL; break; }
 1635 
 1636             u.u_error = HDBD_Request(HdbEnable, msgp, &u);
 1637 
 1638             break;
 1639             }
 1640             
 1641         case _VIOC_HDB_DISABLE:
 1642             {
 1643             struct hdb_walk_msg *msgp = (struct hdb_walk_msg *)data->in;
 1644             if (data->in_size != (int)sizeof(struct hdb_walk_msg))
 1645             { u.u_error = EINVAL; break; }
 1646 
 1647             u.u_error = HDBD_Request(HdbDisable, msgp, &u);
 1648 
 1649             break;
 1650             }
 1651             
 1652         case _VIOC_CLEARPRIORITIES:
 1653             {
 1654             FSDB->ClearPriorities();
 1655 
 1656             break;
 1657             }
 1658 
 1659         case _VIOC_WAITFOREVER:
 1660             {
 1661             int on;
 1662             memcpy(&on, data->in, sizeof(int));
 1663 
 1664             /* We would like "waitforever" behavior to be settable on a
 1665              * per-process group basis. However, this would require
 1666              * cooperation with the kernel, which I don't want to mess
 1667              * with now.  So instead, we will set it on a per-user
 1668              * basis (at least for now). */
 1669             Realm *realm = REALMDB->GetRealm((char *)data->in+sizeof(int));
 1670             userent *ue = realm->GetUser(u.u_uid);
 1671             ue->SetWaitForever(on);
 1672             PutUser(&ue);
 1673             realm->PutRef();
 1674 
 1675             break;
 1676             }
 1677 
 1678         case _VIOC_GETPATH:
 1679             {
 1680             if (data->in_size <= sizeof(VenusFid) || 
 1681             *((char *)data->in + data->in_size - 1) != '\0')
 1682             { u.u_error = EINVAL; break; }
 1683 
 1684             ViceFid fid;
 1685             memcpy(&fid, data->in, sizeof(ViceFid));
 1686             char *realmname = (char *)data->in + sizeof(ViceFid);
 1687             Realm *realm = REALMDB->GetRealm(realmname);
 1688 
 1689             int out_size = CODA_MAXPATHLEN;     /* needed since data->out_size is a short! */
 1690             VenusFid vfid;
 1691             MakeVenusFid(&vfid, realm->Id(), &fid);
 1692 
 1693             GetPath(&vfid, (char *) data->out, &out_size, 1);
 1694 
 1695             data->out_size = out_size;
 1696 
 1697             realm->PutRef();
 1698 
 1699             break;
 1700             }
 1701 
 1702             case _VIOC_TRUNCATELOG:
 1703             {
 1704             RecovFlush(1);
 1705             RecovTruncate(1);
 1706 
 1707             break;
 1708             }
 1709 
 1710             case _VIOC_DISCONNECT:
 1711             {
 1712             if (data->in_size == 0)  /* disconnect from everyone */
 1713                 u.u_error = FailDisconnect(0,0);
 1714             else
 1715 #define nservers ((int *)(data->in))
 1716 #define hostids ((struct in_addr *)(nservers + 1))
 1717                 u.u_error = FailDisconnect(*nservers, hostids);
 1718 #undef nservers
 1719 #undef hostids
 1720             if (u.u_error < 0) u.u_error = EINVAL; /* fail returns -1 */
 1721             break;
 1722             }
 1723 
 1724             case _VIOC_RECONNECT:
 1725             {
 1726             if (data->in_size == 0)  /* reconnect to everyone */
 1727                 u.u_error = FailReconnect(0,0);
 1728             else
 1729 #define nservers ((int *)(data->in))
 1730 #define hostids ((struct in_addr *)(nservers + 1))
 1731                 u.u_error = FailReconnect(*nservers, hostids);
 1732 #undef nservers
 1733 #undef hostids
 1734             if (u.u_error < 0) u.u_error = EINVAL; /* fail returns -1 */
 1735 
 1736             break;
 1737             }
 1738 
 1739         case _VIOC_WD_ALL:
 1740             {
 1741             char *startp = (char *) data->in;
 1742 #define agep ((unsigned int *)(startp))
 1743 #define timep ((unsigned int *)(agep + 1))
 1744             u.u_error = VDB->WriteDisconnect(*agep, *timep);
 1745             break;
 1746             }
 1747         case _VIOC_SYNCCACHE_ALL:
 1748             {
 1749             u.u_error = VDB->SyncCache();
 1750             break;
 1751             }
 1752         }
 1753         }
 1754         if (u.u_error == ERETRY)
 1755         u.u_error = EWOULDBLOCK;
 1756         return;
 1757 
 1758     default:
 1759         u.u_error = EOPNOTSUPP;
 1760         return;
 1761     }
 1762 }