sin_family is not network order
[openafs.git] / src / afsmonitor / afsmonitor.c
index 7c1e1e5..952a95d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
@@ -23,7 +23,7 @@
 #include <math.h>
 #include <string.h>
 #include <errno.h>
-#include <cmd.h>
+#include <afs/cmd.h>
 #include <signal.h>
 #undef IN
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <ctype.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
 
-#include <gtxwindows.h>                /*Generic window package */
-#include <gtxobjects.h>                /*Object definitions */
-#include <gtxlightobj.h>       /*Light object interface */
-#include <gtxcurseswin.h>      /*Curses window package */
-#include <gtxdumbwin.h>                /*Dumb terminal window package */
-#include <gtxX11win.h>         /*X11 window package */
-#include <gtxframe.h>          /*Frame package */
-#include <gtxinput.h>
+#include <afs/gtxwindows.h>            /*Generic window package */
+#include <afs/gtxobjects.h>            /*Object definitions */
+#include <afs/gtxlightobj.h>   /*Light object interface */
+#include <afs/gtxcurseswin.h>  /*Curses window package */
+#include <afs/gtxdumbwin.h>            /*Dumb terminal window package */
+#include <afs/gtxX11win.h>             /*X11 window package */
+#include <afs/gtxframe.h>              /*Frame package */
+#include <afs/gtxinput.h>
 
 #include <afs/xstat_fs.h>
 #include <afs/xstat_cm.h>
@@ -85,7 +88,7 @@ short cm_showFlags[NUM_CM_STAT_ENTRIES];
 #define CM 2                   /* for misc. use */
 
 
-#define        NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66     /* number of fields (longs) in struct afs_PerfStats that we display */
+#define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70    /* number of fields from struct afs_PerfStats that we display */
 #define NUM_AFS_STATS_CMPERF_LONGS 40  /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
 
 
@@ -114,6 +117,12 @@ static struct afsmon_hostEntry *CMnameList;
 int numFS = 0;
 int numCM = 0;
 
+/* number of xstat collection ids */
+#define MAX_NUM_FS_COLLECTIONS 2
+#define MAX_NUM_CM_COLLECTIONS 1
+int num_fs_collections = 0;
+int num_cm_collections = 0;
+
 /* variables used for processing config file */
 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
 in the config file */
@@ -129,8 +138,8 @@ static int lastHostType = 0;        /* 0 = no host entries processed
 /* FILE SERVER CIRCULAR BUFFER VARIABLES  */
 
 struct afsmon_fs_Results_list {
-    struct xstat_fs_ProbeResults *fsResults;   /* ptr to results struct */
-    int empty;                 /* fsResults empty ? */
+    struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
+    int empty[MAX_NUM_FS_COLLECTIONS];
     struct afsmon_fs_Results_list *next;
 };
 
@@ -139,12 +148,15 @@ struct afsmon_fs_Results_CBuffer {
     struct afsmon_fs_Results_list *list;       /* ptr to list of results */
 };
 
+int afsmon_fs_results_length[] =
+    { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
+
 /* buffer for FS probe results */
 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
 
 int afsmon_fs_curr_CBindex = 0;        /* current fs CB slot */
 
-/* Probe number variables. The current probe number is incremented 
+/* Probe number variables. The current probe number is incremented
 when the first probe from a new probe cycle is received. The prev probe
 number is incremented when the last probe of the current cycle is
 received. This difference is because of the purpose for which these
@@ -157,8 +169,8 @@ int afsmon_fs_prev_probeNum = 0;    /* previous fs probe number */
 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES  */
 
 struct afsmon_cm_Results_list {
-    struct xstat_cm_ProbeResults *cmResults;   /* ptr to results struct */
-    int empty;                 /* cmResults empty ? */
+    struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
+    int empty[MAX_NUM_CM_COLLECTIONS];
     struct afsmon_cm_Results_list *next;
 };
 
@@ -167,13 +179,15 @@ struct afsmon_cm_Results_CBuffer {
     struct afsmon_cm_Results_list *list;       /* ptr to list of results */
 };
 
+int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
+
 /* buffer for CM probe results */
 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
 
 int afsmon_cm_curr_CBindex = 0;        /* current cm CB slot */
 
 
-/* Probe number variables. The current probe number is incremented 
+/* Probe number variables. The current probe number is incremented
 when the first probe from a new probe cycle is received. The prev probe
 number is incremented when the last probe of the current cycle is
 received. This difference is because of the purpose for which these
@@ -220,7 +234,7 @@ int numHosts_onfs_alerts;
 int num_cm_alerts;
 int numHosts_oncm_alerts;
 
-/* flag to indicate that atleast one probe cycle has completed and 
+/* flag to indicate that atleast one probe cycle has completed and
 data is available for updating the display */
 extern int fs_Data_Available;
 extern int cm_Data_Available;
@@ -232,16 +246,16 @@ are to be displayed on the File Servers screen. For example, suppose the
 user wishes to display only the vcache statistics then the following array
 will contain indices 2 to 14 corresponding to the position of the
 vcache data items in the fs_varNames[] array. If the config file contains
-no "show fs .." directives, it will contain the indices of all the 
+no "show fs .." directives, it will contain the indices of all the
 items in the fs_varNames[] array */
 
-short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
+short fs_Display_map[NUM_FS_STAT_ENTRIES];
 int fs_DisplayItems_count = 0; /* number of items to display */
 int fs_showDefault = 1;                /* show all of FS data ? */
 
 
 /* same use as above for Cache Managers  */
-short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
+short cm_Display_map[NUM_CM_STAT_ENTRIES];
 int cm_DisplayItems_count = 0; /* number of items to display */
 int cm_showDefault = 1;                /* show all of CM data ? */
 
@@ -251,20 +265,26 @@ extern int fs_curr_LCol;  /* current leftmost column on display on FS frame */
 extern int cm_currPage;                /* current page number in the Cache Managers frame */
 extern int cm_curr_LCol;       /* current leftmost column on display on CM frame */
 
-/* File server and Cache manager data is classified into sections & 
+/* File server and Cache manager data is classified into sections &
 groups to help the user choose what he wants displayed */
 extern char *fs_categories[];  /* file server data category names */
 extern char *cm_categories[];  /* cache manager data category names */
 
 
+static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
+                            struct xstat_fs_ProbeResults *a_fsResults);
+static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
+                                struct xstat_fs_ProbeResults *a_fsResults);
 
-#ifndef HAVE_STRCASESTR
-/*     
-        strcasestr(): Return first occurence of pattern s2 in s1, case 
-       insensitive. 
+#ifdef HAVE_STRCASESTR
+extern char * strcasestr(const char *, const char *);
+#else
+/*
+        strcasestr(): Return first occurence of pattern s2 in s1, case
+       insensitive.
 
        This routine is required since I made pattern matching of the
-       config file to be case insensitive. 
+       config file to be case insensitive.
 */
 
 char *
