Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

vreposmonitor.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Mon May 23 21:50:02 EDT 2005 by ken@xorian.net  
00020 
00021 // vreposmonitor -- a program to monitor the Vesta-2 repository server
00022 // state
00023 
00024 #include <math.h>
00025 
00026 // basics
00027 #include <Basics.H>
00028 #include <SRPC.H>
00029 
00030 #include <ReposStatsSRPC.H>
00031 #include <VDirSurrogate.H>
00032 
00033 using std::cout;
00034 using std::cerr;
00035 using std::endl;
00036 
00037 // The name of this program
00038 Text program_name;
00039 
00040 // The time format used for printing the server start time
00041 Text time_format;
00042 
00043 // The repository we're monitoring
00044 Text repos_host, repos_port;
00045 
00046 ReposStats::StatsResult *operator-(const ReposStats::StatsResult &lhs,
00047                                    const ReposStats::StatsResult &rhs)
00048   throw()
00049 {
00050   ReposStats::StatsResult *result = NEW(ReposStats::StatsResult);
00051 
00052   ReposStats::StatKey k;
00053   ReposStats::Stat *lhs_v, *rhs_v;
00054   ReposStats::StatsResultIter it(&lhs);
00055   while(it.Next(k,lhs_v))
00056     {
00057       if(rhs.Get(k, rhs_v))
00058         {
00059           switch(k.kind)
00060             {
00061             case ReposStats::fdCache:
00062               {
00063                 ReposStats::FdCacheStats
00064                   *lhs_fd_stats = (ReposStats::FdCacheStats *) lhs_v,
00065                   *rhs_fd_stats = (ReposStats::FdCacheStats *) rhs_v;
00066                 result->Put(k,
00067                             NEW_CONSTR(ReposStats::FdCacheStats,
00068                                        (*lhs_fd_stats - *rhs_fd_stats)));
00069               }
00070               break;
00071             case ReposStats::dupeTotal:
00072               {
00073                 ReposStats::DupeStats
00074                   *lhs_dupe_stats = (ReposStats::DupeStats *) lhs_v,
00075                   *rhs_dupe_stats = (ReposStats::DupeStats *) rhs_v;
00076                 result->Put(k,
00077                             NEW_CONSTR(ReposStats::DupeStats,
00078                                        (*lhs_dupe_stats - *rhs_dupe_stats)));
00079               }
00080               break;
00081             case ReposStats::srpcTotal:
00082               {
00083                 ReposStats::TimedCalls
00084                   *lhs_srpc_stats = (ReposStats::TimedCalls *) lhs_v,
00085                   *rhs_srpc_stats = (ReposStats::TimedCalls *) rhs_v;
00086                 result->Put(k,
00087                             NEW_CONSTR(ReposStats::TimedCalls,
00088                                        (*lhs_srpc_stats - *rhs_srpc_stats)));
00089               }
00090               break;
00091             case ReposStats::nfsTotal:
00092               {
00093                 ReposStats::TimedCalls
00094                   *lhs_nfs_stats = (ReposStats::TimedCalls *) lhs_v,
00095                   *rhs_nfs_stats = (ReposStats::TimedCalls *) rhs_v;
00096                 result->Put(k,
00097                             NEW_CONSTR(ReposStats::TimedCalls,
00098                                        (*lhs_nfs_stats - *rhs_nfs_stats)));
00099               }
00100               break;
00101             case ReposStats::memUsage:
00102               {
00103                 // We always preserve the left hand (new) memory stats.
00104                 ReposStats::MemStats
00105                   *lhs_mem_stats = (ReposStats::MemStats *) lhs_v;
00106                 result->Put(k, NEW_CONSTR(ReposStats::MemStats,
00107                                           (*lhs_mem_stats)));
00108               }
00109               break;
00110             }
00111         }
00112     }
00113 
00114   return result;
00115 }
00116 
00117 bool operator<(const ReposStats::StatsResult &lhs,
00118                const ReposStats::StatsResult &rhs)
00119   throw()
00120 {
00121   ReposStats::StatKey k;
00122   ReposStats::Stat *lhs_v, *rhs_v;
00123   ReposStats::StatsResultIter it(&lhs);
00124   while(it.Next(k,lhs_v))
00125     {
00126       if(rhs.Get(k, rhs_v))
00127         {
00128           switch(k.kind)
00129             {
00130             case ReposStats::fdCache:
00131               {
00132                 ReposStats::FdCacheStats
00133                   *lhs_fd_stats = (ReposStats::FdCacheStats *) lhs_v,
00134                   *rhs_fd_stats = (ReposStats::FdCacheStats *) rhs_v;
00135                 if((lhs_fd_stats->hits < rhs_fd_stats->hits) ||
00136                    (lhs_fd_stats->open_misses < rhs_fd_stats->open_misses) ||
00137                    (lhs_fd_stats->try_misses < rhs_fd_stats->try_misses) ||
00138                    (lhs_fd_stats->evictions < rhs_fd_stats->evictions) ||
00139                    (lhs_fd_stats->expirations < rhs_fd_stats->expirations))
00140                   return true;
00141               }
00142               break;
00143             case ReposStats::dupeTotal:
00144               {
00145                 ReposStats::DupeStats
00146                   *lhs_dupe_stats = (ReposStats::DupeStats *) lhs_v,
00147                   *rhs_dupe_stats = (ReposStats::DupeStats *) rhs_v;
00148                 if((lhs_dupe_stats->non < rhs_dupe_stats->non) ||
00149                    (lhs_dupe_stats->inProcess < rhs_dupe_stats->inProcess) ||
00150                    (lhs_dupe_stats->completed < rhs_dupe_stats->completed))
00151                   return true;
00152               }
00153               break;
00154             case ReposStats::srpcTotal:
00155               {
00156                 ReposStats::TimedCalls
00157                   *lhs_srpc_stats = (ReposStats::TimedCalls *) lhs_v,
00158                   *rhs_srpc_stats = (ReposStats::TimedCalls *) rhs_v;
00159                 if((lhs_srpc_stats->call_count < rhs_srpc_stats->call_count) ||
00160                    (lhs_srpc_stats->elapsed_secs <
00161                     rhs_srpc_stats->elapsed_secs) ||
00162                    ((lhs_srpc_stats->elapsed_secs ==
00163                      rhs_srpc_stats->elapsed_secs) &&
00164                     (lhs_srpc_stats->elapsed_usecs <
00165                      rhs_srpc_stats->elapsed_usecs)))
00166                   return true;
00167               }
00168               break;
00169             case ReposStats::nfsTotal:
00170               {
00171                 ReposStats::TimedCalls
00172                   *lhs_nfs_stats = (ReposStats::TimedCalls *) lhs_v,
00173                   *rhs_nfs_stats = (ReposStats::TimedCalls *) rhs_v;
00174                 if((lhs_nfs_stats->call_count < rhs_nfs_stats->call_count) ||
00175                    (lhs_nfs_stats->elapsed_secs <
00176                     rhs_nfs_stats->elapsed_secs) ||
00177                    ((lhs_nfs_stats->elapsed_secs ==
00178                      rhs_nfs_stats->elapsed_secs) &&
00179                     (lhs_nfs_stats->elapsed_usecs <
00180                      rhs_nfs_stats->elapsed_usecs)))
00181                   return true;
00182               }
00183               break;
00184             }
00185         }
00186     }
00187   return false;
00188 }
00189 
00190 void freeStatsResult(ReposStats::StatsResult *trash) throw()
00191 {
00192   // Loop over the table and delete any statistic data it contains.
00193   ReposStats::StatKey key;
00194   ReposStats::Stat *stat;
00195   ReposStats::StatsResultIter it(trash);
00196   while(it.Next(key, stat))
00197     {
00198       delete stat;
00199     }
00200   // Delete the table itself.
00201   delete trash;
00202 }
00203 
00204 static void Error(char *msg, char *arg = (char *)NULL) throw ()
00205 {
00206     cerr << "Error: " << msg;
00207     if (arg != (char *)NULL) cerr << ": `" << arg << "'";
00208     cerr << endl;
00209     cerr << "SYNTAX: vreposmonitor [ -update time ] "
00210          << "[ -ts time ] [ -n num ] [ -rows num ]" << endl;
00211     exit(1);
00212 }
00213 
00214 // The statistics we're going to ask the server for.  Set in main.
00215 ReposStats::StatsRequest statsRequest;
00216 
00217 static void PrintHeader() throw ()
00218 {
00219   Text header_lines[3];
00220   
00221   // Form the header based on the statistics we'll be printing
00222   for(int i = 0; i < statsRequest.size(); i++)
00223     {
00224       switch(statsRequest.get(i))
00225         {
00226         case ReposStats::nfsTotal:
00227           header_lines[0] += "   NFS    ";
00228           header_lines[1] += "NUM   AVG ";
00229           header_lines[2] += "---- -----";
00230           break;
00231         case ReposStats::srpcTotal:
00232           header_lines[0] += "   SRPC   ";
00233           header_lines[1] += "NUM   AVG ";
00234           header_lines[2] += "---- -----";
00235           break;
00236         case ReposStats::dupeTotal:
00237           header_lines[0] += "     DUPE     ";
00238           header_lines[1] += "NEW  INPR DONE";
00239           header_lines[2] += "---- ---- ----";
00240           break;
00241         case ReposStats::fdCache:
00242           header_lines[0] += "           FDCACHE           ";
00243           header_lines[1] += "HELD HITS OMIS TMIS EVIC EXPR";
00244           header_lines[2] += "---- ---- ---- ---- ---- ----";
00245           break;
00246         case ReposStats::memUsage:
00247           header_lines[0] += "  MEMORY  ";
00248           header_lines[1] += "SIZE  RES ";
00249           header_lines[2] += "---- -----";
00250           break;
00251         }
00252       header_lines[0] += "|";
00253       header_lines[1] += "|";
00254       header_lines[2] += " ";
00255     }
00256 
00257   cout << endl
00258        << header_lines[0] << endl
00259        << header_lines[1] << endl
00260        << header_lines[2] << endl;
00261 }
00262 
00263 static void PrintVal(Basics::uint64 val) throw ()
00264 {
00265     const Basics::uint64 OneK = 1024;
00266     const Basics::uint64 OneM = OneK * OneK;
00267     const Basics::uint64 OneG = OneM * OneK;
00268     char buff[10];
00269     if (val < OneK) {
00270         sprintf(buff, "%4d", val);
00271         cout << buff;
00272     } else {
00273       char suffix = 'K';
00274       if (val >= OneG)
00275         {
00276           val /= OneM;
00277           suffix = 'G';
00278         }
00279       else if (val >= OneM)
00280         {
00281           val /= OneK;
00282           suffix = 'M';
00283         }
00284 
00285       float ratio = ((float)val) / ((float)OneK);
00286       if (ratio < 9.95) { // assures won't round up to 10.0
00287         sprintf(buff, "%3.1f", ratio);
00288       } else {
00289         val = (val + (OneK / 2)) / OneK; // round
00290         sprintf(buff, "%3d", val);
00291       }
00292       cout << buff << suffix;
00293     }
00294     cout << ' ';
00295 }
00296 
00297 static void PrintTime(Basics::uint64 secs, Basics::uint32 usecs,
00298                       Basics::uint64 divisor)
00299 {
00300   // Avoid divide by zero
00301   if(divisor == 0)
00302     {
00303       cout << "N/A   ";
00304       return;
00305     }
00306 
00307   // Compute total usecs divide by the divisor
00308   double time = secs;
00309   time *= USECS_PER_SEC;
00310   time += usecs;
00311   time /= divisor;
00312 
00313   const char *units;
00314   // Less than 0.1ms?
00315   if(time < 100)
00316     {
00317       // Print as micorseconds
00318       units = "us";
00319     }
00320   // Less than 0.1s?
00321   else if(time < 100000)
00322     {
00323       // Print as milliseconds
00324       time /= 1000;
00325       units = "ms";
00326     }
00327   // Less than 0.1m?
00328   else if(time < (6*USECS_PER_SEC))
00329     {
00330       // Print as seconds
00331       time /= USECS_PER_SEC;
00332       units = "s ";
00333     }
00334   else
00335     {
00336       // Print as minutes
00337       time /= USECS_PER_SEC;
00338       time /= 60;
00339       units = "m ";
00340     }
00341 
00342     char buff[12];
00343     if (time < 9.95) { // assures won't round up to 10.0
00344       sprintf(buff, "%3.1f", time);
00345     } else {
00346       unsigned int time_int = (unsigned int) rint(time);
00347       sprintf(buff, "%3d", time_int);
00348     }
00349 
00350     cout << buff << units << ' ';
00351 }
00352 
00353 static void filterStatsRequest(ReposStats::StatsResult *received)
00354 {
00355   // We'll accumulate the statistics actually received here, in the
00356   // same order they were requested.
00357   ReposStats::StatsRequest statsReceived;
00358   // Loop over the requested statistics.
00359   for(int i = 0; i < statsRequest.size(); i++)
00360     {
00361       ReposStats::StatKind kind = statsRequest.get(i);
00362       ReposStats::Stat *stats = 0;
00363       // If the server did send us this statistic, add it to the
00364       // received sequence.
00365       if(received->Get(kind, stats))
00366         {
00367           statsReceived.addhi(kind);
00368         }
00369     }
00370   // In future, we'll only request those statistics the server can
00371   // actually provide.  (This also controls the appearance of the
00372   // header.)
00373   statsRequest = statsReceived;
00374 }
00375 
00376 // Format the repository server start time as a text string
00377 Text TextStartTime(time_t when) throw()
00378 {
00379   char timebuf[256];
00380   strftime(timebuf, sizeof(timebuf), time_format.cchars(), localtime(&when));
00381 
00382   return timebuf;
00383 }
00384 
00385 // Format the repository server uptime as a text string
00386 Text TextUptime(Basics::uint32 uptime) throw()
00387 {
00388   Basics::uint32 seconds, minutes, hours, days;
00389 
00390   seconds = uptime % 60;
00391   uptime /= 60;
00392 
00393   minutes = uptime % 60;
00394   uptime /= 60;
00395 
00396   hours = uptime % 24;
00397   uptime /= 24;
00398 
00399   days = uptime;
00400 
00401   Text result;
00402   char buf[20];
00403   if(days > 0)
00404     {
00405       sprintf(buf, "%d", days);
00406       result += buf;
00407       result += " days";
00408     }
00409   if(hours > 0)
00410     {
00411       if(!result.Empty())
00412         result += " ";
00413       sprintf(buf, "%d", hours);
00414       result += buf;
00415       result += " hours";
00416     }
00417   if(minutes > 0)
00418     {
00419       if(!result.Empty())
00420         result += " ";
00421       sprintf(buf, "%d", minutes);
00422       result += buf;
00423       result += " minutes";
00424     }
00425   if(seconds > 0)
00426     {
00427       if(!result.Empty())
00428         result += " ";
00429       sprintf(buf, "%d", seconds);
00430       result += buf;
00431       result += " seconds";
00432     }
00433   return result;
00434 }
00435 
00436 static void NewReposStats(const int ts,
00437                           /*INOUT*/ ReposStats::StatsResult* &oldStats,
00438                           /*INOUT*/ int &rowsPrinted,
00439                           int rows) throw (SRPC::failure)
00440 {
00441     // time at which to print next time stamp
00442     static time_t nextStamp = -1;
00443 
00444     // get new stats
00445     ReposStats::StatsResult *newStats = NEW(ReposStats::StatsResult);
00446     ReposStats::getStats(*newStats, statsRequest,
00447                          0,
00448                          repos_host, repos_port);
00449 
00450     // There's a possibility that we're talking to an older server
00451     // that doesn't support one of the statistic types we requested.
00452     // Figure out if it decided to send us a subset of the statistics
00453     // we asked for so we can display an appropriate header.
00454     if((oldStats == 0) && (rowsPrinted == 0))
00455       {
00456         filterStatsRequest(newStats);
00457       }
00458 
00459     // test if server has been restarted since last sample
00460     if ((oldStats == 0) ||
00461         (*newStats < *oldStats))
00462       {
00463         ReposStats::ServerInfo server_info;
00464         ReposStats::getServerInfo(server_info,
00465                                   0,
00466                                   repos_host, repos_port);
00467         cout << "Repository:     " << repos_host << ":" << repos_port << endl
00468              << "Server Version: " << server_info.version << endl
00469              << "Started:        " << TextStartTime(server_info.start_time)
00470              << endl
00471              << "Uptime:         " << TextUptime(server_info.uptime) << endl
00472              << endl;
00473 
00474         rowsPrinted = 0;
00475         if(oldStats != 0)
00476           {
00477             freeStatsResult(oldStats);
00478             oldStats = 0;
00479           }
00480       }
00481 
00482     // Print a header if we need to.
00483     if (rowsPrinted == 0 || (rows > 0 && rowsPrinted % rows == 0))
00484       PrintHeader();
00485 
00486     // see if it is time to print a timestamp
00487     if (ts >= 0)
00488       {
00489         time_t now = time((time_t *)NULL);
00490         assert(now >= 0);
00491         if (now >= nextStamp)
00492           {
00493             // don't print a timestamp the first time
00494             if (nextStamp >= 0)
00495               {
00496                 char buffer[64];
00497                 (void) ctime_r(&now, buffer);
00498                 buffer[strlen(buffer)-1] = '\0'; // suppress '\n'
00499                 cout << "------------------------ " << buffer
00500                      << " ------------------------" << endl;
00501               }
00502             nextStamp = now + ts;
00503           }
00504       }
00505 
00506     // print either the absolute counts since the server was started,
00507     // or counts since the last call
00508     ReposStats::StatsResult *printedStats =
00509       ((oldStats == 0)
00510        ? newStats
00511        : *newStats - *oldStats);
00512 
00513     for(int i = 0; i < statsRequest.size(); i++)
00514       {
00515         ReposStats::StatKind kind = statsRequest.get(i);
00516         ReposStats::Stat *stats = 0;
00517         if(printedStats->Get(kind, stats))
00518           {
00519             switch(kind)
00520               {
00521               case ReposStats::nfsTotal:
00522                 {
00523                   ReposStats::TimedCalls *nfsStats =
00524                     (ReposStats::TimedCalls *) stats;
00525                   PrintVal(nfsStats->call_count);
00526                   PrintTime(nfsStats->elapsed_secs,
00527                             nfsStats->elapsed_usecs,
00528                             nfsStats->call_count);
00529                 }
00530                 break;
00531               case ReposStats::srpcTotal:
00532                 {
00533                   ReposStats::TimedCalls *srpcStats =
00534                     (ReposStats::TimedCalls *) stats;
00535                   PrintVal(srpcStats->call_count);
00536                   PrintTime(srpcStats->elapsed_secs,
00537                             srpcStats->elapsed_usecs,
00538                             srpcStats->call_count);
00539                 }
00540                 break;
00541               case ReposStats::dupeTotal:
00542                 {
00543                   ReposStats::DupeStats *dupeStats =
00544                     (ReposStats::DupeStats *) stats;
00545                   PrintVal(dupeStats->non);
00546                   PrintVal(dupeStats->inProcess);
00547                   PrintVal(dupeStats->completed);
00548                 }
00549                 break;
00550               case ReposStats::fdCache:
00551                 {
00552                   ReposStats::FdCacheStats *fdCacheStats =
00553                     (ReposStats::FdCacheStats *) stats;
00554                   PrintVal(fdCacheStats->n_in_cache);
00555                   PrintVal(fdCacheStats->hits);
00556                   PrintVal(fdCacheStats->open_misses);
00557                   PrintVal(fdCacheStats->try_misses);
00558                   PrintVal(fdCacheStats->evictions);
00559                   PrintVal(fdCacheStats->expirations);
00560                 }
00561                 break;
00562               case ReposStats::memUsage:
00563                 {
00564                   ReposStats::MemStats *memStats =
00565                     (ReposStats::MemStats *) stats;
00566                   PrintVal(memStats->total);
00567                   PrintVal(memStats->resident);
00568                 }
00569                 break;
00570               }
00571           }
00572       }
00573 
00574     cout << endl;
00575     rowsPrinted++;
00576 
00577     // If the printed stats were the result of taking the difference
00578     // between the old and new stats, free the printed stats.
00579     if(printedStats != newStats)
00580       {
00581         freeStatsResult(printedStats);
00582       }
00583 
00584     // If there are old stats, free them.
00585     if(oldStats != 0)
00586       {
00587         freeStatsResult(oldStats);
00588       }
00589 
00590     // The new stats are now the old stats.
00591     oldStats = newStats;
00592 }
00593 
00594 static void Monitor(int update, int ts, int num, int rows, bool check) throw ()
00595 {
00596     // repostiroy stats
00597     ReposStats::StatsResult *oldStats = 0;
00598 
00599     // loop until enough rows have been printed
00600     int rowsPrinted = 0;
00601     while (num < 0 || rowsPrinted < num) {
00602         try {
00603           NewReposStats(ts, /*INOUT*/ oldStats, /*INOUT*/ rowsPrinted, rows);
00604         }
00605         catch (SRPC::failure) {
00606           // If we're just doing a quick check, exit now.
00607           if(check) exit(1);
00608           cout << "Error contacting repository server; retrying..." << endl;
00609           if(oldStats != 0)
00610             {
00611               freeStatsResult(oldStats);
00612               oldStats = 0;
00613             }
00614         }
00615 
00616         // If we're just doing a quick check, exit now.
00617         if(check) exit(0);
00618 
00619         // pause for "update" seconds
00620         Basics::thread::pause(update);
00621     }
00622 }
00623 
00624 /* Return the number of seconds denoted by "tm". Except for an optional
00625    suffix character, "tm" must be a non-negative integer value. If
00626    present, the suffix character specifies a time unit as follows:
00627 
00628      s  seconds (default)
00629      m  minutes
00630      h  hours
00631      d  days
00632 */
00633 static int ParseTime(char *flag, char *tm) throw ()
00634 {
00635     char errBuff[80];
00636     int len = strlen(tm);
00637     if (len == 0) {
00638         sprintf(errBuff, "argument to `%s' is empty", flag);
00639         Error(errBuff, tm);
00640     }
00641     char lastChar = tm[len - 1];
00642     int multiplier = 1;
00643     switch (lastChar) {
00644       case 'd':
00645         multiplier *= 24;
00646         // fall through
00647       case 'h':
00648         multiplier *= 60;
00649         // fall through
00650       case 'm':
00651         multiplier *= 60;
00652         // fall through
00653       case 's':
00654         tm[len - 1] = '\0';
00655         break;
00656       default:
00657         if (!isdigit(lastChar)) {
00658             sprintf(errBuff, "illegal unit specifier `%c' in `%s' argument",
00659                     lastChar, flag);
00660             Error(errBuff, tm);
00661         }
00662     }
00663     int res;
00664     if (sscanf(tm, "%d", &res) != 1) {
00665         sprintf(errBuff, "argument to `%s' not an integer", flag);
00666         Error(errBuff, tm);
00667     }
00668     return multiplier * res;
00669 }
00670 
00671 int main(int argc, char *argv[])
00672 {
00673     int update = 10; // default: update every 10 seconds
00674     int ts = -1;     // default: do not print any timestamps
00675     int num = -1;    // default: update indefinitely
00676     int rows = -1;   // default: only write header lines once
00677     int arg = 1;
00678     bool check = false;
00679 
00680     program_name = argv[0];
00681 
00682     try
00683       {
00684         repos_host = VDirSurrogate::defaultHost();
00685         repos_port = VDirSurrogate::defaultPort();
00686 
00687         time_format = VestaConfig::get_Text("UserInterface", "TimeFormat");
00688 
00689         // process command-line
00690         while (arg < argc && *argv[arg] == '-') {
00691           if (strcmp(argv[arg], "-update") == 0) {
00692             if (++arg < argc) {
00693               update = ParseTime("-update", argv[arg++]);
00694             } else {
00695               Error("no argument supplied for `-update'");
00696             }
00697           } else if (strcmp(argv[arg], "-ts") == 0) {
00698             if (++arg < argc) {
00699               ts = ParseTime("-ts", argv[arg++]);
00700             } else {
00701               Error("no argument supplied for `-ts'");
00702             }
00703           } else if (strcmp(argv[arg], "-n") == 0) {
00704             if (++arg < argc) {
00705               if (sscanf(argv[arg], "%d", &num) != 1) {
00706                 Error("argument to `-n' not an integer", argv[arg]);
00707               }
00708               arg++;
00709             } else {
00710               Error("no argument supplied for `-n'");
00711             }
00712           } else if (strcmp(argv[arg], "-rows") == 0) {
00713             if (++arg < argc) {
00714               if (sscanf(argv[arg], "%d", &rows) != 1) {
00715                 Error("argument to `-rows' not an integer", argv[arg]);
00716               }
00717               arg++;
00718             } else {
00719               Error("no argument supplied for `-rows'");
00720             }
00721           } else if (strcmp(argv[arg], "-check") == 0) {
00722             check = true;
00723             arg++;
00724           } else if (strcmp(argv[arg], "-R") == 0) {
00725             if (++arg < argc) {
00726               Text repos = argv[arg];
00727               arg++;
00728               // Split up the argument into the host and port part
00729               int colon = repos.FindCharR(':');
00730               if (colon == -1) {
00731                 repos_host = repos;
00732               } else {
00733                 repos_host = repos.Sub(0, colon);
00734                 repos_port = repos.Sub(colon+1);
00735               }
00736             } else {
00737               Error("no argument supplied for `-R'");
00738             }
00739           } else {
00740             Error("unrecognized option", argv[arg]);
00741           }
00742         }
00743         if (arg < argc) Error("too many command-line arguments");
00744 
00745         // For now, just ask for a fixed set of statistics.
00746         statsRequest.addhi(ReposStats::memUsage);
00747         statsRequest.addhi(ReposStats::nfsTotal);
00748         statsRequest.addhi(ReposStats::srpcTotal);
00749         statsRequest.addhi(ReposStats::dupeTotal);
00750         statsRequest.addhi(ReposStats::fdCache);
00751 
00752         Monitor(update, ts, num, rows, check);
00753       }
00754     catch (VestaConfig::failure f)
00755       {
00756         cerr << program_name << ": " << f.msg << endl;
00757         exit(2);
00758       }
00759     catch (SRPC::failure f)
00760       {
00761         cerr << program_name
00762              << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00763         exit(2);
00764       }
00765     return(0);
00766 }

Generated on Mon May 8 00:48:54 2006 for Vesta by  doxygen 1.4.2