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