@@ -318,17 +338,17 @@ GetHostByName(char *name)
  *
  * Description
  *     Exit gracefully from the afsmonitor. Frees memory where appropriate,
- *     cleans up after gtx and closes all open file descriptors. If a user 
+ *     cleans up after gtx and closes all open file descriptors. If a user
  *     provided threshold handler is to be exec'ed then gtx cleanup is
- *     not performed and an exec() is made instead of an exit(). 
+ *     not performed and an exec() is made instead of an exit().
  *
  * Returns
  *     Nothing.
  *
- * Comments 
- *     This function is called to execute a user handler only 
+ * Comments
+ *     This function is called to execute a user handler only
  *     by a child process.
- * 
+ *
  *----------------------------------------------------------------------*/
 
 int
@@ -342,7 +362,7 @@ afsmon_Exit(int a_exitVal)  /* exit code */
     struct afsmon_cm_Results_list *next_cmlist;
     struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
     struct afsmon_hostEntry *curr_hostEntry;
-    struct afsmon_hostEntry *prev_hostEntry;
+    struct afsmon_hostEntry *next_hostEntry;
     int i;
     int j;
     int bufslot;
@@ -388,15 +408,17 @@ afsmon_Exit(int a_exitVal)        /* exit code */
                        break;
                    }
                    next_fslist = tmp_fslist->next;
-                   tmp_xstat_fsPR = tmp_fslist->fsResults;
+                   for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
+                       tmp_xstat_fsPR = tmp_fslist->fsResults[i];
 
-                   if (afsmon_debug)
-                       fprintf(debugFD, "%d ", numFS - j);
+                       if (afsmon_debug)
+                           fprintf(debugFD, "%d ", numFS - j);
 
-                   /* free xstat_fs_Results data */
-                   free(tmp_xstat_fsPR->data.AFS_CollData_val);
-                   free(tmp_xstat_fsPR->connP);
-                   free(tmp_xstat_fsPR);
+                       /* free xstat_fs_Results data */
+                       free(tmp_xstat_fsPR->data.AFS_CollData_val);
+                       free(tmp_xstat_fsPR->connP);
+                       free(tmp_xstat_fsPR);
+                   }
 
                    /* free the fs list item */
                    free(tmp_fslist);
@@ -432,17 +454,19 @@ afsmon_Exit(int a_exitVal)        /* exit code */
                        break;
                    }
                    next_cmlist = tmp_cmlist->next;
-                   tmp_xstat_cmPR = tmp_cmlist->cmResults;
+                   for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
+                       tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
 
-                   if (afsmon_debug)
-                       fprintf(debugFD, "%d ", numCM - j);
-                   /* make sure data is ok */
-                   /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
+                       if (afsmon_debug)
+                           fprintf(debugFD, "%d ", numCM - j);
+                       /* make sure data is ok */
+                       /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
 
-                   /* free xstat_cm_Results data */
-                   free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
-                   free(tmp_xstat_cmPR->connP);
-                   free(tmp_xstat_cmPR);
+                       /* free xstat_cm_Results data */
+                       free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
+                       free(tmp_xstat_cmPR->connP);
+                   }
+                   free(tmp_cmlist->cmResults);
 
                    /* free the cm list item */
                    free(tmp_cmlist);
@@ -483,14 +507,12 @@ afsmon_Exit(int a_exitVal)        /* exit code */
        if (afsmon_debug)
            fprintf(debugFD, "Deallocating FS hostEntries ..");
        curr_hostEntry = FSnameList;
-       for (i = 0; i < numFS; i++) {
-           prev_hostEntry = curr_hostEntry;
+       while (curr_hostEntry) {
+           next_hostEntry = curr_hostEntry->next;
            if (curr_hostEntry->thresh != NULL)
                free(curr_hostEntry->thresh);
            free(curr_hostEntry);
-           if (afsmon_debug)
-               fprintf(debugFD, " %d", i);
-           curr_hostEntry = prev_hostEntry->next;
+           curr_hostEntry = next_hostEntry;
        }
        if (afsmon_debug)
            fprintf(debugFD, "\n");
@@ -499,14 +521,12 @@ afsmon_Exit(int a_exitVal)        /* exit code */
        if (afsmon_debug)
            fprintf(debugFD, "Deallocating CM hostEntries ..");
        curr_hostEntry = CMnameList;
-       for (i = 0; i < numCM; i++) {
-           prev_hostEntry = curr_hostEntry;
+       while (curr_hostEntry) {
+           next_hostEntry = curr_hostEntry->next;
            if (curr_hostEntry->thresh != NULL)
                free(curr_hostEntry->thresh);
            free(curr_hostEntry);
-           if (afsmon_debug)
-               fprintf(debugFD, " %d", i);
-           curr_hostEntry = prev_hostEntry->next;
+           curr_hostEntry = next_hostEntry;
        }
        if (afsmon_debug)
            fprintf(debugFD, "\n");
@@ -790,7 +810,7 @@ parse_hostEntry(char *a_line)
  *
  * Description
  *     Parse the threshold entry line in the config file. This function is
- *     called in the the first pass of the config file. It checks the syntax 
+ *     called in the the first pass of the config file. It checks the syntax
  *     of the config lines and verifies their positional validity - eg.,
  *     a cm threshold cannot appear after a fs hostname entry, etc.
  *     It also counts the thresholds applicable to each host.
@@ -893,7 +913,7 @@ parse_threshEntry(char *a_line)
  *     for cache managers. For global thresholds the info is recorded for
  *     all the hosts. This function is called in the second pass of the
  *     config file. In the first pass a count of the number of global
- *     thresholds is determined and this information is used in this 
+ *     thresholds is determined and this information is used in this
  *     routine. If threshold entries are duplicated the first entry is
  *     overwritten.
  *     Each threshold entry also has an index field. This is a positional
@@ -1072,9 +1092,9 @@ store_threshold(int a_type,               /* 1 = fs , 2 = cm */
  *     This data is mapped to the screen thru fs_Display_map[] and
  *     cm_Display_map[]. This routine parses the "show" entry against the
  *     section/group names in the [fs/cm]_categories[] array. If there is
- *     no match it tries to match it against a variable name in 
+ *     no match it tries to match it against a variable name in
  *     [fs/cm]_varNames[] array. In each case the corresponding indices to
- *     the data is the [fs/cm]_displayInfo[] is recorded. 
+ *     the data is the [fs/cm]_displayInfo[] is recorded.
  *
  * Returns:
  *     Success: 0
@@ -1366,15 +1386,15 @@ parse_showEntry(char *a_line)
  * process_config_file()
  *
  * Description:
- *     Parse config file entries in two passes. In the first pass: 
+ *     Parse config file entries in two passes. In the first pass:
  *             - the syntax of all the entries is checked
- *             - host names are noted and the FSnamesList and CMnamesList 
- *               constructed. 
- *             - a count of the global thresholds and local thresholds of 
- *               each host are counted. 
+ *             - host names are noted and the FSnamesList and CMnamesList
+ *               constructed.
+ *             - a count of the global thresholds and local thresholds of
+ *               each host are counted.
  *             - "show" entries are processed.
  *     In the second pass:
- *             - thresholds are stored 
+ *             - thresholds are stored
  *
  * Returns:
  *     Success: 0
@@ -1479,7 +1499,7 @@ process_config_file(char *a_config_filename)
     }
 
     /* the threshold count of all hosts in increased by 1 for each global
-     * threshold. If one of the hosts has a local threshold for the same 
+     * threshold. If one of the hosts has a local threshold for the same
      * variable it would end up being counted twice. whats a few bytes of memory
      * wasted anyway ? */
 
@@ -1576,7 +1596,7 @@ process_config_file(char *a_config_filename)
            strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
        } else if (strcasecmp(opcode, "thresh") == 0) {
            /* if we have a threshold handler it may have arguments
-            * and the sscanf() above would not get them, so do the 
+            * and the sscanf() above would not get them, so do the
             * following */
            if (strlen(arg4)) {
                handlerPtr = line;
@@ -1640,6 +1660,7 @@ Print_FS_CB(void)
     struct afsmon_fs_Results_list *fslist;
     int i;
     int j;
+    int k;
 
     /* print valid info in the fs CB */
 
@@ -1656,16 +1677,20 @@ Print_FS_CB(void)
            fslist = afsmon_fs_ResultsCB[i].list;
            j = 0;
            while (j < numFS) {
-               if (!fslist->empty) {
-                   fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
-                           fslist->fsResults->probeNum,
-                           fslist->fsResults->connP->hostName);
-                   if (fslist->fsResults->probeOK)
-                       fprintf(debugFD, " NOTOK\n");
-                   else
-                       fprintf(debugFD, " OK\n");
-               } else
-                   fprintf(debugFD, "\t %d) -- empty --\n", j);
+               for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
+                   if (!(fslist->empty[k])) {
+                       fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
+                               j,
+                               fslist->fsResults[k]->probeNum,
+                               fslist->fsResults[k]->connP->hostName,
+                               fslist->fsResults[k]->collectionNumber);
+                       if (fslist->fsResults[k]->probeOK)
+                           fprintf(debugFD, " NOTOK\n");
+                       else
+                           fprintf(debugFD, " OK\n");
+                   } else
+                       fprintf(debugFD, "\t %d) -- empty --\n", j);
+               }
                fslist = fslist->next;
                j++;
            }
