"Fossies" - the Fresh Open Source Software Archive

Member "coda-6.9.5/coda-src/vice/srvproc2.cc" (27 Jul 2009, 29991 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 "srvproc2.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 
   16 #*/
   17 
   18 /*
   19                          IBM COPYRIGHT NOTICE
   20 
   21                           Copyright (C) 1986
   22              International Business Machines Corporation
   23                          All Rights Reserved
   24 
   25 This  file  contains  some  code identical to or derived from the 1986
   26 version of the Andrew File System ("AFS"), which is owned by  the  IBM
   27 Corporation.   This  code is provided "AS IS" and IBM does not warrant
   28 that it is free of infringement of  any  intellectual  rights  of  any
   29 third  party.    IBM  disclaims  liability of any kind for any damages
   30 whatsoever resulting directly or indirectly from use of this  software
   31 or  of  any  derivative work.  Carnegie Mellon University has obtained
   32 permission to  modify,  distribute and sublicense this code,  which is
   33 based on Version 2  of  AFS  and  does  not  contain  the features and
   34 enhancements that are part of  Version 3 of  AFS.  Version 3 of AFS is
   35 commercially   available   and  supported  by   Transarc  Corporation,
   36 Pittsburgh, PA.
   37 
   38 */
   39 
   40 
   41 
   42 #ifdef __cplusplus
   43 extern "C" {
   44 #endif
   45 
   46 #ifdef HAVE_CONFIG_H
   47 #include <config.h>
   48 #endif
   49 
   50 #include <sys/types.h>
   51 #include <sys/time.h>
   52 #include <sys/resource.h>
   53 #include <netinet/in.h>
   54 #include <sys/ioctl.h>
   55 #include <sys/socket.h>
   56 #include <net/if.h>
   57 #ifdef __linux__
   58 #include <linux/if_ether.h>
   59 #endif
   60 
   61 #include "coda_string.h"
   62 #include <unistd.h>
   63 #include <stdlib.h>
   64 #include <fcntl.h>
   65 
   66 #include <lwp/lwp.h>
   67 #include <lwp/lock.h>
   68 #include <rpc2/rpc2.h>
   69 #include <rpc2/errors.h>
   70 #include <util.h>
   71 #include <rvmlib.h>
   72 #include <partition.h>
   73 #include <auth2.h>
   74 #include <prs.h>
   75 #include <al.h>
   76 #include <callback.h>
   77 #include <vice.h>
   78 #include "coda_flock.h"
   79 
   80 #ifdef __cplusplus
   81 }
   82 #endif
   83 
   84 #include <voltypes.h>
   85 #include <vrdb.h>
   86 #include <vldb.h>
   87 #include <volume.h>
   88 #include <srv.h>
   89 #include <volume.h>
   90 #include <vlist.h>
   91 #include <vice.private.h>
   92 #include <operations.h>
   93 #include <ops.h>
   94 #include <lockqueue.h>
   95 #include <vice_file.h>
   96 #include "coppend.h"
   97 
   98 /* *****  Exported variables  ***** */
   99 
  100 unsigned int etherWrites = 0;
  101 unsigned int etherRetries = 0;
  102 unsigned int etherInterupts = 0;
  103 unsigned int etherGoodReads = 0;
  104 unsigned int etherBytesRead = 0;
  105 unsigned int etherBytesWritten = 0;
  106 
  107 /* *****  External routines ***** */
  108 extern int ValidateParms(RPC2_Handle, ClientEntry **, int *ReplicatedOp,
  109              VolumeId *, RPC2_CountedBS *, int *Nservers);
  110 /* *****  Private routines  ***** */
  111 
  112 static void SetVolumeStatus(VolumeStatus *, RPC2_BoundedBS *,
  113                   RPC2_BoundedBS *, RPC2_BoundedBS *, Volume *);
  114 static void SetViceStats(ViceStatistics *);
  115 static void SetRPCStats(ViceStatistics *);
  116 static void SetVolumeStats(ViceStatistics *);
  117 static void SetSystemStats(ViceStatistics *);
  118 static void PrintVolumeStatus(VolumeStatus *);
  119 
  120 
  121 /*
  122   ViceDisconnectFS: Client request for termination
  123 */
  124 long FS_ViceDisconnectFS(RPC2_Handle RPCid)
  125 {
  126     ClientEntry *client = 0;
  127     long   errorCode;
  128     char *rock;
  129 
  130     SLog(1, "ViceDisconnectFS");
  131     errorCode = RPC2_GetPrivatePointer(RPCid, &rock);
  132     client = (ClientEntry *)rock;
  133 
  134     if (!errorCode && client) {
  135     struct Lock *lock = &client->VenusId->lock;
  136     ObtainWriteLock(lock);
  137     CLIENT_Delete(client);
  138     ReleaseWriteLock(lock);
  139     }
  140     else {
  141     SLog(0, "GetPrivate failed in Disconnect rc = %d, client = %d",
  142         errorCode, client);
  143     }
  144 
  145     SLog(2, "ViceDisconnectFS returns success");
  146     return(0);
  147 }
  148 
  149 /*
  150   TokenExpired: When the server detects token expiry between GetRequest
  151     and srv_ExecuteRequest, it converts the Header.Opcode into
  152     TokenExpired. This routine then returns an appropriate error to the
  153     client. (Ofcourse masochistic clients may call this routine
  154     themselves, and enjoy being thrown out :)
  155 */
  156 long FS_TokenExpired(RPC2_Handle RPCid)
  157 {
  158     ClientEntry *client = 0;
  159     long   errorCode;
  160     char *rock;
  161 
  162     SLog(100, "TokenExpired");
  163     errorCode = RPC2_GetPrivatePointer(RPCid, &rock);
  164     client = (ClientEntry *)rock;
  165 
  166     if (!errorCode && client) {
  167     ObtainWriteLock(&client->VenusId->lock);
  168     CLIENT_CleanUpHost(client->VenusId);
  169     ReleaseWriteLock(&client->VenusId->lock);
  170     }
  171 
  172     return(RPC2_NAKED);
  173 }
  174 
  175 long FS_ViceGetOldStatistics(RPC2_Handle RPCid, ViceStatistics *Statistics)
  176 {
  177     return(FS_ViceGetStatistics(RPCid, Statistics));
  178 }
  179 
  180 /* ViceGetStatistics: Used by filestats to get general file server statistics */
  181 long FS_ViceGetStatistics(RPC2_Handle RPCid, ViceStatistics *Statistics)
  182 {
  183     int     errorCode;      /* return code for caller */
  184 
  185     SLog(3, "ViceGetStatistics Received");
  186 
  187     errorCode = 0;
  188 
  189     memset(Statistics, 0, sizeof(ViceStatistics));
  190 
  191     SetViceStats(Statistics);
  192     SetRPCStats(Statistics);
  193     SetVolumeStats(Statistics);
  194     SetSystemStats(Statistics);
  195 
  196     SLog(3, "ViceGetStatistics returns %s", ViceErrorMsg(errorCode));
  197     return(errorCode);
  198 }
  199 
  200 static const char *GetROOTVOLUME(void)
  201 {
  202     static char rootvolume[V_MAXVOLNAMELEN];
  203     int fd, len;
  204 
  205     fd = open(vice_sharedfile("db/ROOTVOLUME"), O_RDONLY);
  206     if (fd < 0)
  207     return NULL;
  208 
  209     len = read(fd, rootvolume, V_MAXVOLNAMELEN-1);
  210     close(fd);
  211     if (len <= 0)
  212     return NULL;
  213 
  214     if (rootvolume[len-1] == '\n') len--;
  215     rootvolume[len] = '\0';
  216 
  217     return rootvolume;
  218 }
  219 
  220 /*
  221   ViceGetVolumeInfo: Used to get information about a particular volume
  222 */
  223 long FS_ViceGetVolumeInfo(RPC2_Handle RPCid, RPC2_String VolName, VolumeInfo *Info)
  224 {
  225     SLog(1,"ViceGetVolumeInfo volume = %s", VolName);
  226 
  227     int errorCode = 0;      /* error code */
  228     vrent *vre;
  229     
  230     if (VolName[0] == '\0' || (VolName[0] == '/' && VolName[1] == '\0')) {
  231     const char *rootvol = GetROOTVOLUME();
  232     if (rootvol)
  233         VolName = (RPC2_String)rootvol;
  234     }
  235 
  236     vre = VRDB.find((char *)VolName);
  237     if (!vre) {
  238     VolumeId Vid = strtol((char *)VolName, NULL, 0);
  239     if (Vid) vre = VRDB.find(Vid);
  240     }
  241     if (vre)
  242     errorCode = vre->GetVolumeInfo(Info);
  243     else {
  244     VGetVolumeInfo((Error *)&errorCode, (char *)VolName, Info);
  245 
  246     if (errorCode == 0) {
  247         if (Info->Type == ROVOL) {
  248         SLog(0, "GetVolumeInfo called for ROVOL");
  249         Info->VSGAddr = 0;
  250         } else if (Info->Type == RWVOL) {
  251         /* Stuff the GroupId in the Info->Type[REPVOL] field. */
  252         VolumeId Vid = Info->Vid;
  253         if (ReverseXlateVid(&Vid))
  254             (&(Info->Type0))[replicatedVolume] = Vid;
  255         }
  256     }
  257     }
  258 
  259     SLog(2, "ViceGetVolumeInfo returns %s, Volume %u, type %x, servers %x %x %x %x...",
  260         ViceErrorMsg(errorCode), Info->Vid, Info->Type,
  261         Info->Server0, Info->Server1, Info->Server2, Info->Server3);
  262     return(errorCode);
  263 }
  264 
  265 /*
  266 ViceGetVolumeLocation: Used to get the location (host:port) of a volume replica
  267 */
  268 long FS_ViceGetVolumeLocation(RPC2_Handle RPCid, VolumeId Vid,
  269                   RPC2_BoundedBS *HostPort)
  270 {
  271     const char *addr;
  272     size_t len;
  273     int err = 0;
  274 
  275     SLog(1,"ViceGetVolumeLocation volume = %08x", Vid);
  276     HostPort->SeqLen = 0;
  277 
  278     addr = VGetVolumeLocation(Vid);
  279     if (!addr) {
  280     /* do we need more detailed errors? VNOVOL/ISREPLICATED/EWOULDBENICE? */
  281     err = VNOSERVICE;
  282     goto errout;
  283     }
  284 
  285     len = strlen(addr);
  286     if (len >= HostPort->MaxSeqLen) {
  287     err = ENAMETOOLONG;
  288     goto errout;
  289     }
  290 
  291     strcpy((char *)HostPort->SeqBody, addr);
  292     HostPort->SeqLen = len;
  293 
  294 errout:
  295     SLog(2, "ViceGetVolumeLocation: Volume %08x, location %s, err %s",
  296      Vid, addr ? addr : "", ViceErrorMsg(err));
  297     return(err);
  298 }
  299 
  300 
  301 /*
  302   ViceGetVolumeStatus: Get the status of a particular volume
  303 */
  304 long FS_ViceGetVolumeStatus(RPC2_Handle RPCid, VolumeId vid, VolumeStatus *status, RPC2_BoundedBS *name, RPC2_BoundedBS *offlineMsg, RPC2_BoundedBS *motd, RPC2_Unsigned PrimaryHost)
  305 {
  306     Vnode * vptr;       /* vnode of the new file */
  307     ViceFid vfid;       /* fid of new file */
  308     long   errorCode;       /* error code */
  309     Error   fileCode;       /* used when writing Vnodes */
  310     Volume * volptr;        /* pointer to the volume header */
  311     AL_AccessList * aCL;    /* access list */
  312     ClientEntry * client;   /* pointer to client entry */
  313     int     aCLSize;
  314     int     rights;
  315     int     anyrights;
  316     char *rock;
  317 
  318     errorCode = fileCode = 0;
  319     vptr = 0;
  320     volptr = 0;
  321     VolumeId VSGVolnum = vid;
  322 
  323     SLog(1,"GetVolumeStatus for volume %u",vid);
  324 
  325     if (vid == 0) {
  326     errorCode = EINVAL;
  327     goto Final;
  328     }
  329 
  330     if (XlateVid(&vid)) {
  331     SLog(1, "XlateVid: %u --> %u", VSGVolnum, vid);
  332     if (PrimaryHost == 0) {
  333         SLog(0, "Translated VSG but PrimaryHost == 0");
  334         errorCode = EINVAL;     /* ??? -JJK */
  335         goto Final;
  336     }
  337     }
  338     else {
  339     if (PrimaryHost != 0) {
  340         SLog(0, "Failed to translate VSG but PrimaryHost != 0");
  341         errorCode = EINVAL;     /* ??? -JJK */
  342         goto Final;
  343     }
  344     }
  345 
  346     if( name->MaxSeqLen < V_MAXVOLNAMELEN || offlineMsg->MaxSeqLen < VMSGSIZE ||
  347         motd->MaxSeqLen < VMSGSIZE) {
  348     errorCode = EINVAL;
  349     goto Final;
  350     }
  351 
  352     vfid.Volume = vid;
  353     vfid.Vnode = ROOTVNODE;
  354     vfid.Unique = 1;
  355 
  356     // get the root vnode even if it is inconsistent
  357     if ((errorCode = GetFsObj(&vfid, &volptr, &vptr,
  358                  READ_LOCK, VOL_NO_LOCK, 1, 0, 0))) {
  359     goto Final;
  360     }
  361 
  362     SetAccessList(vptr, aCL, aCLSize);
  363 
  364     if((errorCode = RPC2_GetPrivatePointer(RPCid, &rock)) != RPC2_SUCCESS)
  365     goto Final;
  366     client = (ClientEntry *)rock;
  367 
  368     if(!client) {
  369     errorCode = EFAULT;
  370     SLog(0, "Client pointer zero in GetVolumeStatus");
  371     goto Final;
  372     }
  373 
  374     CODA_ASSERT(GetRights(client->CPS, aCL, aCLSize, (Rights *)&rights, (Rights *)&anyrights) == 0);
  375 
  376     if(!(rights & PRSFS_READ) && !SystemUser(client)) {
  377     errorCode = EACCES;
  378     goto Final;
  379     }
  380 
  381     SetVolumeStatus(status, name, offlineMsg, motd, volptr);
  382 
  383  Final:
  384     if (vptr) {
  385     VPutVnode(&fileCode, vptr);
  386     CODA_ASSERT(fileCode == 0);
  387     }
  388     PutVolObj(&volptr, VOL_NO_LOCK, 0);
  389 
  390     SLog(2,"GetVolumeStatus returns %s", ViceErrorMsg((int) errorCode));
  391     if(!errorCode) {
  392     SLog(5,"Name = %s, Motd = %s, offMsg = %s",
  393         name->SeqBody, motd->SeqBody, offlineMsg->SeqBody);
  394     PrintVolumeStatus(status);
  395     }
  396     return(errorCode);
  397 }
  398 
  399 
  400 void PerformSetQuota(ClientEntry *client, VolumeId VSGVolnum, Volume *volptr, Vnode *vptr, ViceFid *fid, int NewQuota, int ReplicatedOp, ViceStoreId *StoreId)
  401 {
  402     CodaBreakCallBack((client ? client->VenusId : 0), fid, VSGVolnum);
  403 
  404     V_maxquota(volptr) = NewQuota;
  405 
  406     if (ReplicatedOp)
  407     NewCOP1Update(volptr, vptr, StoreId);
  408 
  409     /* Await COP2 message. */
  410     if (ReplicatedOp) {
  411     ViceFid fids[MAXFIDS];
  412     memset((void *)fids, 0, (int)(MAXFIDS * sizeof(ViceFid)));
  413     fids[0] = *fid;
  414     CopPendingMan->add(new cpent(StoreId, fids));
  415     }
  416 }
  417 
  418 
  419 
  420 /*
  421   BEGIN_HTML
  422   <a name="ViceSetVolumeStatus"><strong>Set the status(e.g. quota) for a volume </strong></a>
  423   END_HTML
  424 */
  425 long FS_ViceSetVolumeStatus(RPC2_Handle RPCid, VolumeId vid, VolumeStatus *status, RPC2_BoundedBS *name, RPC2_BoundedBS *offlineMsg, RPC2_BoundedBS *motd, RPC2_Unsigned PrimaryHost, ViceStoreId *StoreId, RPC2_CountedBS *PiggyCOP2)
  426 {
  427     ViceFid vfid;       /* fid of new file */
  428     long   errorCode;       /* error code */
  429     Error   fileCode;       /* used when writing Vnodes */
  430     Volume * volptr;        /* pointer to the volume header */
  431     AL_AccessList * aCL;    /* access list */
  432     ClientEntry * client;   /* pointer to client entry */
  433     int     aCLSize;
  434     int     rights;
  435     int     anyrights;
  436     int oldquota = -1;               /* Old quota if it was changed */
  437     int ReplicatedOp;
  438     vle *v = 0;
  439     dlist *vlist = new dlist((CFN)VLECmp);
  440 
  441     errorCode = fileCode = 0;
  442     volptr = 0;
  443     VolumeId VSGVolnum = vid;
  444 
  445     SLog(1,"ViceSetVolumeStatus for volume %u", vid);
  446     SLog(5,"Min = %d Max = %d, Name = %d.%d %s, Offline Msg = %d.%d.%s, motd = %d.%d.%s",
  447         status->MinQuota, status->MaxQuota,
  448         name->MaxSeqLen, name->SeqLen, name->SeqBody,
  449         offlineMsg->MaxSeqLen, offlineMsg->SeqLen, offlineMsg->SeqBody,
  450         motd->MaxSeqLen, motd->SeqLen, motd->SeqBody);
  451 
  452     /* Validate parameters. */
  453 
  454     if (vid == 0) {
  455     errorCode = EINVAL;
  456     goto Final;
  457     }
  458 
  459     {
  460     if ((errorCode = ValidateParms(RPCid, &client, &ReplicatedOp, &vid,
  461                       PiggyCOP2, NULL)))
  462         goto Final;
  463     }
  464 
  465     if( name->MaxSeqLen < V_MAXVOLNAMELEN || name->SeqLen > V_MAXVOLNAMELEN) {
  466     errorCode = EINVAL;
  467     goto Final;
  468     }
  469 
  470     if( offlineMsg->MaxSeqLen < VMSGSIZE || motd->MaxSeqLen < VMSGSIZE) {
  471     errorCode = EINVAL;
  472     goto Final;
  473     }
  474 
  475     if( offlineMsg->SeqLen > VMSGSIZE || motd->SeqLen > VMSGSIZE) {
  476     errorCode = EINVAL;
  477     goto Final;
  478     }
  479 
  480 
  481     vfid.Volume = vid;
  482     vfid.Vnode = ROOTVNODE;
  483     vfid.Unique = 1;
  484 
  485     if ((errorCode = GetVolObj(vid, &volptr, VOL_EXCL_LOCK, 0, 1 /* check this */))) {
  486     SLog(0, "Error locking volume in ViceSetVolumeStatus: %s", ViceErrorMsg((int) errorCode));
  487     goto Final ;
  488     }
  489 
  490 
  491     v = AddVLE(*vlist, &vfid);
  492     if ((errorCode = GetFsObj(&vfid, &volptr, &v->vptr, READ_LOCK,
  493                  VOL_NO_LOCK, 0, 0, 0))) {
  494     goto Final;
  495     }
  496 
  497     SetAccessList(v->vptr, aCL, aCLSize);
  498 
  499     if(!client) {
  500     errorCode = EFAULT;
  501     SLog(0, "Client pointer is zero in ViceSetVolumeStatus");
  502     goto Final;
  503     }
  504 
  505     CODA_ASSERT(GetRights(client->CPS, aCL, aCLSize, (Rights *)&rights, (Rights *)&anyrights) == 0);
  506 
  507     if (!SystemUser(client)) {
  508     errorCode = EACCES;
  509     goto Final;
  510     }
  511 
  512     if (status->MinQuota > -1)
  513     V_minquota(volptr) = (int) status->MinQuota;
  514 
  515     if(status->MaxQuota > -1) {
  516         oldquota = V_maxquota(volptr);
  517     PerformSetQuota(client, VSGVolnum, volptr, v->vptr, &vfid,
  518             (int)status->MaxQuota, ReplicatedOp, StoreId);
  519     }
  520 
  521     if(offlineMsg->SeqLen > 1)
  522     strcpy(V_offlineMessage(volptr), (char *)offlineMsg->SeqBody);
  523 
  524     if(name->SeqLen > 1)
  525     strcpy(V_name(volptr), (char *)name->SeqBody);
  526 
  527     if(motd->SeqLen > 1)
  528     strcpy(V_motd(volptr), (char *)motd->SeqBody);
  529 
  530     // Only spool a log entry if the quota was set.
  531     if (oldquota > -1)
  532     if (ReplicatedOp && !errorCode) {
  533         SLog(1, "ViceSetVolumeStatus: About to spool log record, oldquota = %d, new quota = %d\n", oldquota, status->MaxQuota);
  534         if ((errorCode = SpoolVMLogRecord(vlist, v, volptr, StoreId,
  535                          ViceSetVolumeStatus_OP, oldquota,
  536                          status->MaxQuota)))
  537         SLog(0, "ViceSetVolumeStatus: Error %d during SpoolVMLogRecord\n", errorCode);
  538     }
  539 
  540  Final:
  541 
  542     if (!errorCode)
  543         SetVolumeStatus(status, name, offlineMsg, motd, volptr);
  544 
  545     PutObjects((int) errorCode, volptr, VOL_EXCL_LOCK, vlist, 0, 1, TRUE);
  546 
  547     SLog(2,"ViceSetVolumeStatus returns %s", ViceErrorMsg((int) errorCode));
  548     if(!errorCode) {
  549     SLog(5,"Name = %s, Motd = %s, offMsg = %s",
  550         name->SeqBody, motd->SeqBody, offlineMsg->SeqBody);
  551     PrintVolumeStatus(status);
  552     }
  553     return(errorCode);
  554 }
  555 
  556 
  557 #define DEFAULTVOLUME "/"
  558 /*
  559   ViceGetRootVolume: Return the name of the root volume
  560   (corresponding to /coda/<realm>/)
  561 */
  562 long FS_ViceGetRootVolume(RPC2_Handle RPCid, RPC2_BoundedBS *volume)
  563 {
  564     SLog(1, "ViceGetRootVolume");
  565 
  566     if ((unsigned int)volume->MaxSeqLen <= strlen(DEFAULTVOLUME))
  567     {
  568     volume->SeqLen = 0;
  569     SLog(1, "ViceGetRootVolume: not enough space in query");
  570     return VNOVOL;
  571     }
  572 
  573     strcpy((char *)volume->SeqBody, DEFAULTVOLUME);
  574     volume->SeqLen = strlen(DEFAULTVOLUME) + 1;
  575 
  576     return 0;
  577 }
  578 
  579 
  580 /* ViceSetRootVolume: Set the .../db/ROOTVOLUME file to contain the
  581   name of the new root volume */
  582 long FS_ViceSetRootVolume(RPC2_Handle RPCid, RPC2_String volume)
  583 {
  584     long errorCode = 0;
  585     ClientEntry * client;   /* pointer to client entry */
  586     int fd, rc, len;
  587     char *rock;
  588 
  589     SLog(1,"ViceSetRootVolume to %s", (char *)volume);
  590 
  591     errorCode = RPC2_GetPrivatePointer(RPCid, &rock);
  592     if (errorCode != RPC2_SUCCESS)
  593     goto exit;
  594     client = (ClientEntry *)rock;
  595 
  596     if (!client) {
  597     errorCode = EFAULT;
  598     SLog(0, "Client pointer is zero in SetRootVolume");
  599     goto exit;
  600     }
  601 
  602     if (!SystemUser(client)) {
  603     errorCode = EACCES;
  604     goto exit;
  605     }
  606 
  607     fd = open(vice_sharedfile("db/ROOTVOLUME.new"), O_WRONLY|O_CREAT|O_EXCL, 0644);
  608     if (fd < 0) {
  609     errorCode = errno;
  610     SLog(0, "SetRootVolume failed to open ROOTVOLUME.new");
  611     goto exit;
  612     }
  613 
  614     len = strlen((char *)volume);
  615     rc = write(fd, (char *)volume, len);
  616     close(fd);
  617     if (rc != len) {
  618     errorCode = ENOSPC;
  619     SLog(0, "SetRootVolume failed to write ROOTVOLUME.new");
  620     goto exit;
  621     }
  622 
  623     rc = rename(vice_sharedfile("db/ROOTVOLUME.new"),
  624         vice_sharedfile("db/ROOTVOLUME"));
  625     if (rc == -1) {
  626     errorCode = errno;
  627     SLog(0, "SetRootVolume failed to rename ROOTVOLUME.new");
  628     }
  629 
  630 exit:
  631     SLog (2, "ViceSetRootVolume returns %s", ViceErrorMsg(errorCode));
  632     return errorCode;
  633 }
  634 
  635 
  636 /*
  637   ViceGetTime: Returns time of day (a time ping)
  638 */
  639 
  640 long FS_ViceGetTime(RPC2_Handle RPCid, RPC2_Unsigned *seconds, 
  641          RPC2_Integer *useconds)
  642 {
  643     struct timeval tpl;
  644     struct timezone tspl;
  645     ClientEntry *client = NULL;
  646     long errorCode;
  647     char *rock;
  648 
  649     TM_GetTimeOfDay(&tpl,&tspl);
  650     *seconds = tpl.tv_sec;
  651     *useconds = tpl.tv_usec;
  652 
  653     errorCode = RPC2_GetPrivatePointer(RPCid, &rock);
  654     client = (ClientEntry *)rock;
  655 
  656     if (errorCode || !client) { 
  657         SLog(0, "No client structure built by ViceNewConnection");
  658         return ENOTCONN;
  659     }
  660 
  661     SLog(1, "ViceGetTime for user %s at %s:%d on conn %d.",
  662          client->UserName, inet_ntoa(client->VenusId->host),
  663          ntohs(client->VenusId->port), RPCid);
  664     
  665     if (!errorCode && client) {
  666         /* we need a lock, because we cannot do concurrent RPC2 calls on
  667          * the same connection */
  668         ObtainWriteLock(&client->VenusId->lock);
  669 
  670         /* set up a callback channel if there isn't one for this host */
  671         if (client->VenusId->id != 0) {
  672         errorCode = CallBack(client->VenusId->id, (ViceFid *)&NullFid);
  673         if ( errorCode != RPC2_SUCCESS ) {
  674             SLog(0, "GetTime: Destroying callback conn for %s:%d",
  675              inet_ntoa(client->VenusId->host),
  676              ntohs(client->VenusId->port));
  677             /* tear down nak'd connection */
  678             RPC2_Unbind(client->VenusId->id);
  679             client->VenusId->id = 0;
  680         }
  681         }
  682 
  683         if (!client->VenusId->id && !client->DoUnbind) {
  684         SLog(0, "GetTime: Building callback conn to %s:%d.",
  685              inet_ntoa(client->VenusId->host),
  686              ntohs(client->VenusId->port));
  687         errorCode = CLIENT_MakeCallBackConn(client);
  688         }
  689         ReleaseWriteLock(&client->VenusId->lock);
  690     }
  691 
  692     SLog(2, "GetTime returns %d, %d, errorCode %d", 
  693          *seconds, *useconds, errorCode);
  694     
  695     return(errorCode);
  696 }
  697 
  698 
  699 /*
  700 ViceNewConnection: Called after a new bind request is received.
  701 */
  702 
  703 long FS_ViceNewConnection(RPC2_Handle RPCid, RPC2_Integer set, 
  704               RPC2_Integer sl,  RPC2_Integer et, 
  705               RPC2_Integer at, RPC2_CountedBS *cid)
  706 {
  707     char username[PRS_MAXNAMELEN+1] = NEWCONNECT;
  708     SecretToken *st = NULL;
  709     ClientEntry *client = NULL;
  710     long errorCode;
  711 
  712     if (sl == RPC2_OPENKIMONO) {
  713         strncpy(username, (char *)cid->SeqBody, PRS_MAXNAMELEN);
  714         username[PRS_MAXNAMELEN] = '\0';
  715     } else
  716         st = (SecretToken *)cid->SeqBody;
  717 
  718     errorCode = CLIENT_Build(RPCid, username, sl, st, &client);
  719     if (errorCode) {
  720         SLog(0,"New connection setup FAILED, RPCid %d, security level %d, "
  721            "remote cid %d returns %s",
  722          RPCid, sl, cid, ViceErrorMsg((int) errorCode));
  723         return (errorCode);
  724     }
  725     
  726     client->SEType = (int) set;
  727     SLog(1,"New connection received RPCid %d, security lvl %d, rem id %d",
  728          RPCid, sl, cid);
  729 
  730     return(0);
  731 }
  732 
  733 
  734 static void SetVolumeStatus(VolumeStatus *status, RPC2_BoundedBS *name, RPC2_BoundedBS *offMsg,
  735         RPC2_BoundedBS *motd, Volume *volptr)
  736 {
  737     status->Vid = V_id(volptr);
  738     status->ParentId = V_parentId(volptr);
  739     status->Online = V_inUse(volptr);
  740     status->InService = V_inService(volptr);
  741     status->Blessed = V_blessed(volptr);
  742     status->NeedsSalvage = V_needsSalvaged(volptr);
  743     if (VolumeWriteable(volptr))
  744     status->Type = ReadWrite;
  745     else
  746     status->Type = ReadOnly;
  747     status->MinQuota = V_minquota(volptr);
  748     status->MaxQuota = V_maxquota(volptr);
  749     status->BlocksInUse = V_diskused(volptr);
  750     status->PartBlocksAvail = volptr->partition->free;
  751     status->PartMaxBlocks = volptr->partition->totalUsable;
  752     strncpy((char *)name->SeqBody, V_name(volptr), (int)name->MaxSeqLen);
  753     name->SeqLen = strlen(V_name(volptr)) + 1;
  754     if(name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen;
  755     strncpy((char *)offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen);
  756     offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1;
  757     if(offMsg->SeqLen > offMsg->MaxSeqLen) offMsg->SeqLen = offMsg -> MaxSeqLen;
  758     strncpy((char *)motd->SeqBody, V_motd(volptr), (int)offMsg->MaxSeqLen);
  759     motd->SeqLen = strlen(V_motd(volptr)) + 1;
  760     if(motd->SeqLen > motd->MaxSeqLen) motd->SeqLen = motd -> MaxSeqLen;
  761 }
  762 
  763 
  764 static void SetViceStats(ViceStatistics *stats)
  765 {
  766     int seconds;
  767 
  768     /* FetchDataRate & StoreDataRate have wrap-around problems */
  769 
  770     stats->StartTime = StartTime;
  771     stats->CurrentConnections = CurrentConnections;
  772     stats->TotalViceCalls = Counters[TOTAL];
  773 
  774     stats->TotalFetches = Counters[GETATTRPLUSSHA]+Counters[GETATTR]+Counters[GETACL]+Counters[FETCH];
  775     stats->FetchDatas = Counters[FETCH];
  776     stats->FetchedBytes = Counters[FETCHDATA];
  777     seconds = Counters[FETCHTIME]/1000;
  778     if(seconds <= 0) seconds = 1;
  779     stats->FetchDataRate = Counters[FETCHDATA]/seconds;
  780 
  781     stats->TotalStores = Counters[SETATTR]+Counters[SETACL]+Counters[STORE];
  782     stats->StoreDatas = Counters[STORE];
  783     stats->StoredBytes = Counters[STOREDATA];
  784     seconds = Counters[STORETIME]/1000;
  785     if(seconds <= 0) seconds = 1;
  786     stats->StoreDataRate = Counters[STOREDATA]/seconds;
  787 
  788     CLIENT_GetWorkStats((int *)&(stats->WorkStations),
  789             (int *)&(stats->ActiveWorkStations),
  790             (unsigned)(time(0)-15*60));
  791 }
  792 
  793 
  794 static void SetRPCStats(ViceStatistics *stats)
  795 {
  796     /* get send/receive statistics from rpc, multirpc, and sftp */
  797     stats->TotalRPCBytesSent = rpc2_Sent.Bytes + rpc2_MSent.Bytes + 
  798         sftp_Sent.Bytes + sftp_MSent.Bytes;
  799     stats->TotalRPCBytesReceived = rpc2_Recvd.Bytes + rpc2_MRecvd.Bytes + 
  800         sftp_Recvd.Bytes + sftp_MRecvd.Bytes;
  801     stats->TotalRPCPacketsSent = rpc2_Sent.Total + rpc2_MSent.Total + 
  802         sftp_Sent.Total + sftp_MSent.Total;
  803     stats->TotalRPCPacketsReceived = rpc2_Recvd.Total + rpc2_MRecvd.Total + 
  804         sftp_Recvd.Total + sftp_MRecvd.Total;
  805 
  806     /* 
  807      * Retries and busies appear only in rpc2_Send and rpc2_Recvd, because
  808      * they aren't multicasted.
  809      * Sftp is harder -- retries occur because of packet loss _and_ timeouts.
  810      * Punt that.
  811      */
  812     stats->TotalRPCPacketsLost = rpc2_Sent.Retries - rpc2_Recvd.GoodBusies;
  813     stats->TotalRPCBogusPackets = rpc2_Recvd.Total + rpc2_MRecvd.Total - 
  814         rpc2_Recvd.GoodRequests - rpc2_Recvd.GoodReplies - 
  815             rpc2_Recvd.GoodBusies - rpc2_MRecvd.GoodRequests;
  816 
  817     stats->EtherNetTotalErrors = 0;
  818     stats->EtherNetTotalWrites = 0;
  819     stats->EtherNetTotalInterupts = 0;
  820     stats->EtherNetGoodReads = 0;
  821     stats->EtherNetTotalBytesWritten = 0;
  822     stats->EtherNetTotalBytesRead = 0;
  823 }
  824 
  825 
  826 int GetEtherStats()
  827 {
  828 return(0);
  829 }
  830 
  831 static struct DiskPartition *get_part(struct dllist_head *hd)
  832 {
  833     if ( hd == &DiskPartitionList )
  834         return NULL;
  835 
  836     return list_entry(hd, struct DiskPartition, dp_chain);
  837 }
  838 
  839 static void SetVolumeStats(ViceStatistics *stats)
  840 {
  841     struct DiskPartition *part;
  842     struct dllist_head *tmp;
  843     struct ViceDisk *disk; 
  844     int i;
  845 
  846     tmp = DiskPartitionList.next;
  847 
  848     for ( i = 0 ; i < 10 ; i++ ) {
  849         part = get_part(tmp);
  850         /* beware: pointer arithmetic */
  851         disk = &(stats->Disk1) + i;
  852         memset(disk, 0, sizeof(struct ViceDisk));
  853         if(part) {
  854             disk->TotalBlocks = part->totalUsable;
  855             disk->BlocksAvailable = part->free;
  856             strncpy((char *)disk->Name, part->name, V_MAXPARTNAMELEN-1);
  857             disk->Name[V_MAXPARTNAMELEN-1] = '\0';
  858             tmp = tmp->next;
  859         }
  860     }
  861 }
  862 
  863 #if defined(__FreeBSD__) || defined(__NetBSD__)
  864 
  865 #ifdef  __NetBSD__
  866 #define KERNEL "/netbsd"
  867 #else   /* __FreeBSD__ */
  868 #define KERNEL "/kernel"
  869 #endif
  870 
  871 #include <kvm.h>
  872 #include <sys/dkstat.h>
  873 #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104250000)
  874 #include <sys/sched.h>
  875 #endif
  876 #include <limits.h>
  877 
  878 static struct nlist RawStats[] = 
  879 {
  880 #define CPTIME  0
  881     {"_cp_time" },
  882 #define BOOT    1
  883     {"_boottime" },
  884 #define HZ  2
  885     {"_hz" },
  886     /* if we ever cared ... */
  887 #define DISK    3
  888     {"_disk_count" },
  889 #define DISKHD  4
  890     {"_disklist" },
  891     {0 },
  892 };
  893 
  894 static char kd_buf[_POSIX2_LINE_MAX];
  895 static void SetSystemStats_bsd44(ViceStatistics *stats)
  896 {
  897     static  kvm_t   *kd = (kvm_t *) NULL;
  898     static  int kd_opened = 0;
  899     register    int i;
  900     long    busy[CPUSTATES];
  901     struct  timeval bootTime;
  902     int     dk_ndrive;
  903     int     hz;
  904 
  905     if (kd_opened == -1) {
  906     return;
  907     }
  908     
  909     if(kd_opened == 0) {
  910     kd = kvm_openfiles(KERNEL, "/dev/mem", NULL, O_RDONLY, kd_buf);
  911     if (kd == NULL) {
  912         LogMsg(0, SrvDebugLevel, stdout, "kvm_openfiles: %s", kd_buf);
  913         kd_opened = -1;
  914         return;
  915     }
  916     i = kvm_nlist(kd, RawStats);
  917     if (i != 0) {
  918         LogMsg(0, SrvDebugLevel, stdout, "Could not nlist symbols from kernel: %s", kvm_geterr(kd));
  919         kd_opened = -1;
  920         return;
  921     }
  922     kd_opened=1;
  923     }
  924 
  925 #define KVM_READ(kd, offset, buf, size) (kvm_read(kd, (u_long)RawStats[offset].n_value, buf, size) != size)
  926 
  927     if (KVM_READ(kd, CPTIME, busy, sizeof busy)) {
  928     LogMsg(0, SrvDebugLevel, stdout, "Could not read CPTIME data from kernel: %s", kvm_geterr(kd));
  929     return;
  930     }
  931     stats->SystemCPU = busy[CP_SYS];
  932     stats->UserCPU = busy[CP_USER];
  933     stats->NiceCPU = busy[CP_NICE];
  934     stats->IdleCPU = busy[CP_IDLE];
  935 
  936     if (KVM_READ(kd, BOOT, &bootTime, sizeof (bootTime))) {
  937     LogMsg(0, SrvDebugLevel, stdout, "Could not read BOOT data from kernel: %s", kvm_geterr(kd));
  938     return;
  939     }
  940     stats->BootTime = bootTime.tv_sec;
  941 
  942     if (KVM_READ(kd, HZ, &hz, sizeof (hz))) {
  943     LogMsg(0, SrvDebugLevel, stdout, "Could not read HZ data from kernel: %s", kvm_geterr(kd));
  944     return;
  945     }
  946     stats->Spare4 = hz;
  947 
  948     if (KVM_READ(kd, DISK, &dk_ndrive, sizeof (dk_ndrive))) {
  949     LogMsg(0, SrvDebugLevel, stdout, "Could not read DISK data from kernel: %s", kvm_geterr(kd));
  950     return;
  951     }
  952 }
  953 #endif
  954 
  955 #ifdef __linux__
  956 /* Actually, most of these statistics could also be read from an snmp daemon
  957  * running on the server host. */
  958 void SetSystemStats_linux(ViceStatistics *stats)
  959 {
  960     uint32_t d1, d2, d3, d4;
  961     static char line[1024];
  962     FILE *f;
  963 
  964 #define PARSELINE(file, pattern, args...) do { int i; \
  965         for (i = 0; i < 16; i++) { \
  966         if (fscanf(file, pattern, ## args) != 0) break; \
  967         fgets(line, 1024, file); \
  968     } } while(0);
  969 
  970     f = fopen("/proc/stat", "r");
  971     if (f) {
  972     PARSELINE(f, "cpu %u %u %u %u", &stats->UserCPU, &stats->NiceCPU,
  973           &stats->SystemCPU, &stats->IdleCPU);
  974     PARSELINE(f, "disk %u %u %u %u", &d1, &d2, &d3, &d4);
  975     stats->TotalIO = d1 + d2 + d3 + d4;
  976         PARSELINE(f, "btime %u", &stats->BootTime);
  977     fclose(f);
  978     }
  979 
  980     f = fopen("/proc/self/status", "r");
  981     if (f) {
  982     PARSELINE(f, "VmSize: %u kB", &stats->ProcessSize);
  983     PARSELINE(f, "VmRSS: %u kB",  &stats->VmRSS);
  984     PARSELINE(f, "VmData: %u kB", &stats->VmData);
  985     fclose(f);
  986     }
  987 }
  988 #endif
  989 
  990 static struct rusage resource;
  991 
  992 static void SetSystemStats(ViceStatistics *stats)
  993 {
  994     stats->CurrentTime = time(0);
  995     
  996     getrusage(RUSAGE_SELF, &resource);
  997 
  998     stats->MinFlt = resource.ru_minflt;
  999     stats->MajFlt = resource.ru_majflt;
 1000     stats->NSwaps = resource.ru_nswap;
 1001 
 1002     /* keeping time 100's of seconds wraps in 497 days */
 1003     stats->UsrTime = (resource.ru_utime.tv_sec * 100 +
 1004               resource.ru_utime.tv_usec / 10000);
 1005     stats->SysTime = (resource.ru_stime.tv_sec * 100 +
 1006               resource.ru_stime.tv_usec / 10000);
 1007 
 1008 #if defined(__FreeBSD__) || defined(__NetBSD__)
 1009     SetSystemStats_bsd44(stats);
 1010 #endif
 1011 #ifdef __linux__
 1012     SetSystemStats_linux(stats);
 1013 #endif
 1014 }
 1015 
 1016 static void PrintVolumeStatus(VolumeStatus *status)
 1017 {
 1018     SLog(5,"Volume header contains:");
 1019     SLog(5,"Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d",
 1020         status->Vid, status->ParentId, status->Online, status->InService,
 1021         status->Blessed, status->NeedsSalvage);
 1022     SLog(5,"MinQuota = %d, MaxQuota = %d", status->MinQuota, status->MaxQuota);
 1023     SLog(5,"Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d",
 1024         status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks);
 1025 }
 1026 
 1027 
 1028 /*
 1029   ViceNewConnectFS: Called by client (userent::Connect) after connection setup
 1030 */
 1031 long FS_ViceNewConnectFS(RPC2_Handle RPCid, RPC2_Unsigned ViceVersion, 
 1032              ViceClient *ClientId)
 1033 {
 1034     long errorCode;
 1035     ClientEntry *client = NULL;
 1036     char *rock;
 1037 
 1038     SLog(1, "FS_ViceNewConnectFS (version %d) for user %s at %s.%s",
 1039          ViceVersion, ClientId->UserName, ClientId->WorkStationName, 
 1040          ClientId->VenusName);
 1041 
 1042     errorCode = RPC2_GetPrivatePointer(RPCid, &rock);
 1043     client = (ClientEntry *)rock;
 1044 
 1045     if (errorCode || !client) {
 1046         SLog(0, "No client structure built by ViceNewConnection");
 1047     return(RPC2_FAIL);
 1048     }
 1049 
 1050     ObtainWriteLock(&client->VenusId->lock);
 1051 
 1052     if (ViceVersion != VICE_VERSION) {
 1053     CLIENT_CleanUpHost(client->VenusId);
 1054     ReleaseWriteLock(&client->VenusId->lock);
 1055     return(RPC2_FAIL);
 1056     }
 1057 
 1058     /* attempt to send a callback message to this host */
 1059     if (client->VenusId->id != 0) {
 1060     errorCode = CallBack(client->VenusId->id, (ViceFid *)&NullFid);
 1061     if (errorCode) {
 1062         /* tear down nak'd connection */
 1063         RPC2_Unbind(client->VenusId->id);
 1064         client->VenusId->id = 0;
 1065     }
 1066     }           
 1067 
 1068     /* set up a callback channel if there isn't one for this host */
 1069     if (client->VenusId->id == 0) {
 1070     SLog(0, "Building callback conn.");
 1071     errorCode = CLIENT_MakeCallBackConn(client);
 1072     }
 1073 
 1074     if (errorCode)
 1075     CLIENT_CleanUpHost(client->VenusId);
 1076 
 1077     ReleaseWriteLock(&client->VenusId->lock);
 1078 
 1079     SLog(2, "FS_ViceNewConnectFS returns %s", ViceErrorMsg((int) errorCode));
 1080     
 1081     return(errorCode);
 1082 }
 1083 
 1084