convert-from-bsd-to-posix-string-and-memory-functions-20010807
[openafs.git] / src / xstat / xstat_fs.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 client side of the AFS File Server extended
13  *      statistics facility.
14  *
15  *------------------------------------------------------------------------*/
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 RCSID("$Header$");
21
22 #include "xstat_fs.h"                   /*Interface for this module*/
23 #include <lwp.h>                        /*Lightweight process package*/
24
25 #define LWP_STACK_SIZE  (16 * 1024)
26
27 /*
28  * Routines we need that don't have explicit include file definitions.
29  */
30 extern int RXAFSCB_ExecuteRequest();    /*AFS callback dispatcher*/
31 extern char *hostutil_GetNameByINet();  /*Host parsing utility*/
32
33 /*
34  * Help out the linker by explicitly importing the callback routines
35  * File Servers may be lobbing at us.
36  */
37 extern afs_int32 SRXAFSCB_CallBack();
38 extern afs_int32 SRXAFSCB_InitCallBackState3();
39 extern afs_int32 SRXAFSCB_Probe();
40 extern afs_int32 SRXAFSCB_GetCE();
41 extern afs_int32 SRXAFSCB_GetLock();
42
43 /*
44  * Exported variables.
45  */
46 int xstat_fs_numServers;                        /*Num connected servers*/
47 struct xstat_fs_ConnectionInfo
48     *xstat_fs_ConnInfo;                         /*Ptr to connection array*/
49 int numCollections;                             /*Number of data collections*/
50 struct xstat_fs_ProbeResults xstat_fs_Results;  /*Latest probe results*/
51 char terminationEvent;                          /*One-shot termination event*/
52
53 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS];            /*Buffer for collected data*/
54
55 /*
56  * Private globals.
57  */
58 static int xstat_fs_ProbeFreqInSecs;            /*Probe freq. in seconds*/
59 static int xstat_fs_initflag = 0;               /*Was init routine called?*/
60 static int xstat_fs_debug = 0;                  /*Debugging output enabled?*/
61 static int xstat_fs_oneShot = 0;                /*One-shot operation?*/
62 static int (*xstat_fs_Handler)();               /*Probe handler routine*/
63 static PROCESS probeLWP_ID;                     /*Probe LWP process ID*/
64 static int xstat_fs_numCollections;             /*Number of desired collections*/
65 static afs_int32 *xstat_fs_collIDP;                     /*Ptr to collection IDs desired*/
66
67 /*
68  * We have to pass a port to Rx to start up our callback listener
69  * service, but 7001 is already taken up by the Cache Manager.  So,
70  * we make up our own.
71  */
72 #define XSTAT_FS_CBPORT 7101
73
74
75 /*------------------------------------------------------------------------
76  * [private] xstat_fs_CleanupInit
77  *
78  * Description:
79  *      Set up for recovery after an error in initialization (i.e.,
80  *      during a call to xstat_fs_Init.
81  *
82  * Arguments:
83  *      None.
84  *
85  * Returns:
86  *      0 on success,
87  *      Error value otherwise.
88  *
89  * Environment:
90  *      This routine is private to the module.
91  *
92  * Side Effects:
93  *      Zeros out basic data structures.
94  *------------------------------------------------------------------------*/
95
96 static int xstat_fs_CleanupInit()
97
98 { /*xstat_fs_CleanupInit*/
99
100     afs_int32 code;                     /*Return code from callback stubs*/
101     struct rx_call *rxcall;     /*Bogus param*/
102     AFSCBFids *Fids_Array;      /*Bogus param*/
103     AFSCBs *CallBack_Array;     /*Bogus param*/
104
105     xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
106     xstat_fs_Results.probeNum = 0;
107     xstat_fs_Results.probeTime = 0;
108     xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
109     xstat_fs_Results.collectionNumber = 0;
110     xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
111     xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *)xstat_fsData;
112     xstat_fs_Results.probeOK = 0;
113
114     rxcall         = (struct rx_call *)0;
115     Fids_Array     = (AFSCBFids *)0;
116     CallBack_Array = (AFSCBs *)0;
117
118     /*
119      * Call each of the callback routines our module provides (in
120      * xstat_fs_callback.c) to make sure they're all there.
121      */
122     code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
123     if (code)
124         return(code);
125     code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
126     if (code)
127         return(code);
128     code = SRXAFSCB_Probe(rxcall);
129     return(code);
130
131 } /*xstat_fs_CleanupInit*/
132
133
134 /*------------------------------------------------------------------------
135  * [exported] xstat_fs_Cleanup
136  *
137  * Description:
138  *      Clean up our memory and connection state.
139  *
140  * Arguments:
141  *      int a_releaseMem : Should we free up malloc'ed areas?
142  *
143  * Returns:
144  *      0 on total success,
145  *      -1 if the module was never initialized, or there was a problem
146  *              with the xstat_fs connection array.
147  *
148  * Environment:
149  *      xstat_fs_numServers should be properly set.  We don't do anything
150  *      unless xstat_fs_Init() has already been called.
151  *
152  * Side Effects:
153  *      Shuts down Rx connections gracefully, frees allocated space
154  *      (if so directed).
155  *------------------------------------------------------------------------*/
156
157 int xstat_fs_Cleanup(a_releaseMem)
158     int a_releaseMem;
159
160 { /*xstat_fs_Cleanup*/
161
162     static char rn[] = "xstat_fs_Cleanup";      /*Routine name*/
163     int code;                                   /*Return code*/
164     int conn_idx;                               /*Current connection index*/
165     struct xstat_fs_ConnectionInfo *curr_conn;  /*Ptr to xstat_fs connection*/
166
167     /*
168      * Assume the best, but check the worst.
169      */
170     if (!xstat_fs_initflag) {
171         fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
172         return(-1);
173     }
174     else
175         code = 0;
176
177     /*
178      * Take care of all Rx connections first.  Check to see that the
179      * server count is a legal value.
180      */
181     if (xstat_fs_numServers <= 0) {
182         fprintf(stderr,
183                 "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
184                 rn, xstat_fs_numServers);
185         code = -1;
186     }
187     else {
188         if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
189             /*
190              * The xstat_fs connection structure array exists.  Go through
191              * it and close up any Rx connections it holds.
192              */
193             curr_conn = xstat_fs_ConnInfo;
194             for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
195                 if (curr_conn->rxconn != (struct rx_connection *)0) {
196                     rx_DestroyConnection(curr_conn->rxconn);
197                     curr_conn->rxconn = (struct rx_connection *)0;
198                 }
199                 curr_conn++;
200             } /*for each xstat_fs connection*/
201         } /*xstat_fs connection structure exists*/
202     } /*Legal number of servers*/
203
204     /*
205      * If asked to, release the space we've allocated.
206      */
207     if (a_releaseMem) {
208         if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0)
209             free(xstat_fs_ConnInfo);
210     }
211
212     /*
213      * Return the news, whatever it is.
214      */
215     return(code);
216
217 } /*xstat_fs_Cleanup*/
218
219
220 /*------------------------------------------------------------------------
221  * [private] xstat_fs_LWP
222  *
223  * Description:
224  *      This LWP iterates over the server connections and gathers up
225  *      the desired statistics from each one on a regular basis.  When
226  *      the sweep is done, the associated handler function is called
227  *      to process the new data.
228  *
229  * Arguments:
230  *      None.
231  *
232  * Returns:
233  *      Nothing.
234  *
235  * Environment:
236  *      Started by xstat_fs_Init(), uses global structures and the
237  *      global private xstat_fs_oneShot variable.
238  *
239  * Side Effects:
240  *      Nothing interesting.
241  *------------------------------------------------------------------------*/
242
243 static void xstat_fs_LWP()
244
245 { /*xstat_fs_LWP*/
246
247     static char rn[] = "xstat_fs_LWP";          /*Routine name*/
248     register afs_int32 code;                            /*Results of calls*/
249     int oneShotCode;                            /*Result of one-shot signal*/
250     struct timeval tv;                          /*Time structure*/
251     int conn_idx;                               /*Connection index*/
252     struct xstat_fs_ConnectionInfo *curr_conn;  /*Current connection*/
253     afs_int32 srvVersionNumber;                 /*Xstat version #*/
254     afs_int32 clientVersionNumber;                      /*Client xstat version*/
255     afs_int32 numColls;                         /*Number of collections to get*/
256     afs_int32 *currCollIDP;                             /*Curr collection ID desired*/
257
258     static afs_int32 xstat_VersionNumber;               /*Version # of server*/
259
260     /*
261      * Set up some numbers we'll need.
262      */
263     clientVersionNumber = AFS_XSTAT_VERSION;
264
265     while (1) { /*Service loop*/
266         /*
267          * Iterate through the server connections, gathering data.
268          * Don't forget to bump the probe count and zero the statistics
269          * areas before calling the servers.
270          */
271         if (xstat_fs_debug)
272             printf("[%s] Waking up, getting data from %d server(s)\n",
273                    rn, xstat_fs_numServers);
274         curr_conn = xstat_fs_ConnInfo;
275         xstat_fs_Results.probeNum++;
276
277         for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
278             /*
279              * Grab the statistics for the current File Server, if the
280              * connection is valid.
281              */
282             if (xstat_fs_debug)
283                 printf("[%s] Getting collections from File Server '%s'\n",
284                        rn, curr_conn->hostName);
285             if (curr_conn->rxconn != (struct rx_connection *)0) {
286                 if (xstat_fs_debug)
287                     printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
288                            rn);
289
290                 currCollIDP = xstat_fs_collIDP;
291                 for (numColls = 0;
292                      numColls < xstat_fs_numCollections;
293                      numColls++, currCollIDP++) {
294                     /*
295                      * Initialize the per-probe values.
296                      */
297                     if (xstat_fs_debug)
298                         printf("[%s] Asking for data collection %d\n",
299                                rn, *currCollIDP);
300                     xstat_fs_Results.collectionNumber = *currCollIDP;
301                     xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
302                     memset(xstat_fs_Results.data.AFS_CollData_val, 0, AFS_MAX_XSTAT_LONGS * 4);
303                     
304                     xstat_fs_Results.connP = curr_conn;
305                     
306                     if (xstat_fs_debug) {
307                         printf("%s: Calling RXAFS_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
308                                rn, curr_conn->rxconn,
309                                clientVersionNumber,
310                                *currCollIDP,
311                                &srvVersionNumber,
312                                &(xstat_fs_Results.probeTime),
313                                &(xstat_fs_Results.data));
314                         printf("%s: [bufflen=%d, buffer at 0x%x]\n",
315                                rn,
316                                xstat_fs_Results.data.AFS_CollData_len,
317                                xstat_fs_Results.data.AFS_CollData_val);
318                     }
319
320                     xstat_fs_Results.probeOK =
321                         RXAFS_GetXStats(curr_conn->rxconn,
322                                         clientVersionNumber,
323                                         *currCollIDP,
324                                         &srvVersionNumber,
325                                         &(xstat_fs_Results.probeTime),
326                                         &(xstat_fs_Results.data));
327                     
328                     /*
329                      * Now that we (may) have the data for this connection,
330                      * call the associated handler function.  The handler does
331                      * not take any explicit parameters, but rather gets to the
332                      * goodies via some of the objects exported by this module.
333                      */
334                     if (xstat_fs_debug)
335                         printf("[%s] Calling handler routine.\n", rn);
336                     code = xstat_fs_Handler();
337                     if (code)
338                         fprintf(stderr,
339                                 "[%s] Handler returned error code %d\n",
340                                 rn, code);
341                     
342                 } /*For each collection*/
343             } /*Valid Rx connection*/
344             
345             /*
346              * Advance the xstat_fs connection pointer.
347              */
348             curr_conn++;
349
350         } /*For each xstat_fs connection*/
351
352         /*
353          * All (valid) connections have been probed.  Fall asleep for the
354          * prescribed number of seconds, unless we're a one-shot.  In
355          * that case, we need to signal our caller that we're done.
356          */
357         if (xstat_fs_debug)
358             printf("[%s] Polling complete for probe round %d.\n",
359                    rn, xstat_fs_Results.probeNum);
360
361         if (xstat_fs_oneShot) {
362             /*
363              * One-shot execution desired.  Signal our main procedure
364              * that we've finished our collection round.
365              */
366             if (xstat_fs_debug)
367                 printf("[%s] Signalling main process at 0x%x\n",
368                        rn, &terminationEvent);
369             oneShotCode = LWP_SignalProcess(&terminationEvent);
370             if (oneShotCode)
371                 fprintf(stderr,
372                         "[%s] Error %d from LWP_SignalProcess()",
373                         rn, oneShotCode);
374             break; /*from the perpetual while loop*/
375         } /*One-shot execution*/
376         else {
377             /*
378              * Continuous execution desired.  Sleep for the required
379              * number of seconds.
380              */
381             tv.tv_sec  = xstat_fs_ProbeFreqInSecs;
382             tv.tv_usec = 0;
383             if (xstat_fs_debug)
384                 printf("[%s] Falling asleep for %d seconds\n",
385                        rn, xstat_fs_ProbeFreqInSecs);
386             code = IOMGR_Select(0,      /*Num fids*/
387                                 0,      /*Descs ready for reading*/
388                                 0,      /*Descs ready for writing*/
389                                 0,      /*Descs w/exceptional conditions*/
390                                 &tv);   /*Ptr to timeout structure*/
391             if (code)
392                 fprintf(stderr,
393                         "[%s] IOMGR_Select returned code %d\n",
394                         rn, code);
395         } /*Continuous execution*/
396     } /*Service loop*/
397
398 } /*xstat_fs_LWP*/
399
400
401 /*------------------------------------------------------------------------
402  * [exported] xstat_fs_Init
403  *
404  * Description:
405  *      Initialize the xstat_fs module: set up Rx connections to the
406  *      given set of File Servers, start up the probe and callback LWPs,
407  *      and associate the routine to be called when a probe completes.
408  *      Also, let it know which collections you're interested in.
409  *
410  * Arguments:
411  *      int a_numServers                  : Num. servers to connect to.
412  *      struct sockaddr_in *a_socketArray : Array of server sockets.
413  *      int a_ProbeFreqInSecs             : Probe frequency in seconds.
414  *      int (*a_ProbeHandler)()           : Ptr to probe handler fcn.
415  *      int a_flags                       : Various flags.
416  *      int a_numCollections              : Number of collections desired.
417  *      afs_int32 *a_collIDP                      : Ptr to collection IDs.
418  *
419  * Returns:
420  *      0 on success,
421  *      -2 for (at least one) connection error,
422  *      LWP process creation code, if it failed,
423  *      -1 for other fatal errors.
424  *
425  * Environment:
426  *      *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
427  *      Also, the server security object CBsecobj MUST be a static,
428  *      since it has to stick around after this routine exits.
429  *
430  * Side Effects:
431  *      Sets up just about everything.
432  *------------------------------------------------------------------------*/
433
434 int xstat_fs_Init(a_numServers, a_socketArray, a_ProbeFreqInSecs, a_ProbeHandler,
435                   a_flags, a_numCollections, a_collIDP)
436     int a_numServers;
437     struct sockaddr_in *a_socketArray;
438     int a_ProbeFreqInSecs;
439     int (*a_ProbeHandler)();
440     int a_flags;
441     int a_numCollections;
442     afs_int32 *a_collIDP;
443
444 { /*xstat_fs_Init*/
445
446     static char rn[] = "xstat_fs_Init";         /*Routine name*/
447     register afs_int32 code;                            /*Return value*/
448     static struct rx_securityClass *CBsecobj;   /*Callback security object*/
449     struct rx_securityClass *secobj;            /*Client security object*/
450     struct rx_service *rxsrv_afsserver;         /*Server for AFS*/
451     int arg_errfound;                           /*Argument error found?*/
452     int curr_srv;                               /*Current server idx*/
453     struct xstat_fs_ConnectionInfo *curr_conn;  /*Ptr to current conn*/
454     char *hostNameFound;                        /*Ptr to returned host name*/
455     int conn_err;                               /*Connection error?*/
456     int PortToUse;                              /*Callback port to use*/
457     int collIDBytes;                            /*Num bytes in coll ID array*/
458
459     /*
460      * If we've already been called, snicker at the bozo, gently
461      * remind him of his doubtful heritage, and return success.
462      */
463     if (xstat_fs_initflag) {
464         fprintf(stderr, "[%s] Called multiple times!\n", rn);
465         return(0);
466     }
467     else
468         xstat_fs_initflag = 1; 
469
470     /*
471      * Check the parameters for bogosities.
472      */
473     arg_errfound = 0;
474     if (a_numServers <= 0) {
475         fprintf(stderr, "[%s] Illegal number of servers: %d\n",
476                 rn, a_numServers);
477         arg_errfound = 1;
478     }
479     if (a_socketArray == (struct sockaddr_in *)0) {
480         fprintf(stderr, "[%s] Null server socket array argument\n", rn);
481         arg_errfound = 1;
482     }
483     if (a_ProbeFreqInSecs <= 0) {
484         fprintf(stderr, "[%s] Illegal probe frequency: %d\n",
485                 rn, a_ProbeFreqInSecs);
486         arg_errfound = 1;
487     }
488     if (a_ProbeHandler == (int (*)())0) {
489         fprintf(stderr, "[%s] Null probe handler function argument\n",
490                 rn);
491         arg_errfound = 1;
492     }
493     if (a_numCollections <= 0) {
494         fprintf(stderr, "[%s] Illegal collection count argument: %d\n",
495                 rn, a_numServers);
496         arg_errfound = 1;
497     }
498     if (a_collIDP == (afs_int32 *)0) {
499         fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
500         arg_errfound = 1;
501     }
502     if (arg_errfound)
503         return(-1);
504
505     /*
506      * Record our passed-in info.
507      */
508     xstat_fs_debug           = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
509     xstat_fs_oneShot         = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
510     xstat_fs_numServers      = a_numServers;
511     xstat_fs_Handler         = a_ProbeHandler;
512     xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
513     xstat_fs_numCollections  = a_numCollections;
514     collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
515     xstat_fs_collIDP         = (afs_int32 *)(malloc(collIDBytes));
516     memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
517     if (xstat_fs_debug) {
518         printf("[%s] Asking for %d collection(s): ", rn, xstat_fs_numCollections);
519         for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
520             printf("%d ", *(xstat_fs_collIDP+curr_srv));
521         printf("\n");
522     }
523
524     /*
525      * Get ready in case we have to do a cleanup - basically, zero
526      * everything out.
527      */
528     code = xstat_fs_CleanupInit();
529     if (code)
530         return(code);
531
532     /*
533      * Allocate the necessary data structures and initialize everything
534      * else.
535      */
536     xstat_fs_ConnInfo =
537         (struct xstat_fs_ConnectionInfo *)
538             malloc(a_numServers * sizeof(struct xstat_fs_ConnectionInfo));
539     if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
540         fprintf(stderr,
541                 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
542                 rn, a_numServers,
543                 (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
544         return(-1);     /*No cleanup needs to be done yet*/
545     }
546
547     /*
548      * Initialize the Rx subsystem, just in case nobody's done it.
549      */
550     if (xstat_fs_debug)
551         printf("[%s] Initializing Rx\n", rn);
552     PortToUse = XSTAT_FS_CBPORT;
553
554     do {
555         code = rx_Init(htons(PortToUse));
556         if (code) {
557             if (code == RX_ADDRINUSE) {
558                 if (xstat_fs_debug)
559                     fprintf(stderr,
560                             "[%s] Callback port %d in use, advancing\n",
561                             rn, PortToUse);
562                 PortToUse++;
563             }
564             else {
565                 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
566                 return(-1);
567             }
568         }
569     } while (code);
570     if (xstat_fs_debug)
571         printf("[%s] Rx initialized on port %d\n", rn, PortToUse);
572
573     /*
574      * Create a null Rx server security object, to be used by the
575      * Callback listener.
576      */
577     CBsecobj = (struct rx_securityClass *)
578         rxnull_NewServerSecurityObject();
579     if (CBsecobj == (struct rx_securityClass *)0) {
580         fprintf(stderr,
581                 "[%s] Can't create callback listener's security object.\n",
582                 rn);
583         xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
584         return(-1);
585     }
586     if (xstat_fs_debug)
587         printf("[%s] Callback server security object created\n", rn);
588     
589     /*
590      * Create a null Rx client security object, to be used by the
591      * probe LWP.
592      */
593     secobj = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
594     if (secobj == (struct rx_securityClass *)0) {
595         fprintf(stderr,
596                 "[%s] Can't create probe LWP client security object.\n",
597                 rn);
598         xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
599         return(-1);
600     }
601     if (xstat_fs_debug)
602         printf("[%s] Probe LWP client security object created\n", rn);
603
604     curr_conn = xstat_fs_ConnInfo;
605     conn_err = 0;
606     for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
607         /*
608          * Copy in the socket info for the current server, resolve its
609          * printable name if possible.
610          */
611         if (xstat_fs_debug) {
612             printf("[%s] Copying in the following socket info:\n",
613                    rn);
614             printf("[%s] IP addr 0x%lx, port %d\n", rn,
615                    (a_socketArray + curr_srv)->sin_addr.s_addr,
616                    (a_socketArray + curr_srv)->sin_port);
617         }
618         memcpy(&(curr_conn->skt), a_socketArray + curr_srv, sizeof(struct sockaddr_in));
619         
620         hostNameFound =
621             hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
622         if (hostNameFound == (char *)0) {
623             fprintf(stderr,
624                     "[%s] Can't map Internet address %lu to a string name\n",
625                     rn, curr_conn->skt.sin_addr.s_addr);
626             curr_conn->hostName[0] = '\0';
627         }
628         else {
629             strcpy(curr_conn->hostName, hostNameFound);
630             if (xstat_fs_debug)
631                 printf("[%s] Host name for server index %d is %s\n",
632                        rn, curr_srv, curr_conn->hostName);
633         }
634         
635         /*
636          * Make an Rx connection to the current server.
637          */
638         if (xstat_fs_debug)
639             printf("[%s] Connecting to srv idx %d, IP addr 0x%lx, port %d, service 1\n",
640                    rn, curr_srv, curr_conn->skt.sin_addr.s_addr,
641                    curr_conn->skt.sin_port);
642
643         curr_conn->rxconn =
644             rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr*/
645                              curr_conn->skt.sin_port,        /*Server port*/
646                              1,                              /*AFS service #*/
647                              secobj,                         /*Security obj*/
648                              0);                             /*# of above*/
649         if (curr_conn->rxconn == (struct rx_connection *)0) {
650             fprintf(stderr,
651                     "[%s] Can't create Rx connection to server '%s' (%lu)\n",
652                     rn, curr_conn->hostName, curr_conn->skt.sin_addr.s_addr);
653             conn_err = 1;
654         }
655         if (xstat_fs_debug)
656             printf("[%s] New connection at 0x%lx\n",
657                    rn, curr_conn->rxconn);
658
659         /*
660          * Bump the current xstat_fs connection to set up.
661          */
662         curr_conn++;
663
664     } /*for curr_srv*/
665
666     /*
667      * Create the AFS callback service (listener).
668      */
669     if (xstat_fs_debug)
670         printf("[%s] Creating AFS callback listener\n", rn);
671     rxsrv_afsserver =
672         rx_NewService(0,                        /*Use default port*/
673                       1,                        /*Service ID*/
674                       "afs",                    /*Service name*/
675                       &CBsecobj,                /*Ptr to security object(s)*/
676                       1,                        /*# of security objects*/
677                       RXAFSCB_ExecuteRequest);  /*Dispatcher*/
678     if (rxsrv_afsserver == (struct rx_service *)0) {
679         fprintf(stderr,
680                 "[%s] Can't create callback Rx service/listener\n",
681                 rn);
682         xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
683         return(-1);
684     }
685     if (xstat_fs_debug)
686         printf("[%s] Callback listener created\n", rn);
687
688     /*
689      * Start up the AFS callback service.
690      */
691     if (xstat_fs_debug)
692         printf("[%s] Starting up callback listener.\n", rn);
693     rx_StartServer(0); /*Don't donate yourself to LWP pool*/
694
695     /*
696      * Start up the probe LWP.
697      */
698     if (xstat_fs_debug)
699         printf("[%s] Creating the probe LWP\n", rn);
700     code =
701         LWP_CreateProcess(xstat_fs_LWP,         /*Function to start up*/
702                           LWP_STACK_SIZE,       /*Stack size in bytes*/
703                           1,                    /*Priority*/
704                           0,                    /*Parameters*/
705                           "xstat_fs Worker",    /*Name to use*/
706                           &probeLWP_ID);        /*Returned LWP process ID*/
707     if (code) {
708         fprintf(stderr,
709                 "[%s] Can't create xstat_fs LWP!  Error is %d\n",
710                 rn, code);
711         xstat_fs_Cleanup(1); /*Delete already-malloc'ed areas*/
712         return(code);
713     }
714     if (xstat_fs_debug)
715         printf("[%s] Probe LWP process structure located at 0x%x\n",
716                rn, probeLWP_ID);
717
718     /*
719      * Return the final results.
720      */
721     if (conn_err)
722         return(-2);
723     else
724         return(0);
725
726 } /*xstat_fs_Init*/
727
728
729 /*------------------------------------------------------------------------
730  * [exported] xstat_fs_ForceProbeNow
731  *
732  * Description:
733  *      Wake up the probe LWP, forcing it to execute a probe immediately.
734  *
735  * Arguments:
736  *      None.
737  *
738  * Returns:
739  *      0 on success,
740  *      Error value otherwise.
741  *
742  * Environment:
743  *      The module must have been initialized.
744  *
745  * Side Effects:
746  *      As advertised.
747  *------------------------------------------------------------------------*/
748
749 int xstat_fs_ForceProbeNow()
750
751 { /*xstat_fs_ForceProbeNow*/
752
753     static char rn[] = "xstat_fs_ForceProbeNow";        /*Routine name*/
754
755     /*
756      * There isn't a prayer unless we've been initialized.
757      */
758     if (!xstat_fs_initflag) {
759         fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
760         return(-1);
761     }
762
763     /*
764      * Kick the sucker in the side.
765      */
766     IOMGR_Cancel(probeLWP_ID);
767
768     /*
769      * We did it, so report the happy news.
770      */
771     return(0);
772
773 } /*xstat_fs_ForceProbeNow*/