@@ -1698,6 +1723,7 @@ save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
     struct afsmon_fs_Results_list *tmp_fslist_item;    /* temp fs list item */
     struct xstat_fs_ProbeResults *tmp_fsPR;    /* temp ptr */
     int i;
+    int index;
 
     if (afsmon_debug) {
        fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
@@ -1705,6 +1731,19 @@ save_FS_results_inCB(int a_newProbeCycle)        /* start of a new probe cycle ? */
        fflush(debugFD);
     }
 
+    switch (xstat_fs_Results.collectionNumber) {
+    case AFS_XSTATSCOLL_FULL_PERF_INFO:
+       index = 0;
+       break;
+    case AFS_XSTATSCOLL_CBSTATS:
+       index = 1;
+    default:
+       if (index < 0) {
+           fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
+                   rn, xstat_fs_Results.collectionNumber);
+           afsmon_Exit(51);
+       }
+    }
 
     /* If a new probe cycle started, mark the list in the current buffer
      * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
@@ -1713,7 +1752,7 @@ save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
     if (a_newProbeCycle) {
        tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
        for (i = 0; i < numFS; i++) {
-           tmp_fslist_item->empty = 1;
+           tmp_fslist_item->empty[index] = 1;
            tmp_fslist_item = tmp_fslist_item->next;
        }
     }
@@ -1721,13 +1760,13 @@ save_FS_results_inCB(int a_newProbeCycle)       /* start of a new probe cycle ? */
     /* locate last unused item in list */
     tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
     for (i = 0; i < numFS; i++) {
-       if (tmp_fslist_item->empty)
+       if (tmp_fslist_item->empty[index])
            break;
        tmp_fslist_item = tmp_fslist_item->next;
     }
 
     /* if we could not find one we have an inconsistent list */
