e19600eeb391cf12883d5d8db3371cc9849a489b
[openafs.git] / src / fsprobe / fsprobe.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Description:
12  *      Implementation of the AFS FileServer probe facility.
13  *
14  *------------------------------------------------------------------------*/
15
16 #include <afsconfig.h>
17 #include <afs/param.h>
18
19 #include <roken.h>
20
21 #include <pthread.h>
22 #include <afs/cellconfig.h>
23 #include <afs/afsint.h>
24 #include <afs/afsutil.h>
25 #include <afs/volser.h>
26 #include <afs/volser_prototypes.h>
27 #define FSINT_COMMON_XG
28 #include <afs/afscbint.h>
29
30 #include "fsprobe.h"            /*Interface for this module */
31
32 /*
33  * Exported variables.
34  */
35 int fsprobe_numServers;         /*Num servers connected */
36 struct fsprobe_ConnectionInfo *fsprobe_ConnInfo;        /*Ptr to connection array */
37 struct fsprobe_ProbeResults fsprobe_Results;    /*Latest probe results */
38 int fsprobe_ProbeFreqInSecs;    /*Probe freq. in seconds */
39
40 /*
41  * Private globals.
42  */
43 static int fsprobe_initflag = 0;        /*Was init routine called? */
44 static int fsprobe_debug = 0;   /*Debugging output enabled? */
45 static int (*fsprobe_Handler) (void);   /*Probe handler routine */
46 static pthread_t fsprobe_thread;        /*Probe thread */
47 static int fsprobe_statsBytes;  /*Num bytes in stats block */
48 static int fsprobe_probeOKBytes;        /*Num bytes in probeOK block */
49 static opr_mutex_t fsprobe_force_lock;  /*Lock to force probe */
50 static opr_cv_t fsprobe_force_cv;       /*Condvar to force probe */
51
52 /*------------------------------------------------------------------------
53  * [private] fsprobe_CleanupInit
54  *
55  * Description:
56  *      Set up for recovery after an error in initialization (i.e.,
57  *      during a call to fsprobe_Init.
58  *
59  * Arguments:
60  *      None.
61  *
62  * Returns:
63  *      0 on success,
64  *      Error value otherwise.
65  *
66  * Environment:
67  *      This routine is private to the module.
68  *
69  * Side Effects:
70  *      Zeros out basic data structures.
71  *------------------------------------------------------------------------*/
72
73 static int
74 fsprobe_CleanupInit(void)
75 {                               /*fsprobe_CleanupInit */
76
77     afs_int32 code;             /*Return code from callback stubs */
78     struct rx_call *rxcall;     /*Bogus param */
79     AFSCBFids *Fids_Array;      /*Bogus param */
80     AFSCBs *CallBack_Array;     /*Bogus param */
81     struct interfaceAddr *interfaceAddr;        /*Bogus param */
82
83     fsprobe_ConnInfo = (struct fsprobe_ConnectionInfo *)0;
84     memset(&fsprobe_Results, 0, sizeof(struct fsprobe_ProbeResults));
85
86     rxcall = (struct rx_call *)0;
87     Fids_Array = (AFSCBFids *) 0;
88     CallBack_Array = (AFSCBs *) 0;
89     interfaceAddr = NULL;
90
91     code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
92     if (code)
93         return (code);
94     code = SRXAFSCB_InitCallBackState2(rxcall, interfaceAddr);
95     if (code)
96         return (code);
97     code = SRXAFSCB_Probe(rxcall);
98     return (code);
99
100 }                               /*fsprobe_CleanupInit */
101
102
103 /*------------------------------------------------------------------------
104  * [exported] fsprobe_Cleanup
105  *
106  * Description:
107  *      Clean up our memory and connection state.
108  *
109  * Arguments:
110  *      int a_releaseMem : Should we free up malloc'ed areas?
111  *
112  * Returns:
113  *      0 on total success,
114  *      -1 if the module was never initialized, or there was a problem
115  *              with the fsprobe connection array.
116  *
117  * Environment:
118  *      fsprobe_numServers should be properly set.  We don't do anything
119  *      unless fsprobe_Init() has already been called.
120  *
121  * Side Effects:
122  *      Shuts down Rx connections gracefully, frees allocated space
123  *      (if so directed).
124  *------------------------------------------------------------------------*/
125
126 int
127 fsprobe_Cleanup(int a_releaseMem)
128 {                               /*fsprobe_Cleanup */
129
130     static char rn[] = "fsprobe_Cleanup";       /*Routine name */
131     int code;                   /*Return code */
132     int conn_idx;               /*Current connection index */
133     struct fsprobe_ConnectionInfo *curr_conn;   /*Ptr to fsprobe connection */
134
135     /*
136      * Assume the best, but check the worst.
137      */
138     if (!fsprobe_initflag) {
139         fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
140         return (-1);
141     } else
142         code = 0;
143
144     /*
145      * Take care of all Rx connections first.  Check to see that the
146      * server count is a legal value.
147      */
148     if (fsprobe_numServers <= 0) {
149         fprintf(stderr,
150                 "[%s] Illegal number of servers to clean up (fsprobe_numServers = %d)\n",
151                 rn, fsprobe_numServers);
152         code = -1;
153     } else {
154         if (fsprobe_ConnInfo != (struct fsprobe_ConnectionInfo *)0) {
155             /*
156              * The fsprobe connection structure array exists.  Go through it
157              * and close up any Rx connections it holds.
158              */
159             curr_conn = fsprobe_ConnInfo;
160             for (conn_idx = 0; conn_idx < fsprobe_numServers; conn_idx++) {
161                 if (curr_conn->rxconn != (struct rx_connection *)0) {
162                     rx_DestroyConnection(curr_conn->rxconn);
163                     curr_conn->rxconn = (struct rx_connection *)0;
164                 }
165                 if (curr_conn->rxVolconn != (struct rx_connection *)0) {
166                     rx_DestroyConnection(curr_conn->rxVolconn);
167                     curr_conn->rxVolconn = (struct rx_connection *)0;
168                 }
169                 curr_conn++;
170             }                   /*for each fsprobe connection */
171         }                       /*fsprobe connection structure exists */
172     }                           /*Legal number of servers */
173
174     /*
175      * Now, release all the space we've allocated, if asked to.
176      */
177     if (a_releaseMem) {
178         if (fsprobe_ConnInfo != (struct fsprobe_ConnectionInfo *)0)
179             free(fsprobe_ConnInfo);
180         if (fsprobe_Results.stats != NULL)
181             free(fsprobe_Results.stats);
182         if (fsprobe_Results.probeOK != (int *)0)
183             free(fsprobe_Results.probeOK);
184     }
185
186     /*
187      * Return the news, whatever it is.
188      */
189     return (code);
190
191 }                               /*fsprobe_Cleanup */
192
193 /*------------------------------------------------------------------------
194  * [private] fsprobe_LWP
195  *
196  * Description:
197  *      This thread iterates over the server connections and gathers up
198  *      the desired statistics from each one on a regular basis.  When
199  *      the sweep is done, the associated handler function is called
200  *      to process the new data.
201  *
202  * Arguments:
203  *      None.
204  *
205  * Returns:
206  *      Nothing.
207  *
208  * Environment:
209  *      Started by fsprobe_Init(), uses global sturctures.
210  *
211  * Side Effects:
212  *      As advertised.
213  *------------------------------------------------------------------------*/
214 static void *
215 fsprobe_LWP(void *unused)
216 {                               /*fsprobe_LWP */
217
218     static char rn[] = "fsprobe_LWP";   /*Routine name */
219     afs_int32 code;     /*Results of calls */
220     struct timeval tv;          /*Time structure */
221     struct timespec wait;       /*Time to wait */
222     int conn_idx;               /*Connection index */
223     struct fsprobe_ConnectionInfo *curr_conn;   /*Current connection */
224     struct ProbeViceStatistics *curr_stats;     /*Current stats region */
225     int *curr_probeOK;          /*Current probeOK field */
226     ViceStatistics64 stats64;      /*Current stats region */
227     stats64.ViceStatistics64_val = malloc(STATS64_VERSION *
228                                           sizeof(afs_uint64));
229     while (1) {                 /*Service loop */
230         /*
231          * Iterate through the server connections, gathering data.
232          * Don't forget to bump the probe count and zero the statistics
233          * areas before calling the servers.
234          */
235         if (fsprobe_debug)
236             fprintf(stderr,
237                     "[%s] Waking up, collecting data from %d connected servers\n",
238                     rn, fsprobe_numServers);
239         curr_conn = fsprobe_ConnInfo;
240         curr_stats = fsprobe_Results.stats;
241         curr_probeOK = fsprobe_Results.probeOK;
242         fsprobe_Results.probeNum++;
243         memset(fsprobe_Results.stats, 0, fsprobe_statsBytes);
244         memset(fsprobe_Results.probeOK, 0, fsprobe_probeOKBytes);
245
246         for (conn_idx = 0; conn_idx < fsprobe_numServers; conn_idx++) {
247             /*
248              * Grab the statistics for the current FileServer, if the
249              * connection is valid.
250              */
251             if (fsprobe_debug)
252                 fprintf(stderr, "[%s] Contacting server %s\n", rn,
253                         curr_conn->hostName);
254             if (curr_conn->rxconn != (struct rx_connection *)0) {
255                 if (fsprobe_debug)
256                     fprintf(stderr,
257                             "[%s] Connection valid, calling RXAFS_GetStatistics\n",
258                             rn);
259                 *curr_probeOK =
260                     RXAFS_GetStatistics64(curr_conn->rxconn, STATS64_VERSION, &stats64);
261                 if (*curr_probeOK == RXGEN_OPCODE)
262                     *curr_probeOK =
263                         RXAFS_GetStatistics(curr_conn->rxconn, (ViceStatistics *)curr_stats);
264                 else if (*curr_probeOK == 0) {
265                     curr_stats->CurrentTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_CURRENTTIME]);
266                     curr_stats->BootTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_BOOTTIME]);
267                     curr_stats->StartTime = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_STARTTIME]);
268                     curr_stats->CurrentConnections = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_CURRENTCONNECTIONS]);
269                     curr_stats->TotalFetchs = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_TOTALFETCHES]);
270                     curr_stats->TotalStores = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_TOTALSTORES]);
271                     curr_stats->WorkStations = RoundInt64ToInt32(stats64.ViceStatistics64_val[STATS64_WORKSTATIONS]);
272                 }
273             }
274
275             /*Valid Rx connection */
276             /*
277              * Call the Volume Server too to get additional stats
278              */
279             if (fsprobe_debug)
280                 fprintf(stderr, "[%s] Contacting volume server %s\n", rn,
281                         curr_conn->hostName);
282             if (curr_conn->rxVolconn != (struct rx_connection *)0) {
283                 int i, code;
284                 char pname[10];
285                 struct diskPartition partition;
286                 struct diskPartition64 *partition64p =
287                     malloc(sizeof(struct diskPartition64));
288
289                 if (fsprobe_debug)
290                     fprintf(stderr,
291                             "[%s] Connection valid, calling RXAFS_GetStatistics\n",
292                             rn);
293                 for (i = 0; i < curr_conn->partCnt; i++) {
294                     if (curr_conn->partList.partFlags[i] & PARTVALID) {
295                         MapPartIdIntoName(curr_conn->partList.partId[i],
296                                           pname);
297                         code =
298                             AFSVolPartitionInfo64(curr_conn->rxVolconn, pname,
299                                                   partition64p);
300
301                         if (!code) {
302                             curr_stats->Disk[i].BlocksAvailable =
303                                 RoundInt64ToInt31(partition64p->free);
304                             curr_stats->Disk[i].TotalBlocks =
305                                 RoundInt64ToInt31(partition64p->minFree);
306                             strcpy(curr_stats->Disk[i].Name, pname);
307                         }
308                         if (code == RXGEN_OPCODE) {
309                             code =
310                                 AFSVolPartitionInfo(curr_conn->rxVolconn,
311                                                     pname, &partition);
312                             if (!code) {
313                                 curr_stats->Disk[i].BlocksAvailable =
314                                     partition.free;
315                                 curr_stats->Disk[i].TotalBlocks =
316                                     partition.minFree;
317                                 strcpy(curr_stats->Disk[i].Name, pname);
318                             }
319                         }
320                         if (code) {
321                             fprintf(stderr,
322                                     "Could not get information on server %s partition %s\n",
323                                     curr_conn->hostName, pname);
324                         }
325                     }
326                 }
327                 free(partition64p);
328             }
329
330
331             /*
332              * Advance the fsprobe connection pointer & stats pointer.
333              */
334             curr_conn++;
335             curr_stats++;
336             curr_probeOK++;
337
338         }                       /*For each fsprobe connection */
339
340         /*
341          * All (valid) connections have been probed.  Now, call the
342          * associated handler function.  The handler does not take
343          * any explicit parameters, rather gets to the goodies via
344          * some of the objects exported by this module.
345          */
346         if (fsprobe_debug)
347             fprintf(stderr,
348                     "[%s] Polling complete, calling associated handler routine.\n",
349                     rn);
350         code = fsprobe_Handler();
351         if (code)
352             fprintf(stderr, "[%s] Handler routine returned error code %d\n",
353                     rn, code);
354
355         /*
356          * Fall asleep for the prescribed number of seconds or wakeup
357          * sooner if forced.
358          */
359         gettimeofday(&tv, NULL);
360         wait.tv_sec = tv.tv_sec + fsprobe_ProbeFreqInSecs;
361         wait.tv_nsec = tv.tv_usec * 1000;
362         opr_mutex_enter(&fsprobe_force_lock);
363         code = opr_cv_timedwait(&fsprobe_force_cv, &fsprobe_force_lock, &wait);
364         opr_Assert(code == 0 || code == ETIMEDOUT);
365         opr_mutex_exit(&fsprobe_force_lock);
366     }                           /*Service loop */
367     AFS_UNREACHED(free(stats64.ViceStatistics64_val));
368     AFS_UNREACHED(return(NULL));
369 }                               /*fsprobe_LWP */
370
371 /*list all the partitions on <aserver> */
372 static int newvolserver = 0;
373
374 int
375 XListPartitions(struct rx_connection *aconn, struct partList *ptrPartList,
376                 afs_int32 *cntp)
377 {
378     struct pIDs partIds;
379     struct partEntries partEnts;
380     int i, j = 0, code;
381
382     *cntp = 0;
383     if (newvolserver == 1) {
384         for (i = 0; i < 26; i++)
385             partIds.partIds[i] = -1;
386       tryold:
387         code = AFSVolListPartitions(aconn, &partIds);
388         if (!code) {
389             for (i = 0; i < 26; i++) {
390                 if ((partIds.partIds[i]) != -1) {
391                     ptrPartList->partId[j] = partIds.partIds[i];
392                     ptrPartList->partFlags[j] = PARTVALID;
393                     j++;
394                 } else
395                     ptrPartList->partFlags[i] = 0;
396             }
397             *cntp = j;
398         }
399         goto out;
400     }
401     partEnts.partEntries_len = 0;
402     partEnts.partEntries_val = NULL;
403     code = AFSVolXListPartitions(aconn, &partEnts);
404     if (!newvolserver) {
405         if (code == RXGEN_OPCODE) {
406             newvolserver = 1;   /* Doesn't support new interface */
407             goto tryold;
408         } else if (!code) {
409             newvolserver = 2;
410         }
411     }
412     if (!code) {
413         *cntp = partEnts.partEntries_len;
414         if (*cntp > VOLMAXPARTS) {
415             fprintf(stderr,
416                     "Warning: number of partitions on the server too high %d (process only %d)\n",
417                     *cntp, VOLMAXPARTS);
418             *cntp = VOLMAXPARTS;
419         }
420         for (i = 0; i < *cntp; i++) {
421             ptrPartList->partId[i] = partEnts.partEntries_val[i];
422             ptrPartList->partFlags[i] = PARTVALID;
423         }
424         free(partEnts.partEntries_val);
425     }
426   out:
427     if (code)
428         fprintf(stderr,
429                 "Could not fetch the list of partitions from the server\n");
430     return code;
431 }
432
433
434 /*------------------------------------------------------------------------
435  * [exported] fsprobe_Init
436  *
437  * Description:
438  *      Initialize the fsprobe module: set up Rx connections to the
439  *      given set of servers, start up the probe and callback threads,
440  *      and associate the routine to be called when a probe completes.
441  *
442  * Arguments:
443  *      int a_numServers                  : Num. servers to connect to.
444  *      struct sockaddr_in *a_socketArray : Array of server sockets.
445  *      int a_ProbeFreqInSecs             : Probe frequency in seconds.
446  *      int (*a_ProbeHandler)()           : Ptr to probe handler fcn.
447  *      int a_debug;                      : Turn debugging output on?
448  *
449  * Returns:
450  *      0 on success,
451  *      -2 for (at least one) connection error,
452  *      thread process creation code, if it failed,
453  *      -1 for other fatal errors.
454  *
455  * Environment:
456  *      *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
457  *      Also, the server security object CBsecobj MUST be a static,
458  *      since it has to stick around after this routine exits.
459  *
460  * Side Effects:
461  *      Sets up just about everything.
462  *------------------------------------------------------------------------*/
463
464 int
465 fsprobe_Init(int a_numServers, struct sockaddr_in *a_socketArray,
466              int a_ProbeFreqInSecs, int (*a_ProbeHandler)(void),
467              int a_debug)
468 {                               /*fsprobe_Init */
469
470     static char rn[] = "fsprobe_Init";  /*Routine name */
471     afs_int32 code;     /*Return value */
472     static struct rx_securityClass *CBsecobj;   /*Callback security object */
473     struct rx_securityClass *secobj;    /*Client security object */
474     struct rx_service *rxsrv_afsserver; /*Server for AFS */
475     int arg_errfound;           /*Argument error found? */
476     int curr_srv;               /*Current server idx */
477     struct fsprobe_ConnectionInfo *curr_conn;   /*Ptr to current conn */
478     char *hostNameFound;        /*Ptr to returned host name */
479     int conn_err;               /*Connection error? */
480
481     /*
482      * If we've already been called, snicker at the bozo, gently
483      * remind him of his doubtful heritage, and return success.
484      */
485     if (fsprobe_initflag) {
486         fprintf(stderr, "[%s] Called multiple times!\n", rn);
487         return (0);
488     } else
489         fsprobe_initflag = 1;
490
491     opr_mutex_init(&fsprobe_force_lock);
492     opr_cv_init(&fsprobe_force_cv);
493
494     /*
495      * Check the parameters for bogosities.
496      */
497     arg_errfound = 0;
498     if (a_numServers <= 0) {
499         fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
500                 a_numServers);
501         arg_errfound = 1;
502     }
503     if (a_socketArray == (struct sockaddr_in *)0) {
504         fprintf(stderr, "[%s] Null server socket array argument\n", rn);
505         arg_errfound = 1;
506     }
507     if (a_ProbeFreqInSecs <= 0) {
508         fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
509                 a_ProbeFreqInSecs);
510         arg_errfound = 1;
511     }
512     if (a_ProbeHandler == NULL) {
513         fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
514         arg_errfound = 1;
515     }
516     if (arg_errfound)
517         return (-1);
518
519     /*
520      * Record our passed-in info.
521      */
522     fsprobe_debug = a_debug;
523     fsprobe_numServers = a_numServers;
524     fsprobe_Handler = a_ProbeHandler;
525     fsprobe_ProbeFreqInSecs = a_ProbeFreqInSecs;
526
527     /*
528      * Get ready in case we have to do a cleanup - basically, zero
529      * everything out.
530      */
531     fsprobe_CleanupInit();
532
533     /*
534      * Allocate the necessary data structures and initialize everything
535      * else.
536      */
537     fsprobe_ConnInfo = (struct fsprobe_ConnectionInfo *)
538         malloc(a_numServers * sizeof(struct fsprobe_ConnectionInfo));
539     if (fsprobe_ConnInfo == (struct fsprobe_ConnectionInfo *)0) {
540         fprintf(stderr,
541                 "[%s] Can't allocate %d connection info structs (%"AFS_SIZET_FMT" bytes)\n",
542                 rn, a_numServers,
543                 (a_numServers * sizeof(struct fsprobe_ConnectionInfo)));
544         return (-1);            /*No cleanup needs to be done yet */
545     }
546
547     fsprobe_statsBytes = a_numServers * sizeof(struct ProbeViceStatistics);
548     fsprobe_Results.stats = (struct ProbeViceStatistics *)
549         malloc(fsprobe_statsBytes);
550     if (fsprobe_Results.stats == NULL) {
551         fprintf(stderr,
552                 "[%s] Can't allocate %d statistics structs (%d bytes)\n", rn,
553                 a_numServers, fsprobe_statsBytes);
554         fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
555         return (-1);
556     } else if (fsprobe_debug)
557         fprintf(stderr, "[%s] fsprobe_Results.stats allocated (%d bytes)\n",
558                 rn, fsprobe_statsBytes);
559
560     fsprobe_probeOKBytes = a_numServers * sizeof(int);
561     fsprobe_Results.probeOK = malloc(fsprobe_probeOKBytes);
562     if (fsprobe_Results.probeOK == (int *)0) {
563         fprintf(stderr,
564                 "[%s] Can't allocate %d probeOK array entries (%d bytes)\n",
565                 rn, a_numServers, fsprobe_probeOKBytes);
566         fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
567         return (-1);
568     } else if (fsprobe_debug)
569         fprintf(stderr, "[%s] fsprobe_Results.probeOK allocated (%d bytes)\n",
570                 rn, fsprobe_probeOKBytes);
571
572     fsprobe_Results.probeNum = 0;
573     fsprobe_Results.probeTime = 0;
574     memset(fsprobe_Results.stats, 0,
575            (a_numServers * sizeof(struct ProbeViceStatistics)));
576
577     /*
578      * Initialize the Rx subsystem, just in case nobody's done it.
579      */
580     if (fsprobe_debug)
581         fprintf(stderr, "[%s] Initializing Rx\n", rn);
582     code = rx_Init(0);
583     if (code) {
584         fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
585         return (-1);
586     }
587     if (fsprobe_debug)
588         fprintf(stderr, "[%s] Rx initialized.\n", rn);
589
590     /*
591      * Create a null Rx server security object, to be used by the
592      * Callback listener.
593      */
594     CBsecobj = rxnull_NewServerSecurityObject();
595     if (CBsecobj == (struct rx_securityClass *)0) {
596         fprintf(stderr,
597                 "[%s] Can't create null security object for the callback listener.\n",
598                 rn);
599         fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
600         return (-1);
601     }
602     if (fsprobe_debug)
603         fprintf(stderr, "[%s] Callback server security object created\n", rn);
604
605     /*
606      * Create a null Rx client security object, to be used by the
607      * probe thread.
608      */
609     secobj = rxnull_NewClientSecurityObject();
610     if (secobj == (struct rx_securityClass *)0) {
611         fprintf(stderr,
612                 "[%s] Can't create client security object for probe thread.\n",
613                 rn);
614         fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
615         return (-1);
616     }
617     if (fsprobe_debug)
618         fprintf(stderr, "[%s] Probe thread client security object created\n",
619                 rn);
620
621     curr_conn = fsprobe_ConnInfo;
622     conn_err = 0;
623     for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
624         /*
625          * Copy in the socket info for the current server, resolve its
626          * printable name if possible.
627          */
628         if (fsprobe_debug) {
629             fprintf(stderr, "[%s] Copying in the following socket info:\n",
630                     rn);
631             fprintf(stderr, "[%s] IP addr 0x%x, port %d\n", rn,
632                     (a_socketArray + curr_srv)->sin_addr.s_addr,
633                     (a_socketArray + curr_srv)->sin_port);
634         }
635         memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
636                sizeof(struct sockaddr_in));
637
638         hostNameFound =
639             hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
640         if (hostNameFound == NULL) {
641             fprintf(stderr,
642                     "[%s] Can't map Internet address %u to a string name\n",
643                     rn, curr_conn->skt.sin_addr.s_addr);
644             curr_conn->hostName[0] = '\0';
645         } else {
646             strcpy(curr_conn->hostName, hostNameFound);
647             if (fsprobe_debug)
648                 fprintf(stderr, "[%s] Host name for server index %d is %s\n",
649                         rn, curr_srv, curr_conn->hostName);
650         }
651
652         /*
653          * Make an Rx connection to the current server.
654          */
655         if (fsprobe_debug)
656             fprintf(stderr,
657                     "[%s] Connecting to srv idx %d, IP addr 0x%x, port %d, service 1\n",
658                     rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
659                     curr_conn->skt.sin_port);
660         curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr,    /*Server addr */
661                                              curr_conn->skt.sin_port,   /*Server port */
662                                              1, /*AFS service num */
663                                              secobj,    /*Security object */
664                                              0);        /*Number of above */
665         if (curr_conn->rxconn == (struct rx_connection *)0) {
666             fprintf(stderr,
667                     "[%s] Can't create Rx connection to server %s (%u)\n",
668                     rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
669             conn_err = 1;
670         }
671         if (fsprobe_debug)
672             fprintf(stderr, "[%s] New connection at %p\n", rn,
673                     curr_conn->rxconn);
674
675         /*
676          * Make an Rx connection to the current volume server.
677          */
678         if (fsprobe_debug)
679             fprintf(stderr,
680                     "[%s] Connecting to srv idx %d, IP addr 0x%x, port %d, service 1\n",
681                     rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
682                     htons(7005));
683         curr_conn->rxVolconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
684                                                 htons(AFSCONF_VOLUMEPORT),      /*Volume Server port */
685                                                 VOLSERVICE_ID,  /*AFS service num */
686                                                 secobj, /*Security object */
687                                                 0);     /*Number of above */
688         if (curr_conn->rxVolconn == (struct rx_connection *)0) {
689             fprintf(stderr,
690                     "[%s] Can't create Rx connection to volume server %s (%u)\n",
691                     rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
692             conn_err = 1;
693         } else {
694             int i, cnt;
695
696             memset(&curr_conn->partList, 0, sizeof(struct partList));
697             curr_conn->partCnt = 0;
698             i = XListPartitions(curr_conn->rxVolconn, &curr_conn->partList,
699                                 &cnt);
700             if (!i) {
701                 curr_conn->partCnt = cnt;
702             }
703         }
704         if (fsprobe_debug)
705             fprintf(stderr, "[%s] New connection at %p\n", rn,
706                     curr_conn->rxVolconn);
707
708
709         /*
710          * Bump the current fsprobe connection to set up.
711          */
712         curr_conn++;
713
714     }                           /*for curr_srv */
715
716     /*
717      * Create the AFS callback service (listener).
718      */
719     if (fsprobe_debug)
720         fprintf(stderr, "[%s] Creating AFS callback listener\n", rn);
721     rxsrv_afsserver = rx_NewService(0,  /*Use default port */
722                                     1,  /*Service ID */
723                                     "afs",      /*Service name */
724                                     &CBsecobj,  /*Ptr to security object(s) */
725                                     1,  /*Number of security objects */
726                                     RXAFSCB_ExecuteRequest);    /*Dispatcher */
727     if (rxsrv_afsserver == (struct rx_service *)0) {
728         fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
729                 rn);
730         fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
731         return (-1);
732     }
733     if (fsprobe_debug)
734         fprintf(stderr, "[%s] Callback listener created\n", rn);
735
736     /*
737      * Start up the AFS callback service.
738      */
739     if (fsprobe_debug)
740         fprintf(stderr, "[%s] Starting up callback listener.\n", rn);
741     rx_StartServer(0 /*Don't donate yourself to thread pool */ );
742
743     /*
744      * Start up the probe thread.
745      */
746     if (fsprobe_debug)
747         fprintf(stderr, "[%s] Creating the probe thread\n", rn);
748     code = pthread_create(&fsprobe_thread, NULL, fsprobe_LWP, NULL);
749     if (code) {
750         fprintf(stderr, "[%s] Can't create fsprobe thread!  Error is %d\n", rn,
751                 code);
752         fsprobe_Cleanup(1);     /*Delete already-malloc'ed areas */
753         return (code);
754     }
755
756     /*
757      * Return the final results.
758      */
759     if (conn_err)
760         return (-2);
761     else
762         return (0);
763
764 }                               /*fsprobe_Init */
765
766
767 /*------------------------------------------------------------------------
768  * [exported] fsprobe_ForceProbeNow
769  *
770  * Description:
771  *      Wake up the probe thread, forcing it to execute a probe immediately.
772  *
773  * Arguments:
774  *      None.
775  *
776  * Returns:
777  *      0 on success,
778  *      Error value otherwise.
779  *
780  * Environment:
781  *      The module must have been initialized.
782  *
783  * Side Effects:
784  *      As advertised.
785  *------------------------------------------------------------------------*/
786
787 int
788 fsprobe_ForceProbeNow(void)
789 {                               /*fsprobe_ForceProbeNow */
790
791     static char rn[] = "fsprobe_ForceProbeNow"; /*Routine name */
792
793     /*
794      * There isn't a prayer unless we've been initialized.
795      */
796     if (!fsprobe_initflag) {
797         fprintf(stderr, "[%s] Must call fsprobe_Init first!\n", rn);
798         return (-1);
799     }
800
801     /*
802      * Kick the sucker in the side.
803      */
804     opr_mutex_enter(&fsprobe_force_lock);
805     opr_cv_signal(&fsprobe_force_cv);
806     opr_mutex_exit(&fsprobe_force_lock);
807
808     /*
809      * We did it, so report the happy news.
810      */
811     return (0);
812
813 }                               /*fsprobe_ForceProbeNow */
814
815 /*------------------------------------------------------------------------
816  * [exported] fsprobe_Wait
817  *
818  * Description:
819  *      Wait for the collection to complete.
820  *
821  * Arguments:
822  *    int sleep_secs : time to wait in seconds. 0 means sleep forever.
823  *
824  * Returns:
825  *      0 on success,
826  *      Error value otherwise.
827  *
828  * Environment:
829  *      The module must have been initialized.
830  *
831  * Side Effects:
832  *      As advertised.
833  *------------------------------------------------------------------------*/
834 int
835 fsprobe_Wait(int sleep_secs)
836 {
837     int code;
838     struct timeval tv;
839
840     if (sleep_secs == 0) {
841         while (1) {
842             tv.tv_sec = 30;
843             tv.tv_usec = 0;
844             code = select(0, 0, 0, 0, &tv);
845             if (code < 0)
846                 break;
847         }
848     } else {
849         tv.tv_sec = sleep_secs;
850         tv.tv_usec = 0;
851         code = select(0, 0, 0, 0, &tv);
852     }
853     return code;
854 }