e636e3eea574f22d0da66781810ccbf96a6e73a2
[openafs.git] / src / WINNT / afssvrmgr / alert.cpp
1 extern "C" {
2 #include <afs/param.h>
3 #include <afs/stds.h>
4 }
5
6 #include "svrmgr.h"
7 #include "alert.h"
8 #include "creds.h"
9
10
11 /*
12  * DEFINITIONS ________________________________________________________________
13  *
14  */
15
16
17 /*
18  * VARIABLES __________________________________________________________________
19  *
20  */
21
22
23 /*
24  * PROTOTYPES _________________________________________________________________
25  *
26  */
27
28 BOOL Alert_Scout_CheckServer (LPSERVER lpServer);
29
30 void Alert_BeginUpdate (LPIDENT lpi, LPSERVER *ppServer);
31 void Alert_EndUpdate (LPIDENT lpi, LPSERVER lpServer);
32
33 void Alert_RemoveFunc (LPOBJECTALERTS lpoa, size_t iAlert);
34 LPTSTR Alert_GetDescriptionFunc (LPIDENT lpiPrimary, size_t iAlertPrimary, LPIDENT lpiServer, BOOL fFull);
35 LPTSTR Alert_GetRemedyFunc (LPIDENT lpiPrimary, size_t iAlertPrimary, LPIDENT lpiServer);
36 LPTSTR Alert_GetButtonFunc (LPIDENT lpiPrimary, size_t iAlertPrimary, LPIDENT lpiServer);
37
38 DWORD WINAPI Alert_ScoutProc (LPVOID lp);
39 void Alert_Scout_SetUpToDate (LPOBJECTALERTS lpoa);
40
41
42 /*
43  * ROUTINES ___________________________________________________________________
44  *
45  */
46
47 LPOBJECTALERTS Alert_GetObjectAlerts (LPIDENT lpi, BOOL fAlwaysServer, ULONG *pStatus)
48 {
49    LPOBJECTALERTS lpoa = NULL;
50
51    if (fAlwaysServer || lpi->fIsServer())
52       {
53       LPSERVER_PREF lpsp;
54       if ((lpsp = (LPSERVER_PREF)lpi->GetServer()->GetUserParam()) != NULL)
55          {
56          lpoa = &lpsp->oa;
57          }
58       }
59    else if (lpi->fIsService())
60       {
61       LPSERVICE_PREF lpsp;
62       if ((lpsp = (LPSERVICE_PREF)lpi->GetUserParam()) != NULL)
63          {
64          lpoa = &lpsp->oa;
65          }
66       }
67    else if (lpi->fIsAggregate())
68       {
69       LPAGGREGATE_PREF lpap;
70       if ((lpap = (LPAGGREGATE_PREF)lpi->GetUserParam()) != NULL)
71          {
72          lpoa = &lpap->oa;
73          }
74       }
75    else if (lpi->fIsFileset())
76       {
77       LPFILESET_PREF lpfp;
78       if ((lpfp = (LPFILESET_PREF)lpi->GetUserParam()) != NULL)
79          {
80          lpoa = &lpfp->oa;
81          }
82       }
83
84    return lpoa;
85 }
86
87
88 void Alert_BeginUpdate (LPIDENT lpi, LPSERVER *ppServer)
89 {
90    if (lpi->fIsServer())
91       {
92       *ppServer = NULL;
93       }
94    else
95       {
96       *ppServer = lpi->OpenServer();
97       }
98 }
99
100
101 void Alert_EndUpdate (LPIDENT lpi, LPSERVER lpServer)
102 {
103    // If we just updated some aggregate, fileset or service, then the
104    // associated server's secondary alerts are probably out-of-date.
105    // Update them.
106    //
107    if (lpServer != NULL)
108       {
109       LPOBJECTALERTS lpoaServer = Alert_GetObjectAlerts (lpServer->GetIdentifier());
110       LPOBJECTALERTS lpoaChild  = Alert_GetObjectAlerts (lpi);
111
112       if (lpoaServer)
113          {
114          for (size_t iAlert = 0; iAlert < lpoaServer->nAlerts; )
115             {
116             if ( (lpoaServer->aAlerts[ iAlert ].alert == alertSECONDARY) &&
117                  (lpoaServer->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary == lpi) )
118                {
119                Alert_RemoveFunc (lpoaServer, iAlert);
120                }
121             else
122                {
123                ++iAlert;
124                }
125             }
126          }
127
128       if (lpoaServer && lpoaChild)
129          {
130          BOOL fNeedBadCredsWarning = FALSE;
131          BOOL fHaveBadCredsWarning = FALSE;
132
133          for (size_t iAlert = 0; iAlert < lpoaServer->nAlerts; ++iAlert)
134             {
135             if (lpoaServer->aAlerts[ iAlert ].alert == alertSECONDARY)
136                {
137                ALERT alert = Alert_GetAlert (lpoaServer->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary,
138                                              lpoaServer->aAlerts[ iAlert ].aiSECONDARY.iSecondary);
139                if (alert == alertNO_SVRENT)
140                   fNeedBadCredsWarning = TRUE;
141                }
142             }
143          for (iAlert = 0; iAlert < lpoaChild->nAlerts; ++iAlert)
144             {
145             if (lpoaChild->aAlerts[ iAlert ].alert == alertNO_SVRENT)
146                fNeedBadCredsWarning = TRUE;
147             }
148          if (lpoaServer->nAlerts &&
149              lpoaServer->aAlerts[ 0 ].alert == alertBADCREDS)
150             {
151             fHaveBadCredsWarning = TRUE;
152             }
153
154          if (fNeedBadCredsWarning)
155             {
156             fNeedBadCredsWarning = !CheckCredentials (FALSE);
157             }
158
159          if (fHaveBadCredsWarning && !fNeedBadCredsWarning)
160             {
161             Alert_RemoveFunc (lpoaServer, 0);
162             }
163          else if (fNeedBadCredsWarning && !fHaveBadCredsWarning)
164             {
165             for (iAlert = min( lpoaServer->nAlerts, nAlertsMAX-1 );
166                  iAlert > 0;
167                  --iAlert)
168                {
169                memcpy (&lpoaServer->aAlerts[ iAlert ], &lpoaServer->aAlerts[ iAlert-1 ], sizeof(ALERTINFO));
170                }
171             lpoaServer->aAlerts[0].alert = alertBADCREDS;
172             lpoaServer->nAlerts = min( nAlertsMAX, lpoaServer->nAlerts+1 );
173             }
174
175          for (iAlert = 0; iAlert < lpoaChild->nAlerts; ++iAlert)
176             {
177             if (lpoaServer->nAlerts < nAlertsMAX)
178                {
179                lpoaServer->aAlerts[ lpoaServer->nAlerts ].alert = alertSECONDARY;
180                lpoaServer->aAlerts[ lpoaServer->nAlerts ].aiSECONDARY.lpiSecondary = lpi;
181                lpoaServer->aAlerts[ lpoaServer->nAlerts ].aiSECONDARY.iSecondary = iAlert;
182                lpoaServer->nAlerts ++;
183                }
184             }
185          }
186
187       lpServer->Close();
188       }
189 }
190
191
192 void Alert_SetDefaults (LPOBJECTALERTS lpoa)
193 {
194    if (lpoa != NULL)
195       {
196       memset (lpoa, 0x00, sizeof(OBJECTALERTS));
197       lpoa->cTickRefresh = DEFAULT_SCOUT_REFRESH_RATE;
198       }
199 }
200
201
202 void Alert_Initialize (LPOBJECTALERTS lpoa)
203 {
204    if (lpoa != NULL)
205       {
206       lpoa->dwTickNextTest = 0;
207       lpoa->dwTickNextRefresh = 0;
208       lpoa->nAlerts = 0;
209       }
210 }
211
212
213 void Alert_RemoveSecondary (LPIDENT lpiChild)
214 {
215    BOOL fChangedAlerts = FALSE;
216
217    LPOBJECTALERTS lpoa;
218    if ((lpoa = Alert_GetObjectAlerts (lpiChild, TRUE)) != NULL)
219       {
220       for (size_t iAlert = 0; iAlert < lpoa->nAlerts; )
221          {
222          if ( (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY) &&
223               (lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary == lpiChild) )
224             {
225             Alert_RemoveFunc (lpoa, iAlert);
226             fChangedAlerts = TRUE;
227             }
228          else
229             {
230             ++iAlert;
231             }
232          }
233
234
235       BOOL fNeedBadCredsWarning = FALSE;
236
237       for (iAlert = 0; iAlert < lpoa->nAlerts; ++iAlert)
238          {
239          if (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY)
240             {
241             ALERT alert = Alert_GetAlert (lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary,
242                                           lpoa->aAlerts[ iAlert ].aiSECONDARY.iSecondary);
243             if (alert == alertNO_SVRENT)
244                fNeedBadCredsWarning = TRUE;
245             }
246          }
247
248       if ( (!fNeedBadCredsWarning) &&
249            (lpoa->nAlerts && (lpoa->aAlerts[ 0 ].alert == alertBADCREDS)) )
250          {
251          Alert_RemoveFunc (lpoa, 0);
252          fChangedAlerts = TRUE;
253          }
254       }
255
256    if (fChangedAlerts)
257       {
258       PostNotification (evtAlertsChanged, lpiChild->GetServer());
259       PostNotification (evtAlertsChanged, lpiChild);
260       }
261 }
262
263
264 void Alert_Remove (LPIDENT lpi, size_t iAlert)
265 {
266    LPOBJECTALERTS lpoa;
267
268    if ((lpoa = Alert_GetObjectAlerts (lpi)) != NULL)
269       {
270       if (iAlert < lpoa->nAlerts)
271          {
272          LPSERVER lpServer;
273          Alert_BeginUpdate (lpi, &lpServer);
274
275          Alert_RemoveFunc (lpoa, iAlert);
276
277          Alert_EndUpdate (lpi, lpServer);
278          }
279       }
280 }
281
282
283 void Alert_RemoveFunc (LPOBJECTALERTS lpoa, size_t iAlert)
284 {
285    if (iAlert < lpoa->nAlerts-1)
286       {
287       memcpy (&lpoa->aAlerts[ iAlert ], &lpoa->aAlerts[ lpoa->nAlerts-1 ], sizeof(ALERTINFO));
288       }
289    lpoa->nAlerts --;
290 }
291
292
293 void Alert_AddPrimary (LPIDENT lpi, LPALERTINFO lpai)
294 {
295    LPOBJECTALERTS lpoa;
296
297    if ((lpoa = Alert_GetObjectAlerts (lpi)) != NULL)
298       {
299       if (lpoa->nAlerts < nAlertsMAX)
300          {
301          LPSERVER lpServer;
302          Alert_BeginUpdate (lpi, &lpServer);
303
304          memcpy (&lpoa->aAlerts[ lpoa->nAlerts ], lpai, sizeof(ALERTINFO));
305          lpoa->nAlerts ++;
306
307          Alert_EndUpdate (lpi, lpServer);
308          }
309       }
310 }
311
312
313 void Alert_Scout_ServerStatus (LPIDENT lpi, ULONG status)
314 {
315    LPOBJECTALERTS lpoa;
316    if ((lpoa = Alert_GetObjectAlerts (lpi)) != NULL)
317       {
318       BOOL fChanged = FALSE;
319
320       for (size_t iAlert = 0; iAlert < lpoa->nAlerts; ++iAlert)
321          {
322          if (lpoa->aAlerts[ iAlert ].alert == alertTIMEOUT)
323             {
324             fChanged = TRUE;
325             Alert_RemoveFunc (lpoa, iAlert);
326             break;
327             }
328          }
329
330       if (status != 0)
331          {
332          size_t iInsert = 0;
333          if (lpoa->nAlerts && (lpoa->aAlerts[0].alert == alertBADCREDS))
334             iInsert = 1;
335
336          for (size_t iHole = iInsert; iHole < lpoa->nAlerts; ++iHole)
337             {
338             if (lpoa->aAlerts[ iHole ].alert == alertINVALID)
339                break;
340             }
341          if (iHole < nAlertsMAX)
342             {
343             for (size_t iTarget = iHole; iTarget > iInsert; --iTarget)
344                {
345                memcpy (&lpoa->aAlerts[ iTarget ], &lpoa->aAlerts[ iTarget-1 ], sizeof(ALERTINFO));
346                }
347
348             lpoa->nAlerts ++;
349             lpoa->aAlerts[ iInsert ].alert = alertTIMEOUT;
350             lpoa->aAlerts[ iInsert ].aiTIMEOUT.status = status;
351             lpoa->aAlerts[ iInsert ].aiTIMEOUT.stLastAttempt;
352             GetSystemTime (&lpoa->aAlerts[ iInsert ].aiTIMEOUT.stLastAttempt);
353
354             fChanged = TRUE;
355             }
356          }
357
358       if (fChanged)
359          {
360          PostNotification (evtAlertsChanged, lpi);
361          }
362       }
363 }
364
365
366 size_t Alert_GetCount (LPIDENT lpi)
367 {
368    LPOBJECTALERTS lpoa;
369
370    if ((lpoa = Alert_GetObjectAlerts (lpi)) == NULL)
371       return 0;
372
373    return lpoa->nAlerts;
374 }
375
376
377 ALERT Alert_GetAlert (LPIDENT lpi, size_t iAlert)
378 {
379    LPOBJECTALERTS lpoa;
380
381    if ((lpoa = Alert_GetObjectAlerts (lpi)) == NULL)
382       return alertINVALID;
383
384    if (iAlert > lpoa->nAlerts)
385       return alertINVALID;
386
387    if (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY)
388       {
389       return Alert_GetAlert (lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary,
390                              lpoa->aAlerts[ iAlert ].aiSECONDARY.iSecondary);
391       }
392
393    return lpoa->aAlerts[ iAlert ].alert;
394 }
395
396
397 LPIDENT Alert_GetIdent (LPIDENT lpi, size_t iAlert)
398 {
399    LPOBJECTALERTS lpoa;
400
401    if ((lpoa = Alert_GetObjectAlerts (lpi)) == NULL)
402       return NULL;
403
404    if (iAlert > lpoa->nAlerts)
405       return NULL;
406
407    if (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY)
408       {
409       return lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary;
410       }
411
412    return lpi;
413 }
414
415
416 LPTSTR Alert_GetQuickDescription (LPIDENT lpi)
417 {
418    LPTSTR pszStatus = NULL;
419
420    size_t cAlerts;
421    if ((cAlerts = Alert_GetCount (lpi)) <= 1)
422       pszStatus = Alert_GetDescription (lpi, 0, FALSE);
423    else if (lpi->fIsServer())
424       pszStatus = FormatString (IDS_SERVER_MULTIPLE_PROBLEMS, TEXT("%lu"), cAlerts);
425    else if (lpi->fIsService())
426       pszStatus = FormatString (IDS_SERVICE_MULTIPLE_PROBLEMS, TEXT("%lu"), cAlerts);
427    else if (lpi->fIsAggregate())
428       pszStatus = FormatString (IDS_AGGREGATE_MULTIPLE_PROBLEMS, TEXT("%lu"), cAlerts);
429    else if (lpi->fIsFileset())
430       pszStatus = FormatString (IDS_FILESET_MULTIPLE_PROBLEMS, TEXT("%lu"), cAlerts);
431
432    return pszStatus;
433 }
434
435
436 LPTSTR Alert_GetDescription (LPIDENT lpi, size_t iAlert, BOOL fFull)
437 {
438    LPOBJECTALERTS lpoa;
439
440    if ((lpoa = Alert_GetObjectAlerts (lpi)) == NULL)
441       return NULL;
442
443    if (!lpoa->nAlerts && lpi->fIsServer())
444       {
445       LPSERVER_PREF lpsp;
446       if ((lpsp = (LPSERVER_PREF)lpi->GetUserParam()) != NULL)
447          {
448          if (!lpsp->fIsMonitored)
449             {
450             TCHAR szName[ cchNAME ];
451             lpi->GetServerName (szName);
452             return FormatString (IDS_ALERT_DESCSHORT_UNMONITORED, TEXT("%s"), szName);
453             }
454          }
455       }
456
457    if (iAlert >= lpoa->nAlerts)
458       return NULL;
459
460    if (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY)
461       {
462       return Alert_GetDescriptionFunc (lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary,
463                                        lpoa->aAlerts[ iAlert ].aiSECONDARY.iSecondary,
464                                        lpi,
465                                        fFull);
466       }
467
468    return Alert_GetDescriptionFunc (lpi, iAlert, NULL, fFull);
469 }
470
471
472 LPTSTR Alert_GetRemedy (LPIDENT lpi, size_t iAlert)
473 {
474    LPOBJECTALERTS lpoa;
475
476    if ((lpoa = Alert_GetObjectAlerts (lpi)) == NULL)
477       return NULL;
478
479    if (iAlert >= lpoa->nAlerts)
480       return NULL;
481
482    if (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY)
483       {
484       return Alert_GetRemedyFunc (lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary,
485                                   lpoa->aAlerts[ iAlert ].aiSECONDARY.iSecondary,
486                                   lpi);
487       }
488
489    return Alert_GetRemedyFunc (lpi, iAlert, NULL);
490 }
491
492
493 LPTSTR Alert_GetButton (LPIDENT lpi, size_t iAlert)
494 {
495    LPOBJECTALERTS lpoa;
496
497    if ((lpoa = Alert_GetObjectAlerts (lpi)) == NULL)
498       return NULL;
499
500    if (iAlert >= lpoa->nAlerts)
501       return NULL;
502
503    if (lpoa->aAlerts[ iAlert ].alert == alertSECONDARY)
504       {
505       return Alert_GetButtonFunc (lpoa->aAlerts[ iAlert ].aiSECONDARY.lpiSecondary,
506                                   lpoa->aAlerts[ iAlert ].aiSECONDARY.iSecondary,
507                                   lpi);
508       }
509
510    return Alert_GetButtonFunc (lpi, iAlert, NULL);
511 }
512
513
514 LPTSTR Alert_GetDescriptionFunc (LPIDENT lpiPrimary, size_t iAlertPrimary, LPIDENT lpiServer, BOOL fFull)
515 {
516    LPOBJECTALERTS lpoa;
517    if ((lpoa = Alert_GetObjectAlerts (lpiPrimary)) != NULL)
518       {
519       int ids;
520       TCHAR szServer[ cchRESOURCE ];
521       TCHAR szService[ cchRESOURCE ];
522       TCHAR szAggregate[ cchRESOURCE ];
523       TCHAR szFileset[ cchRESOURCE ];
524
525       switch (lpoa->aAlerts[ iAlertPrimary ].alert)
526          {
527          case alertTIMEOUT:
528             ids = (fFull) ? IDS_ALERT_DESCFULL_TIMEOUT : IDS_ALERT_DESCSHORT_TIMEOUT;
529             lpiPrimary->GetServerName (szServer);
530             return FormatString (ids, TEXT("%s%t%e"), szServer, &lpoa->aAlerts[ iAlertPrimary ].aiTIMEOUT.stLastAttempt, lpoa->aAlerts[ iAlertPrimary ].aiTIMEOUT.status);
531
532          case alertFULL:
533             lpiPrimary->GetServerName (szServer);
534             lpiPrimary->GetAggregateName (szAggregate);
535             if (lpiPrimary->fIsAggregate())
536                {
537                ids = (fFull) ? IDS_ALERT_DESCFULL_AGG_FULL : IDS_ALERT_DESCSHORT_AGG_FULL;
538                return FormatString (ids, TEXT("%s%s%d%.1B"), szServer, szAggregate, lpoa->aAlerts[ iAlertPrimary ].aiFULL.perWarning, 1024.0 * (double)lpoa->aAlerts[ iAlertPrimary ].aiFULL.ckWarning);
539                }
540             else if (lpiPrimary->fIsFileset())
541                {
542                ids = (fFull) ? IDS_ALERT_DESCFULL_SET_FULL : IDS_ALERT_DESCSHORT_SET_FULL;
543                lpiPrimary->GetFilesetName (szFileset);
544                return FormatString (ids, TEXT("%s%s%s%d%.1B"), szServer, szAggregate, szFileset, lpoa->aAlerts[ iAlertPrimary ].aiFULL.perWarning, 1024.0 * (double)lpoa->aAlerts[ iAlertPrimary ].aiFULL.ckWarning);
545                }
546             break;
547
548          case alertNO_VLDBENT:
549             ids = (fFull) ? IDS_ALERT_DESCFULL_NO_VLDBENT : IDS_ALERT_DESCSHORT_NO_VLDBENT;
550             lpiPrimary->GetServerName (szServer);
551             lpiPrimary->GetAggregateName (szAggregate);
552             lpiPrimary->GetFilesetName (szFileset);
553             return FormatString (ids, TEXT("%s%s%s"), szServer, szAggregate, szFileset);
554
555          case alertNO_SVRENT:
556             if (lpiPrimary->fIsFileset())
557                {
558                ids = (fFull) ? IDS_ALERT_DESCFULL_NO_SVRENT_SET : IDS_ALERT_DESCSHORT_NO_SVRENT_SET;
559                lpiPrimary->GetServerName (szServer);
560                lpiPrimary->GetAggregateName (szAggregate);
561                lpiPrimary->GetFilesetName (szFileset);
562                return FormatString (ids, TEXT("%s%s%s"), szServer, szAggregate, szFileset);
563                }
564             else
565                {
566                ids = (fFull) ? IDS_ALERT_DESCFULL_NO_SVRENT_AGG : IDS_ALERT_DESCSHORT_NO_SVRENT_AGG;
567                lpiPrimary->GetServerName (szServer);
568                lpiPrimary->GetAggregateName (szAggregate);
569                return FormatString (ids, TEXT("%s%s"), szServer, szAggregate);
570                }
571             break;
572
573          case alertSTOPPED:
574             ids = (fFull) ? IDS_ALERT_DESCFULL_STOPPED : IDS_ALERT_DESCSHORT_STOPPED;
575             lpiPrimary->GetServerName (szServer);
576             lpiPrimary->GetServiceName (szService);
577             return FormatString (ids, TEXT("%s%s%t%t%lu"), szServer, szService, &lpoa->aAlerts[ iAlertPrimary ].aiSTOPPED.stStopped, &lpoa->aAlerts[ iAlertPrimary ].aiSTOPPED.stLastError, lpoa->aAlerts[ iAlertPrimary ].aiSTOPPED.errLastError);
578
579          case alertBADCREDS:
580             ids = (fFull) ? IDS_ALERT_DESCFULL_BADCREDS : IDS_ALERT_DESCSHORT_BADCREDS;
581             lpiPrimary->GetServerName (szServer);
582             return FormatString (ids, TEXT("%s"), szServer);
583
584          case alertOVERALLOC:
585             lpiPrimary->GetServerName (szServer);
586             lpiPrimary->GetAggregateName (szAggregate);
587             ids = (fFull) ? IDS_ALERT_DESCFULL_AGG_ALLOC : IDS_ALERT_DESCSHORT_AGG_ALLOC;
588             return FormatString (ids, TEXT("%s%s%.1B%.1B"), szServer, szAggregate, 1024.0 * (double)(lpoa->aAlerts[ iAlertPrimary ].aiOVERALLOC.ckCapacity), 1024.0 * (double)(lpoa->aAlerts[ iAlertPrimary ].aiOVERALLOC.ckAllocated));
589
590          case alertSTATE_NO_VNODE:
591             ids = (fFull) ? IDS_ALERT_DESCFULL_STATE_NO_VNODE : IDS_ALERT_DESCSHORT_STATE_NO_VNODE;
592             lpiPrimary->GetServerName (szServer);
593             lpiPrimary->GetAggregateName (szAggregate);
594             lpiPrimary->GetFilesetName (szFileset);
595             return FormatString (ids, TEXT("%s%s%s%08lX"), szServer, szAggregate, szFileset, lpoa->aAlerts[ iAlertPrimary ].aiSTATE.State);
596
597          case alertSTATE_NO_SERVICE:
598             ids = (fFull) ? IDS_ALERT_DESCFULL_STATE_NO_SERVICE : IDS_ALERT_DESCSHORT_STATE_NO_SERVICE;
599             lpiPrimary->GetServerName (szServer);
600             lpiPrimary->GetAggregateName (szAggregate);
601             lpiPrimary->GetFilesetName (szFileset);
602             return FormatString (ids, TEXT("%s%s%s%08lX"), szServer, szAggregate, szFileset, lpoa->aAlerts[ iAlertPrimary ].aiSTATE.State);
603
604          case alertSTATE_OFFLINE:
605             ids = (fFull) ? IDS_ALERT_DESCFULL_STATE_OFFLINE : IDS_ALERT_DESCSHORT_STATE_OFFLINE;
606             lpiPrimary->GetServerName (szServer);
607             lpiPrimary->GetAggregateName (szAggregate);
608             lpiPrimary->GetFilesetName (szFileset);
609             return FormatString (ids, TEXT("%s%s%s%08lX"), szServer, szAggregate, szFileset, lpoa->aAlerts[ iAlertPrimary ].aiSTATE.State);
610          }
611       }
612
613    return NULL;
614 }
615
616
617 LPTSTR Alert_GetRemedyFunc (LPIDENT lpiPrimary, size_t iAlertPrimary, LPIDENT lpiServer)
618 {
619    LPOBJECTALERTS lpoa;
620    if ((lpoa = Alert_GetObjectAlerts (lpiPrimary)) != NULL)
621       {
622       switch (lpoa->aAlerts[ iAlertPrimary ].alert)
623          {
624          case alertTIMEOUT:
625             return FormatString (IDS_ALERT_FIX_TIMEOUT);
626          case alertFULL:
627             if (lpiPrimary->fIsAggregate())
628                return FormatString (IDS_ALERT_FIX_AGG_FULL);
629             else if (lpiPrimary->fIsFileset())
630                return FormatString (IDS_ALERT_FIX_SET_FULL);
631             break;
632          case alertNO_VLDBENT:
633             return FormatString (IDS_ALERT_FIX_NO_VLDBENT);
634          case alertNO_SVRENT:
635             if (lpiPrimary->fIsFileset())
636                return FormatString (IDS_ALERT_FIX_NO_SVRENT_SET);
637             else
638                return FormatString (IDS_ALERT_FIX_NO_SVRENT_AGG);
639             break;
640          case alertSTOPPED:
641             return FormatString (IDS_ALERT_FIX_STOPPED);
642          case alertBADCREDS:
643             return FormatString (IDS_ALERT_FIX_BADCREDS);
644          case alertOVERALLOC:
645             return FormatString (IDS_ALERT_FIX_AGG_ALLOC);
646          case alertSTATE_NO_VNODE:
647             return FormatString (IDS_ALERT_FIX_STATE_NO_VNODE);
648          case alertSTATE_NO_SERVICE:
649             return FormatString (IDS_ALERT_FIX_STATE_NO_SERVICE);
650          case alertSTATE_OFFLINE:
651             return FormatString (IDS_ALERT_FIX_STATE_OFFLINE);
652          }
653       }
654
655    return NULL;
656 }
657
658
659 LPTSTR Alert_GetButtonFunc (LPIDENT lpiPrimary, size_t iAlertPrimary, LPIDENT lpiServer)
660 {
661    LPOBJECTALERTS lpoa;
662    if ((lpoa = Alert_GetObjectAlerts (lpiPrimary)) != NULL)
663       {
664       switch (lpoa->aAlerts[ iAlertPrimary ].alert)
665          {
666          case alertTIMEOUT:
667             return FormatString (IDS_ALERT_BUTTON_TRYAGAIN);
668          case alertFULL:
669             return FormatString (IDS_ALERT_BUTTON_WARNINGS);
670          case alertNO_VLDBENT:
671             return NULL;
672          case alertNO_SVRENT:
673             return NULL;
674          case alertSTOPPED:
675             return FormatString (IDS_ALERT_BUTTON_VIEWLOG);
676          case alertBADCREDS:
677             return FormatString (IDS_ALERT_BUTTON_GETCREDS);
678          case alertOVERALLOC:
679             return NULL;
680          case alertSTATE_NO_VNODE:
681             return NULL;
682          case alertSTATE_NO_SERVICE:
683             return NULL;
684          case alertSTATE_OFFLINE:
685             return NULL;
686          }
687       }
688
689    return NULL;
690 }
691
692
693 /*
694  * SCOUT ______________________________________________________________________
695  *
696  * (okay, well, our simulated Scout anyway)
697  *
698  */
699
700 static HANDLE hScout = 0;       // scout's thread
701 static HANDLE heScoutWakeup = 0;        // scout's wakeup event
702
703 BOOL Alert_StartScout (ULONG *pStatus)
704 {
705    if (hScout == 0)  // create scout?
706       {
707       heScoutWakeup = CreateEvent (NULL, FALSE, FALSE, NULL);
708
709       DWORD dwThreadID;
710       if ((hScout = CreateThread (NULL, 0,
711                                   (LPTHREAD_START_ROUTINE)Alert_ScoutProc,
712                                   NULL, 0,
713                                   &dwThreadID)) == NULL)
714          {
715          if (pStatus)
716             *pStatus = GetLastError();
717          return FALSE;
718          }
719
720       SetThreadPriority (hScout, THREAD_PRIORITY_BELOW_NORMAL);
721       }
722    else // or just wake up scout from its slumber?
723       {
724       PulseEvent (heScoutWakeup);
725       }
726
727    return TRUE;
728 }
729
730
731 BOOL Alert_Scout_QueueCheckServer (LPIDENT lpiServer, ULONG *pStatus)
732 {
733    Alert_Scout_SetOutOfDate (lpiServer);
734    return Alert_StartScout (pStatus);
735 }
736
737
738 DWORD WINAPI Alert_ScoutProc (LPVOID lp)
739 {
740    // We'll keep working forever...
741    //
742    for (;;)
743       {
744       AfsClass_Enter();
745
746       LPCELL lpCell = (g.lpiCell == NULL) ? NULL : g.lpiCell->OpenCell();
747       if (lpCell != NULL)
748          {
749          // See if our credentials have expired
750          //
751          CheckForExpiredCredentials();
752
753          // See if any new servers have arrived, or old servers disappeared.
754          //
755          lpCell->RefreshServerList();
756
757          // Check all the out-of-date servers we can find.
758          //
759          HENUM hEnum;
760          for (LPSERVER lpServer = lpCell->ServerFindFirst (&hEnum); lpServer; lpServer = lpCell->ServerFindNext (&hEnum))
761             {
762             LPIDENT lpiServer = lpServer->GetIdentifier();
763             LPOBJECTALERTS lpoa;
764
765             if ( ((lpoa = Alert_GetObjectAlerts (lpiServer)) != NULL) &&
766                  (lpoa->dwTickNextTest <= GetTickCount()) )
767                {
768
769                // Okay!  We've found a server that needs to be tested for
770                // alert conditions.  Do that now, and when we're done, set
771                // its next query-time to some distance in the future.
772                //
773                if (lpoa->dwTickNextRefresh == 0)
774                   {
775                   if (lpoa->cTickRefresh != 0)
776                      lpoa->dwTickNextRefresh = lpoa->cTickRefresh + GetTickCount();
777                   }
778                else if (lpoa->dwTickNextRefresh <= GetTickCount())
779                   {
780                   (void)lpServer->Invalidate();
781                   (void)lpServer->RefreshAll();
782                   lpoa->dwTickNextRefresh = lpoa->cTickRefresh + GetTickCount();
783                   }
784
785                (void)Alert_Scout_CheckServer (lpServer);
786                }
787
788             lpServer->Close();
789             }
790
791          lpCell->Close();
792          }
793
794       AfsClass_Leave();
795
796       // Now that we have completed a pass over the servers in this cell,
797       // and now that we're not holding any critical sections on which
798       // other threads would otherwise block, go to sleep for a while.
799       //
800       WaitForSingleObjectEx (heScoutWakeup, 45L * cmsec1SECOND, FALSE);
801       }
802
803    return 0;
804 }
805
806
807 void Alert_Scout_SetOutOfDate (LPIDENT lpi)
808 {
809    LPOBJECTALERTS lpoa;
810    if ((lpoa = Alert_GetObjectAlerts (lpi, TRUE)) != NULL)
811       {
812       lpoa->dwTickNextTest = GetTickCount() -1;
813       }
814 }
815
816
817 void Alert_Scout_SetUpToDate (LPOBJECTALERTS lpoa)
818 {
819    if (lpoa != NULL)
820       {
821       lpoa->dwTickNextTest = GetTickCount() + lpoa->cTickRefresh;
822       }
823 }
824
825
826 BOOL Alert_Scout_CheckServer (LPSERVER lpServer)
827 {
828    BOOL rc = TRUE;
829
830    LPSERVER_PREF lpsp;
831    if ((lpsp = (LPSERVER_PREF)lpServer->GetUserParam()) != NULL)
832       {
833       LPOBJECTALERTS lpoa;
834       if ((lpoa = Alert_GetObjectAlerts (lpServer->GetIdentifier())) != NULL)
835          {
836          PostNotification (evtScoutBegin, lpServer->GetIdentifier());
837
838          BOOL fChangedServerAlerts = FALSE;
839
840          DWORD dwTickNextTestWhenStarted = lpoa->dwTickNextTest;
841
842          // First look through the server's aggregates and filesets, to
843          // find any which have usages over their warning threshholds.
844          //
845          HENUM heAggregate;
846          for (LPAGGREGATE lpAggregate = lpServer->AggregateFindFirst (&heAggregate); lpAggregate; lpAggregate = lpServer->AggregateFindNext (&heAggregate))
847             {
848             BOOL fChangedAggregateAlerts = FALSE;
849             LPIDENT lpiAggregate = lpAggregate->GetIdentifier();
850
851             LPOBJECTALERTS lpoaAggregate;
852             if ((lpoaAggregate = Alert_GetObjectAlerts (lpAggregate->GetIdentifier())) != NULL)
853                {
854                for (size_t iAlert = 0; iAlert < lpoaAggregate->nAlerts; )
855                   {
856                   if ( (lpoaAggregate->aAlerts[ iAlert ].alert == alertFULL) ||
857                        (lpoaAggregate->aAlerts[ iAlert ].alert == alertOVERALLOC) ||
858                        (lpoaAggregate->aAlerts[ iAlert ].alert == alertNO_SVRENT) )
859                      {
860                      fChangedAggregateAlerts = TRUE;
861                      fChangedServerAlerts = TRUE;
862                      Alert_Remove (lpAggregate->GetIdentifier(), iAlert);
863                      }
864                   else
865                      ++iAlert;
866                   }
867
868                LPAGGREGATE_PREF lpap;
869                if ((lpap = (LPAGGREGATE_PREF)lpAggregate->GetUserParam()) != NULL)
870                   {
871                   short wGhost = lpAggregate->GetGhostStatus();
872                   if (lpsp->fWarnAggNoServ && !(wGhost & GHOST_HAS_SERVER_ENTRY))
873                      {
874                      ALERTINFO ai;
875                      ai.alert = alertNO_SVRENT;
876                      Alert_AddPrimary (lpAggregate->GetIdentifier(), &ai);
877                      fChangedAggregateAlerts = TRUE;
878                      fChangedServerAlerts = TRUE;
879                      }
880
881                   if (lpsp->fWarnAggAlloc && lpap->fWarnAggAlloc)
882                      {
883                      AGGREGATESTATUS as;
884                      if (lpAggregate->GetStatus (&as, TRUE))
885                         {
886                         if (as.ckStorageAllocated > as.ckStorageTotal)
887                            {
888                            ALERTINFO ai;
889                            ai.alert = alertOVERALLOC;
890                            ai.aiOVERALLOC.ckAllocated = as.ckStorageAllocated;
891                            ai.aiOVERALLOC.ckCapacity = as.ckStorageTotal;
892                            Alert_AddPrimary (lpAggregate->GetIdentifier(), &ai);
893                            fChangedAggregateAlerts = TRUE;
894                            fChangedServerAlerts = TRUE;
895                            }
896                         }
897                      }
898
899                   short perWarnAggFull = lpap->perWarnAggFull;
900                   if (perWarnAggFull == -1)
901                      perWarnAggFull = lpsp->perWarnAggFull;
902                   if (perWarnAggFull != 0)
903                      {
904                      AGGREGATESTATUS as;
905                      if (lpAggregate->GetStatus (&as, TRUE))
906                         {
907                         if (as.ckStorageTotal != 0)
908                            {
909                            short perNow = (short)( (double)(as.ckStorageTotal - as.ckStorageFree) * 100.0 / (double)(as.ckStorageTotal) );
910
911                            if (perNow > perWarnAggFull)
912                               {
913                               ALERTINFO ai;
914                               ai.alert = alertFULL;
915                               ai.aiFULL.perWarning = perWarnAggFull;
916                               ai.aiFULL.ckWarning = (ULONG)( (double)perWarnAggFull * (double)(as.ckStorageTotal) / 100.0 );
917                               Alert_AddPrimary (lpAggregate->GetIdentifier(), &ai);
918                               fChangedAggregateAlerts = TRUE;
919                               fChangedServerAlerts = TRUE;
920                               }
921                            }
922                         }
923                      }
924                   }
925                }
926
927             HENUM heFileset;
928             for (LPFILESET lpFileset = lpAggregate->FilesetFindFirst (&heFileset); lpFileset; lpFileset = lpAggregate->FilesetFindNext (&heFileset))
929                {
930                BOOL fChangedFilesetAlerts = FALSE;
931                LPIDENT lpiFileset = lpFileset->GetIdentifier();
932
933                LPOBJECTALERTS lpoaFileset;
934                if ((lpoaFileset = Alert_GetObjectAlerts (lpFileset->GetIdentifier())) != NULL)
935                   {
936                   for (size_t iAlert = 0; iAlert < lpoaFileset->nAlerts; )
937                      {
938                      if ( (lpoaFileset->aAlerts[ iAlert ].alert == alertFULL) ||
939                           (lpoaFileset->aAlerts[ iAlert ].alert == alertSTATE_NO_VNODE) ||
940                           (lpoaFileset->aAlerts[ iAlert ].alert == alertSTATE_NO_SERVICE) ||
941                           (lpoaFileset->aAlerts[ iAlert ].alert == alertSTATE_OFFLINE) ||
942                           (lpoaFileset->aAlerts[ iAlert ].alert == alertNO_VLDBENT) ||
943                           (lpoaFileset->aAlerts[ iAlert ].alert == alertNO_SVRENT) )
944                         {
945                         fChangedFilesetAlerts = TRUE;
946                         fChangedServerAlerts = TRUE;
947                         Alert_Remove (lpFileset->GetIdentifier(), iAlert);
948                         }
949                      else
950                         ++iAlert;
951                      }
952                   }
953
954                LPFILESET_PREF lpfp;
955                if ((lpfp = (LPFILESET_PREF)lpFileset->GetUserParam()) != NULL)
956                   {
957                   FILESETSTATUS fs;
958                   if (lpFileset->GetStatus (&fs, TRUE))
959                      {
960                      if (fs.State & fsNO_VNODE)
961                         {
962                         ALERTINFO ai;
963                         ai.alert = alertSTATE_NO_VNODE;
964                         ai.aiSTATE.State = fs.State;
965                         Alert_AddPrimary (lpFileset->GetIdentifier(), &ai);
966                         fChangedFilesetAlerts = TRUE;
967                         fChangedServerAlerts = TRUE;
968                         }
969                      else if (fs.State & fsNO_SERVICE)
970                         {
971                         ALERTINFO ai;
972                         ai.alert = alertSTATE_NO_SERVICE;
973                         ai.aiSTATE.State = fs.State;
974                         Alert_AddPrimary (lpFileset->GetIdentifier(), &ai);
975                         fChangedFilesetAlerts = TRUE;
976                         fChangedServerAlerts = TRUE;
977                         }
978                      else if (fs.State & fsOFFLINE)
979                         {
980                         ALERTINFO ai;
981                         ai.alert = alertSTATE_OFFLINE;
982                         ai.aiSTATE.State = fs.State;
983                         Alert_AddPrimary (lpFileset->GetIdentifier(), &ai);
984                         fChangedFilesetAlerts = TRUE;
985                         fChangedServerAlerts = TRUE;
986                         }
987
988                      short perWarnSetFull = lpfp->perWarnSetFull;
989                      if (perWarnSetFull == -1)
990                         perWarnSetFull = lpsp->perWarnSetFull;
991                      if (perWarnSetFull != 0)
992                         {
993                         if (fs.Type == ftREADWRITE)
994                            {
995                            if (fs.ckQuota != 0)
996                               {
997                               short perNow = (short)( (double)(fs.ckUsed) * 100.0 / (double)(fs.ckQuota) );
998
999                               if (perNow > perWarnSetFull)
1000                                  {
1001                                  ALERTINFO ai;
1002                                  ai.alert = alertFULL;
1003                                  ai.aiFULL.perWarning = perWarnSetFull;
1004                                  ai.aiFULL.ckWarning = (ULONG)( (double)perWarnSetFull * (double)(fs.ckQuota) / 100.0 );
1005                                  Alert_AddPrimary (lpFileset->GetIdentifier(), &ai);
1006                                  fChangedFilesetAlerts = TRUE;
1007                                  fChangedServerAlerts = TRUE;
1008                                  }
1009                               }
1010                            }
1011                         }
1012                      }
1013
1014                   short wGhost = lpFileset->GetGhostStatus();
1015                   if (lpsp->fWarnSetNoVLDB && !(wGhost & GHOST_HAS_VLDB_ENTRY))
1016                      {
1017                      ALERTINFO ai;
1018                      ai.alert = alertNO_VLDBENT;
1019                      Alert_AddPrimary (lpFileset->GetIdentifier(), &ai);
1020                      fChangedFilesetAlerts = TRUE;
1021                      fChangedServerAlerts = TRUE;
1022                      }
1023                   if (lpsp->fWarnSetNoServ && !(wGhost & GHOST_HAS_SERVER_ENTRY) && !(fs.Type == ftREPLICA))
1024                      {
1025                      ALERTINFO ai;
1026                      ai.alert = alertNO_SVRENT;
1027                      Alert_AddPrimary (lpFileset->GetIdentifier(), &ai);
1028                      fChangedFilesetAlerts = TRUE;
1029                      fChangedServerAlerts = TRUE;
1030                      }
1031                   }
1032
1033                lpFileset->Close();
1034                if (fChangedFilesetAlerts)
1035                   {
1036                   PostNotification (evtAlertsChanged, lpiFileset);
1037                   }
1038                }
1039
1040             lpAggregate->Close();
1041             if (fChangedAggregateAlerts)
1042                {
1043                PostNotification (evtAlertsChanged, lpiAggregate);
1044                }
1045             }
1046
1047          // Next look through the server's servces to find any
1048          // which have stopped.
1049          //
1050          HENUM heService;
1051          for (LPSERVICE lpService = lpServer->ServiceFindFirst (&heService); lpService; lpService = lpServer->ServiceFindNext (&heService))
1052             {
1053             BOOL fChangedServiceAlerts = FALSE;
1054             LPIDENT lpiService = lpService->GetIdentifier();
1055
1056             LPOBJECTALERTS lpoaService;
1057             if ((lpoaService = Alert_GetObjectAlerts (lpService->GetIdentifier())) != NULL)
1058                {
1059                for (size_t iAlert = 0; iAlert < lpoaService->nAlerts; )
1060                   {
1061                   if (lpoaService->aAlerts[ iAlert ].alert == alertSTOPPED)
1062                      {
1063                      fChangedServiceAlerts = TRUE;
1064                      fChangedServerAlerts = TRUE;
1065                      Alert_Remove (lpService->GetIdentifier(), iAlert);
1066                      }
1067                   else
1068                      ++iAlert;
1069                   }
1070
1071                LPSERVICE_PREF lpcp;
1072                if ((lpcp = (LPSERVICE_PREF)lpService->GetUserParam()) != NULL)
1073                   {
1074                   if (lpcp->fWarnSvcStop && lpsp->fWarnSvcStop)
1075                      {
1076                      SERVICESTATUS ss;
1077                      if (lpService->GetStatus (&ss, TRUE))
1078                         {
1079                         if (ss.state != SERVICESTATE_RUNNING)
1080                            {
1081                            ALERTINFO ai;
1082                            ai.alert = alertSTOPPED;
1083                            memcpy (&ai.aiSTOPPED.stStopped,   &ss.timeLastStop, sizeof(SYSTEMTIME));
1084                            memcpy (&ai.aiSTOPPED.stLastError, &ss.timeLastFail, sizeof(SYSTEMTIME));
1085                            ai.aiSTOPPED.errLastError = ss.dwErrLast;
1086                            Alert_AddPrimary (lpService->GetIdentifier(), &ai);
1087                            fChangedServiceAlerts = TRUE;
1088                            fChangedServerAlerts = TRUE;
1089                            }
1090                         }
1091                      }
1092                   }
1093                }
1094
1095             lpService->Close();
1096             if (fChangedServiceAlerts)
1097                {
1098                PostNotification (evtAlertsChanged, lpiService);
1099                }
1100             }
1101
1102          if (rc && (dwTickNextTestWhenStarted == lpoa->dwTickNextTest))
1103             {
1104             Alert_Scout_SetUpToDate (lpoa);
1105             }
1106
1107          if (fChangedServerAlerts)
1108             {
1109             PostNotification (evtAlertsChanged, lpServer->GetIdentifier());
1110             }
1111
1112          PostNotification (evtScoutEnd, lpServer->GetIdentifier());
1113          }
1114       }
1115
1116    return rc;
1117 }
1118