-    if (!tmp_fslist_item->empty) {
+    if (!tmp_fslist_item->empty[index]) {
        fprintf(stderr,
                "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
                rn, xstat_fs_Results.probeNum,
@@ -1735,7 +1774,7 @@ save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
        afsmon_Exit(50);
     }
 
-    tmp_fsPR = tmp_fslist_item->fsResults;
+    tmp_fsPR = tmp_fslist_item->fsResults[index];
 
     /* copy hostname and probe number and probe time and probe status.
      * if the probe failed return now */
@@ -1747,7 +1786,7 @@ save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
     tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
     if (xstat_fs_Results.probeOK) {    /* probeOK = 1 => notOK */
        /* we have a nonempty results structure so mark the list item used */
-       tmp_fslist_item->empty = 0;
+       tmp_fslist_item->empty[index] = 0;
        return (0);
     }
 
@@ -1760,14 +1799,16 @@ save_FS_results_inCB(int a_newProbeCycle)       /* start of a new probe cycle ? */
     tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
 
     /* copy the probe data information */
-    tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
+    tmp_fsPR->data.AFS_CollData_len =
+       min(xstat_fs_Results.data.AFS_CollData_len,
+           afsmon_fs_results_length[index]);
     memcpy(tmp_fsPR->data.AFS_CollData_val,
           xstat_fs_Results.data.AFS_CollData_val,
-          xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
+          tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
 
 
     /* we have a valid results structure so mark the list item used */
-    tmp_fslist_item->empty = 0;
+    tmp_fslist_item->empty[index] = 0;
 
     /* Print the fs circular buffer */
     Print_FS_CB();
@@ -1780,10 +1821,10 @@ save_FS_results_inCB(int a_newProbeCycle)       /* start of a new probe cycle ? */
  * fs_Results_ltoa()
  *
  * Description:
- *     The results of xstat probes are stored in a string format in 
+ *     The results of xstat probes are stored in a string format in
  *     the arrays curr_fsData and prev_fsData. The information stored in
- *     prev_fsData is copied to the screen. 
- *     This function converts xstat FS results from longs to strings and 
+ *     prev_fsData is copied to the screen.
+ *     This function converts xstat FS results from longs to strings and
  *     place them in the given buffer (a pointer to an item in curr_fsData).
  *     When a probe cycle completes, curr_fsData is copied to prev_fsData
  *     in afsmon_FS_Hnadler().
@@ -1798,11 +1839,6 @@ fs_Results_ltoa(struct fs_Display_Data *a_fsData,        /* target buffer */
 {                              /* fs_Results_ltoa */
 
     static char rn[] = "fs_Results_ltoa";      /* routine name */
-    afs_int32 *srcbuf;
-    struct fs_stats_FullPerfStats *fullPerfP;
-    int idx;
-    int i, j;
-    afs_int32 *tmpbuf;
 
     if (afsmon_debug) {
        fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
@@ -1810,14 +1846,70 @@ fs_Results_ltoa(struct fs_Display_Data *a_fsData,       /* target buffer */
        fflush(debugFD);
     }
 
+    switch (a_fsResults->collectionNumber) {
+    case AFS_XSTATSCOLL_FULL_PERF_INFO:
+       fs_FullPerfs_ltoa(a_fsData, a_fsResults);
+       break;
+    case AFS_XSTATSCOLL_CBSTATS:
+       fs_CallBackStats_ltoa(a_fsData, a_fsResults);
+       break;
+    default:
+       if (afsmon_debug) {
+           fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
+                   rn, a_fsResults->collectionNumber);
+       }
+    }
+
+    return (0);
+}                              /* fs_Results_ltoa */
+
+/*-----------------------------------------------------------------------
+ * fs_FullPerfs_ltoa()
+ *
+ * Description:
+ *     Convert the full perf xstat collection from int32s to strings.
+ *
+ * Returns:
+ *     Always returns 0.
+ *----------------------------------------------------------------------*/
+static int
+fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
+               struct xstat_fs_ProbeResults *a_fsResults)
+{
+    afs_int32 *srcbuf;
+    struct fs_stats_FullPerfStats *fullPerfP;
+    int idx;
+    int i, j;
+    afs_int32 *tmpbuf;
+    afs_int32 numInt32s;
+
     fullPerfP = (struct fs_stats_FullPerfStats *)
        (a_fsResults->data.AFS_CollData_val);
 
-    /* there are two parts to the xstat FS statistics 
+    /* there are two parts to the xstat FS statistics
      * - fullPerfP->overall which give the overall performance statistics, and
      * - fullPerfP->det which gives detailed info about file server operation
      * execution times */
 
+    /*
+     * Unfortunately, the full perf stats contain timeval structures which
+     * do not have the same size everywhere. Avoid displaying gargbage,
+     * but at least try to show the overall stats.
+     */
+    numInt32s = a_fsResults->data.AFS_CollData_len;
+    if (numInt32s !=
+       (sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32))) {
+       srcbuf = a_fsResults->data.AFS_CollData_val;
+       for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
+           if (i < numInt32s && i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS) {
+               sprintf(a_fsData->data[i], "%d", srcbuf[i]);
+           } else {
+               sprintf(a_fsData->data[i], "%s", "--");
+           }
+       }
+       return 0;
+    }
+
     /* copy overall performance statistics */
     srcbuf = (afs_int32 *) & (fullPerfP->overall);
     idx = 0;
@@ -1904,18 +1996,44 @@ fs_Results_ltoa(struct fs_Display_Data *a_fsData,       /* target buffer */
     }
 
     return (0);
-}                              /* fs_Results_ltoa */
+}
 
+/*-----------------------------------------------------------------------
+ * fs_CallBackStats_ltoa()
+ *
+ * Description:
+ *     Convert the callback counter xstat collection from
+ *     int32s to strings.
+ *
+ * Returns:
+ *     Always returns 0.
+ *----------------------------------------------------------------------*/
+
+static int
+fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
+                     struct xstat_fs_ProbeResults *a_fsResults)
+{
+    int idx;
+    int i;
+    int len = a_fsResults->data.AFS_CollData_len;
+    afs_int32 *val = a_fsResults->data.AFS_CollData_val;
 
+    /* place callback stats after the full perf stats */
+    idx = NUM_FS_FULLPERF_ENTRIES;
+    for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
+       sprintf(a_fsData->data[idx++], "%u", val[i]);
+    }
+    return 0;
+}
 
 /*-----------------------------------------------------------------------
  * execute_thresh_handler()
  *
  * Description:
- *     Execute a threshold handler. An agrv[] array of pointers is 
- *     constructed from the given data. A child process is forked 
+ *     Execute a threshold handler. An agrv[] array of pointers is
+ *     constructed from the given data. A child process is forked
  *     which immediately calls afsmon_Exit() with indication that a
- *     threshold handler is to be exec'ed insted of exiting. 
+ *     threshold handler is to be exec'ed insted of exiting.
  *
  * Returns:
  *     Success: 0
@@ -2014,11 +2132,11 @@ execute_thresh_handler(char *a_handler,         /* ptr to handler function + args */
  * Description:
  *     Checks the thresholds and sets the overflow flag. Recall that the
  *     thresholds for each host are stored in the hostEntry lists
- *     [fs/cm]nameList arrays. The probe results are passed to this 
+ *     [fs/cm]nameList arrays. The probe results are passed to this
  *     function in the display-ready format - ie., as strings. Though
  *     this looks stupid the overhead incurred in converting the strings
- *     back to floats and comparing them is insignificant and 
- *     programming is easier this way. 
+ *     back to floats and comparing them is insignificant and
+ *     programming is easier this way.
  *     The threshold flags are a part of the display structures
  *     curr_[fs/cm]Data.
  *
@@ -2108,11 +2226,11 @@ check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
  * Description:
  *     Does the following:
  *     - if the probe number changed (ie, a cycle completed) curr_fsData
- *     is copied to prev_fsData, curr_fsData zeroed and refresh the 
+ *     is copied to prev_fsData, curr_fsData zeroed and refresh the
  *     overview screen and file server screen with the new data.
  *     - store the results of the current probe from xstat_fs_Results into
  *     curr_fsData. ie., convert longs to strings.
- *     - check the thresholds 
+ *     - check the thresholds
  *
  * Returns:
  *     Success: 0
@@ -2127,7 +2245,7 @@ save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
     struct fs_Display_Data *curr_fsDataP;      /* tmp ptr to curr_fsData */
     struct fs_Display_Data *prev_fsDataP;      /* tmp ptr to prev_fsData */
     struct afsmon_hostEntry *curr_host;
-    static int probes_Received = 0;    /* number of probes reveived in
+    static int results_Received = 0;   /* number of probes reveived in
                                         * the current cycle. If this is equal to numFS we got all
                                         * the data we want in this cycle and can now display it */
     int numBytes;
