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