@@ -2163,7 +2281,7 @@ save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
     }
 
     /*  Check the status of the probe. If it succeeded, we store its
-     * results in the display data structure. If it failed we only mark 
+     * results in the display data structure. If it failed we only mark
      * the failed status in the display data structure. */
 
     if (a_fsResults->probeOK) {        /* 1 => notOK the xstat results */
@@ -2180,11 +2298,11 @@ save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
     } else {                   /* probe succeeded, update display data structures */
        curr_fsDataP->probeOK = 1;
 
-       /* covert longs to strings and place them in curr_fsDataP */
+       /* convert longs to strings and place them in curr_fsDataP */
        fs_Results_ltoa(curr_fsDataP, a_fsResults);
 
        /* compare with thresholds and set the overflow flags.
-        * note that the threshold information is in the hostEntry structure and 
+        * note that the threshold information is in the hostEntry structure and
         * each threshold item has a positional index associated with it */
 
        /* locate the hostEntry for this host */
@@ -2227,9 +2345,9 @@ save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
     /* if we have received a reply from all the hosts for this probe cycle,
      * it is time to display the data */
 
-    probes_Received++;
-    if (probes_Received == numFS) {
-       probes_Received = 0;
+    results_Received++;
+    if (results_Received == numFS * num_fs_collections) {
+       results_Received = 0;
 
        if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
            sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
@@ -2248,12 +2366,12 @@ save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
        /* initialize curr_fsData but retain the threshold flag information.
         * The previous state of threshold flags is used in check_fs_thresholds() */
 
-       numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
+       numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
        curr_fsDataP = curr_fsData;
        for (i = 0; i < numFS; i++) {
            curr_fsDataP->probeOK = 0;
            curr_fsDataP->ovfCount = 0;
-           memset((char *)curr_fsDataP->data, 0, numBytes);
+           memset(curr_fsDataP->data, 0, numBytes);
            curr_fsDataP++;
        }
 
@@ -2320,9 +2438,10 @@ afsmon_FS_Handler(void)
 
     if (afsmon_debug) {
        fprintf(debugFD,
-               "[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n", rn,
+               "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
                xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
-               xstat_fs_Results.probeOK ? "FAILED" : "OK");
+               xstat_fs_Results.probeOK ? "FAILED" : "OK",
+               xstat_fs_Results.collectionNumber);
        fflush(debugFD);
     }
 
@@ -2337,7 +2456,7 @@ afsmon_FS_Handler(void)
        }
     }
 
-    /* Update current probe number and circular buffer index. if current 
+    /* Update current probe number and circular buffer index. if current
      * probenum changed make sure it is only by 1 */
 
     newProbeCycle = 0;
@@ -2355,6 +2474,7 @@ afsmon_FS_Handler(void)
        }
     }
 
+
     /* store the results of this probe in the FS circular buffer */
     if (num_bufSlots)
        save_FS_results_inCB(newProbeCycle);
@@ -2362,7 +2482,7 @@ afsmon_FS_Handler(void)
 
     /* store the results of the current probe in the fs data display structure.
      * if the current probe number changed, swap the current and previous display
-     * structures. note that the display screen is updated from these structures 
+     * structures. note that the display screen is updated from these structures
      * and should start showing the data of the just completed probe cycle */
 
     save_FS_data_forDisplay(&xstat_fs_Results);
@@ -2372,12 +2492,12 @@ afsmon_FS_Handler(void)
 
 
 
-/*----------------------------------------------------------------------- * 
- * Print_CM_CB()     
+/*----------------------------------------------------------------------- *
+ * Print_CM_CB()
  *
  * Description:
  *     Debug routine.
- *     Prints the  Cache Manager circular buffer 
+ *     Prints the  Cache Manager circular buffer
  *----------------------------------------------------------------------*/
 
 void
@@ -2387,6 +2507,7 @@ Print_CM_CB(void)
     struct afsmon_cm_Results_list *cmlist;
     int i;
     int j;
+    int k;
 
     /* print valid info in the cm CB */
 
@@ -2403,16 +2524,21 @@ Print_CM_CB(void)
            cmlist = afsmon_cm_ResultsCB[i].list;
            j = 0;
            while (j < numCM) {
-               if (!cmlist->empty) {
-                   fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
-                           cmlist->cmResults->probeNum,
-                           cmlist->cmResults->connP->hostName);
-                   if (cmlist->cmResults->probeOK)
-                       fprintf(debugFD, " NOTOK\n");
-                   else
-                       fprintf(debugFD, " OK\n");
-               } else
-                   fprintf(debugFD, "\t %d) -- empty --\n", j);
+               for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
+                   if (!cmlist->empty[k]) {
+                       fprintf(debugFD,
+                               "\t %d) probeNum = %d host = %s cn = %d",
+                               j,
+                               cmlist->cmResults[k]->probeNum,
+                               cmlist->cmResults[k]->connP->hostName,
+                               cmlist->cmResults[k]->collectionNumber);
+                       if (cmlist->cmResults[k]->probeOK)
+                           fprintf(debugFD, " NOTOK\n");
+                       else
+                           fprintf(debugFD, " OK\n");
+                   } else
+                       fprintf(debugFD, "\t %d) -- empty --\n", j);
+               }
                cmlist = cmlist->next;
                j++;
            }
@@ -2447,6 +2573,7 @@ save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
     struct afsmon_cm_Results_list *tmp_cmlist_item;    /* temp cm list item */
     struct xstat_cm_ProbeResults *tmp_cmPR;    /* temp ptr */
     int i;
+    int index;
 
 
     if (afsmon_debug) {
@@ -2455,6 +2582,14 @@ save_CM_results_inCB(int a_newProbeCycle)        /* start of new probe cycle ? */
        fflush(debugFD);
     }
 
+    if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
+       index = 0;
+    } else {
+       fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
+               rn, xstat_cm_Results.collectionNumber);
+       afsmon_Exit(91);
+    }
+
     /* If a new probe cycle started, mark the list in the current buffer
      * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
      * incremented in afsmon_CM_Handler() */
@@ -2462,7 +2597,7 @@ save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
     if (a_newProbeCycle) {
        tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
        for (i = 0; i < numCM; i++) {
-           tmp_cmlist_item->empty = 1;
+           tmp_cmlist_item->empty[index] = 1;
            tmp_cmlist_item = tmp_cmlist_item->next;
        }
     }
@@ -2470,13 +2605,13 @@ save_CM_results_inCB(int a_newProbeCycle)       /* start of new probe cycle ? */
     /* locate last unused item in list */
     tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
     for (i = 0; i < numCM; i++) {
-       if (tmp_cmlist_item->empty)
+       if (tmp_cmlist_item->empty[index])
            break;
        tmp_cmlist_item = tmp_cmlist_item->next;
     }
 
     /* if we could not find one we have an inconsistent list */
-    if (!tmp_cmlist_item->empty) {
+    if (!tmp_cmlist_item->empty[index]) {
        fprintf(stderr,
                "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
                rn, xstat_cm_Results.probeNum,
@@ -2484,7 +2619,7 @@ save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
        afsmon_Exit(90);
     }
 
-    tmp_cmPR = tmp_cmlist_item->cmResults;
+    tmp_cmPR = tmp_cmlist_item->cmResults[index];
 
     /* copy hostname and probe number and probe time and probe status.
      * if the probe failed return now */
@@ -2496,7 +2631,7 @@ save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
     tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
     if (xstat_cm_Results.probeOK) {    /* probeOK = 1 => notOK */
        /* we have a nonempty results structure so mark the list item used */
-       tmp_cmlist_item->empty = 0;
+       tmp_cmlist_item->empty[index] = 0;
        return (0);
     }
 
@@ -2513,14 +2648,15 @@ save_CM_results_inCB(int a_newProbeCycle)       /* start of new probe cycle ? */
 
     /* copy the probe data information */
     tmp_cmPR->data.AFSCB_CollData_len =
-       xstat_cm_Results.data.AFSCB_CollData_len;
+       min(xstat_cm_Results.data.AFSCB_CollData_len,
+           afsmon_cm_results_length[index]);
     memcpy(tmp_cmPR->data.AFSCB_CollData_val,
           xstat_cm_Results.data.AFSCB_CollData_val,
-          xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
+          tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
 
 
     /* we have a valid results structure so mark the list item used */
-    tmp_cmlist_item->empty = 0;
+    tmp_cmlist_item->empty[index] = 0;
 
     /* print the stored info - to make sure we copied it right */
     /*   Print_cm_FullPerfInfo(tmp_cmPR);        */
@@ -2535,10 +2671,10 @@ save_CM_results_inCB(int a_newProbeCycle)       /* start of new probe cycle ? */
  * cm_Results_ltoa()
  *
  * Description:
- *     The results of xstat probes are stored in a string format in 
+ *     The results of xstat probes are stored in a string format in
  *     the arrays curr_cmData and prev_cmData. The information stored in
- *     prev_cmData is copied to the screen. 
- *     This function converts xstat FS results from longs to strings and 
+ *     prev_cmData is copied to the screen.
+ *     This function converts xstat FS results from longs to strings and
  *     places them in the given buffer (a pointer to an item in curr_cmData).
  *     When a probe cycle completes, curr_cmData is copied to prev_cmData
  *     in afsmon_CM_Handler().
@@ -2572,7 +2708,7 @@ cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
 
     /* There are 4 parts to CM statistics
      * - Overall performance statistics (including up/down statistics)
-     * - This CMs FS RPC operations info 
+     * - This CMs FS RPC operations info
      * - This CMs FS RPC errors info
      * - This CMs FS transfers info
      * - Authentication info
@@ -2783,11 +2919,11 @@ cm_Results_ltoa(struct cm_Display_Data *a_cmData,       /* target buffer */
  * Description:
  *     Checks the thresholds and sets the overflow flag. Recall that the
  *     thresholds for each host are stored in the hostEntry lists
- *     [fs/cm]nameList arrays. The probe results are passed to this 
+ *     [fs/cm]nameList arrays. The probe results are passed to this
  *     function in the display-ready format - ie., as strings. Though
  *     this looks stupid the overhead incurred in converting the strings
- *     back to floats and comparing them is insignificant and 
- *     programming is easier this way. 
+ *     back to floats and comparing them is insignificant and
+ *     programming is easier this way.
  *     The threshold flags are a part of the display structures
  *     curr_[fs/cm]Data.
  *
@@ -2878,11 +3014,11 @@ check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry,       /* ptr to hostEntry */
  * Description:
  *     Does the following:
  *     - if the probe number changed (ie, a cycle completed) curr_cmData
- *     is copied to prev_cmData, curr_cmData zeroed and refresh the 
+ *     is copied to prev_cmData, curr_cmData zeroed and refresh the
  *     overview screen and file server screen with the new data.
  *     - store the results of the current probe from xstat_cm_Results into
  *     curr_cmData. ie., convert longs to strings.
- *     - check the thresholds 
+ *     - check the thresholds
  *
  * Returns:
  *     Success: 0
@@ -2898,7 +3034,7 @@ save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
     struct cm_Display_Data *curr_cmDataP;
     struct cm_Display_Data *prev_cmDataP;
     struct afsmon_hostEntry *curr_host;
-    static int probes_Received = 0;    /* number of probes reveived in
+    static int results_Received = 0;   /* number of probes reveived in
                                         * the current cycle. If this is equal to numFS we got all
                                         * the data we want in this cycle and can now display it */
     int numBytes;
@@ -2933,7 +3069,7 @@ save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
     }
 
     /*  Check the status of the probe. If it succeeded, we store its
-     * results in the display data structure. If it failed we only mark 
+     * results in the display data structure. If it failed we only mark
      * the failed status in the display data structure. */
 
 
@@ -2956,7 +3092,7 @@ save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
        cm_Results_ltoa(curr_cmDataP, a_cmResults);
 
        /* compare with thresholds and set the overflow flags.
-        * note that the threshold information is in the hostEntry structure and 
+        * note that the threshold information is in the hostEntry structure and
         * each threshold item has a positional index associated with it */
 
        /* locate the hostEntry for this host */
@@ -3038,9 +3174,9 @@ save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
     /* if we have received a reply from all the hosts for this probe cycle,
      * it is time to display the data */
 
-    probes_Received++;
-    if (probes_Received == numCM) {
-       probes_Received = 0;
+    results_Received++;
+    if (results_Received == numCM * num_cm_collections) {
+       results_Received = 0;
 
        if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
            sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
@@ -3065,7 +3201,7 @@ save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
        for (i = 0; i < numCM; i++) {
            curr_cmDataP->probeOK = 0;
            curr_cmDataP->ovfCount = 0;
-           memset((char *)curr_cmDataP->data, 0, numBytes);
+           memset(curr_cmDataP->data, 0, numBytes);
            curr_cmDataP++;
        }
 
@@ -3147,7 +3283,7 @@ afsmon_CM_Handler(void)
        }
     }
 
-    /* Update current probe number and circular buffer index. if current 
+    /* Update current probe number and circular buffer index. if current
      * probenum changed make sure it is only by 1 */
 
     newProbeCycle = 0;
@@ -3171,7 +3307,7 @@ afsmon_CM_Handler(void)
 
     /* store the results of the current probe in the cm data display structure.
      * if the current probe number changed, swap the current and previous display
-     * structures. note that the display screen is updated from these structures 
+     * structures. note that the display screen is updated from these structures
      * and should start showing the data of the just completed probe cycle */
 
     save_CM_data_forDisplay(&xstat_cm_Results);
@@ -3218,7 +3354,7 @@ init_fs_buffers(void)
        afsmon_fs_ResultsCB[i].probeNum = 0;
     }
 
-    /* create  a list of numFS items to store fs probe results for 
+    /* create  a list of numFS items to store fs probe results for
      * each slot in CB */
 
     if (numFS) {               /* if we have file servers to monitor */
@@ -3227,7 +3363,7 @@ init_fs_buffers(void)
            while (numfs--) {
 
                /* if any of these mallocs fail we only need to free the memory we
-                * have allocated in this iteration. the rest of it which is in a 
+                * have allocated in this iteration. the rest of it which is in a
                 * proper linked list will be freed in afsmon_Exit */
 
                /* allocate memory for an fs list item */
@@ -3236,36 +3372,37 @@ init_fs_buffers(void)
                if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
                    return (-1);
 
-               /* allocate memory to store xstat_fs_Results */
-               new_fsPR = (struct xstat_fs_ProbeResults *)
-                   malloc(sizeof(struct xstat_fs_ProbeResults));
-               if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
-                   free(new_fslist_item);
-                   return (-1);
-               }
-               new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
-                   malloc(sizeof(struct xstat_fs_ConnectionInfo));
-               if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
-                   free(new_fslist_item);
-                   free(new_fsPR);
-                   return (-1);
-               }
+               for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
+                   /* allocate memory to store xstat_fs_Results */
+                   new_fsPR = (struct xstat_fs_ProbeResults *)
+                       malloc(sizeof(struct xstat_fs_ProbeResults));
+                   if (!new_fsPR) {
+                       free(new_fslist_item);
+                       return (-1);
+                   }
 
-               /* >>>  need to allocate rx connection info structure here <<< */
+                   new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
+                       malloc(sizeof(struct xstat_fs_ConnectionInfo));
+                   if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
+                       free(new_fslist_item);
+                       free(new_fsPR);
+                       return (-1);
+                   }
 
-               new_fsPR->data.AFS_CollData_val =
-                   (afs_int32 *) malloc(XSTAT_FS_FULLPERF_RESULTS_LEN *
-                                        sizeof(afs_int32));
-               if (new_fsPR->data.AFS_CollData_val == NULL) {
-                   free(new_fslist_item);
-                   free(new_fsPR->connP);
-                   free(new_fsPR);
-                   return (-1);
+                   /* >>>  need to allocate rx connection info structure here <<< */
+                   new_fsPR->data.AFS_CollData_val = (afs_int32 *)
+                      malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
+                   if (new_fsPR->data.AFS_CollData_val == NULL) {
+                      free(new_fslist_item);
+                      free(new_fsPR->connP);
+                      free(new_fsPR);
+                      return (-1);
+                   }
+                   new_fslist_item->fsResults[i] = new_fsPR;
+                   new_fslist_item->empty[i] = 1;
                }
 
                /* initialize this list entry */
-               new_fslist_item->fsResults = new_fsPR;
-               new_fslist_item->empty = 1;
                new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
 
                /* store it at the end of the fs list in the current CB slot */
@@ -3334,7 +3471,7 @@ init_cm_buffers(void)
        afsmon_cm_ResultsCB[i].probeNum = 0;
     }
 
-    /* create  a list of numCM items to store fs probe results for 
+    /* create  a list of numCM items to store fs probe results for
      * each slot in CB */
 
     if (numCM) {               /* if we have file servers to monitor */
@@ -3343,7 +3480,7 @@ init_cm_buffers(void)
            while (numcm--) {
 
                /* if any of these mallocs fail we only need to free the memory we
-                * have allocated in this iteration. the rest of it which is in a 
+                * have allocated in this iteration. the rest of it which is in a
                 * proper linked list will be freed in afsmon_Exit */
 
                /* allocate memory for an fs list item */
@@ -3352,36 +3489,39 @@ init_cm_buffers(void)
                if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
                    return (-1);
 
-               /* allocate memory to store xstat_cm_Results */
-               new_cmPR = (struct xstat_cm_ProbeResults *)
-                   malloc(sizeof(struct xstat_cm_ProbeResults));
-               if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
-                   free(new_cmlist_item);
-                   return (-1);
-               }
-               new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
-                   malloc(sizeof(struct xstat_cm_ConnectionInfo));
-               if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0) {
-                   free(new_cmlist_item);
-                   free(new_cmPR);
-                   return (-1);
-               }
+               for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
+                   /* allocate memory to store xstat_cm_Results */
+                   new_cmPR = (struct xstat_cm_ProbeResults *)
+                       malloc(sizeof(struct xstat_cm_ProbeResults));
+                   if (!new_cmPR) {
+                       free(new_cmlist_item);
+                       return (-1);
+                   }
+                   new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
+                       malloc(sizeof(struct xstat_cm_ConnectionInfo));
+                   if (!new_cmPR->connP) {
+                       free(new_cmlist_item);
+                       free(new_cmPR);
+                       return (-1);
+                   }
 
-               /* >>>  need to allocate rx connection info structure here <<< */
+                   /* >>>  need to allocate rx connection info structure here <<< */
 
-               new_cmPR->data.AFSCB_CollData_val =
-                   (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN *
-                                        sizeof(afs_int32));
-               if (new_cmPR->data.AFSCB_CollData_val == NULL) {
-                   free(new_cmlist_item);
-                   free(new_cmPR->connP);
-                   free(new_cmPR);
-                   return (-1);
+                   new_cmPR->data.AFSCB_CollData_val =
+                       (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
+                                            * sizeof(afs_int32));
+                   if (new_cmPR->data.AFSCB_CollData_val == NULL) {
+                       free(new_cmlist_item);
+                       free(new_cmPR->connP);
+                       free(new_cmPR);
+                       return (-1);
+                   }
+
+                   new_cmlist_item->cmResults[i] = new_cmPR;
+                   new_cmlist_item->empty[i] = 1;
                }
 
                /* initialize this list entry */
-               new_cmlist_item->cmResults = new_cmPR;
-               new_cmlist_item->empty = 1;
                new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
 
                /* store it at the end of the cm list in the current CB slot */
@@ -3423,8 +3563,8 @@ init_cm_buffers(void)
  *
  * Description:
  *     Allocate and initialize the buffers used for printing results
- *     to the display screen. These buffers store the current and 
- *     previous probe results in ascii format. 
+ *     to the display screen. These buffers store the current and
+ *     previous probe results in ascii format.
  *
  * Returns:
  *     Success: 0
@@ -3455,7 +3595,7 @@ init_print_buffers(void)
     /* we need two instances of this structure - one (curr_fsData) for storing
      * the results of the fs probes currently in progress and another (prev_fsData)
      * for the last completed probe. The display is updated from the contents of
-     * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever 
+     * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
      * the probe number changes */
 
     if (numFS) {
@@ -3555,7 +3695,7 @@ quit_signal(int sig)
  * Description:
  *     This is where we start it all. Initialize an array of sockets for
  *     file servers and cache cache managers and call the xstat_[fs/cm]_Init
- *     routines. The last step is to call the gtx input server which 
+ *     routines. The last step is to call the gtx input server which
  *     grabs control of the keyboard.
  *
  * Returns:
@@ -3578,12 +3718,12 @@ afsmon_execute(void)
     struct afsmon_hostEntry *curr_FS;  /* ptr to FS name list */
     struct afsmon_hostEntry *curr_CM;  /* ptr to CM name list */
     struct hostent *he;                /* host entry */
-    afs_int32 *collIDP;                /* ptr to collection ID */
-    int numCollIDs;            /* number of collection IDs */
     int FSinitFlags = 0;       /* flags for xstat_fs_Init */
     int CMinitFlags = 0;       /* flags for xstat_cm_Init */
     int code;                  /* function return code */
     struct timeval tv;         /* time structure */
+    int i;
+    short index;
 
     if (afsmon_debug) {
        fprintf(debugFD, "[ %s ] Called\n", rn);
@@ -3593,6 +3733,8 @@ afsmon_execute(void)
 
     /* process file server entries */
     if (numFS) {
+       afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
+
        /* Allocate an array of sockets for each fileserver we monitor */
 
        FSsktbytes = numFS * sizeof(struct sockaddr_in);
@@ -3631,18 +3773,22 @@ afsmon_execute(void)
            curr_FS = curr_FS->next;
        }
 
-       /* initialize collection IDs. We need only one entry since we collect
-        * all the information from xstat */
-
-       numCollIDs = 1;
-       collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
-       if (collIDP == NULL) {
-           fprintf(stderr,
-                   "[ %s ] failed to allocate a measely afs_int32 word.Argh!\n",
-                   rn);
-           return (-1);
+       /* Initialize collection IDs, depending on the data requested. */
+       num_fs_collections = 0;
+       for (i = 0; i < fs_DisplayItems_count; i++) {
+           index = fs_Display_map[i];
+           if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
+               collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
+               break;
+           }
+       }
+       for (i = 0; i < fs_DisplayItems_count; i++) {
+           index = fs_Display_map[i];
+           if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
+               collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
+               break;
+           }
        }
-       *collIDP = 2;           /* USE A macro for this */
 
        FSinitFlags = 0;
        if (afsmon_onceOnly)    /* option not provided at this time */
@@ -3658,8 +3804,8 @@ afsmon_execute(void)
                             afsmon_probefreq,  /*probe frequency */
                             afsmon_FS_Handler, /*Handler routine */
                             FSinitFlags,       /*Initialization flags */
-                            numCollIDs,        /*Number of collection IDs */
-                            collIDP);  /*Ptr to collection ID */
+                            num_fs_collections,        /*Number of collection IDs */
+                            collIDs);  /*Ptr to collection ID */
 
        if (code) {
            fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
@@ -3672,6 +3818,8 @@ afsmon_execute(void)
     /* end of process fileserver entries */
     /* process cache manager entries */
     if (numCM) {
+       afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
+
        /* Allocate an array of sockets for each cache manager we monitor */
 
        CMsktbytes = numCM * sizeof(struct sockaddr_in);
@@ -3699,12 +3847,8 @@ afsmon_execute(void)
            }
            strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN);      /* complete name */
            memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
-#if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
-           curr_skt->sin_family = AF_INET;             /*Internet family */
-#else
-           curr_skt->sin_family = htons(AF_INET);      /*Internet family */
-#endif
-           curr_skt->sin_port = htons(7001);   /*Cache Manager port */
+           curr_skt->sin_family = AF_INET;
+           curr_skt->sin_port = htons(7001);   /* Cache Manager port */
 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
            curr_skt->sin_len = sizeof(struct sockaddr_in);
 #endif
@@ -3716,16 +3860,8 @@ afsmon_execute(void)
 
        /* initialize collection IDs. We need only one entry since we collect
         * all the information from xstat */
-
-       numCollIDs = 1;
-       collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
-       if (collIDP == NULL) {
-           fprintf(stderr,
-                   "[ %s ] failed to allocate a measely long word.Argh!\n",
-                   rn);
-           return (-1);
-       }
-       *collIDP = 2;           /* USE A macro for this */
+       num_cm_collections = 0;
+       collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
 
        CMinitFlags = 0;
        if (afsmon_onceOnly)    /* once only ? */
@@ -3741,8 +3877,8 @@ afsmon_execute(void)
                             afsmon_probefreq,  /*probe frequency */
                             afsmon_CM_Handler, /*Handler routine */
                             CMinitFlags,       /*Initialization flags */
-                            numCollIDs,        /*Number of collection IDs */
-                            collIDP);  /*Ptr to collection ID */
+                            num_cm_collections,        /*Number of collection IDs */
+                            collIDs);  /*Ptr to collection ID */
 
        if (code) {
            fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
@@ -3753,7 +3889,7 @@ afsmon_execute(void)
 
 
     /* end of process cache manager entries */
-    /* if only one probe was required setup a waiting process for the 
+    /* if only one probe was required setup a waiting process for the
      * termination signal */
     if (afsmon_onceOnly) {
        code = LWP_WaitProcess(&terminationEvent);
@@ -3768,7 +3904,7 @@ afsmon_execute(void)
     }
 
     /* start the gtx input server */
-    code = (int) gtx_InputServer(afsmon_win);
+    code = (intptr_t)gtx_InputServer(afsmon_win);
     if (code) {
        fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
        afsmon_Exit(140);
@@ -3934,7 +4070,7 @@ afsmonInit(struct cmd_syndesc *as, void *arock)
     FSnameList = (struct afsmon_hostEntry *)0;
     CMnameList = (struct afsmon_hostEntry *)0;
 
-    /* The -config option is mutually exclusive with the -fshosts,-cmhosts 
+    /* The -config option is mutually exclusive with the -fshosts,-cmhosts
      * options */
 
     if (as->parms[P_CONFIG].items) {
@@ -3953,7 +4089,7 @@ afsmonInit(struct cmd_syndesc *as, void *arock)
 
 
     /* If a file server host is specified on the command line we reuse
-     * parse_hostEntry() function . Just the pass the info as if it were 
+     * parse_hostEntry() function . Just the pass the info as if it were
      * read off the config file */
 
     if (as->parms[P_FSHOSTS].items) {
@@ -4139,7 +4275,7 @@ main(int argc, char **argv)
                "number of buffer slots");
 
     /*
-     * Parse command-line switches & execute afsmonitor 
+     * Parse command-line switches & execute afsmonitor
      */
 
     code = cmd_Dispatch(argc, argv);