win95-initial-port-20010430
[openafs.git] / src / WINNT / afsadmsvr / TaAfsAdmSvrGeneral.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 "TaAfsAdmSvrInternal.h"
16
17 extern "C" {
18 #include <afs/afs_AdminErrors.h>
19 } // extern "C"
20
21
22 /*
23  * VARIABLES __________________________________________________________________
24  *
25  */
26
27 #define cminREQ_CLIENT_PING   (csecAFSADMSVR_CLIENT_PING * 2L / 60L)
28
29 #define cREALLOC_CLIENTS          1
30 #define cREALLOC_OPERATIONS      16
31
32 #define cminAUTO_SHUTDOWN         2 // stop if idle for more than 2min
33 #define cminAUTO_SHUTDOWN_SLEEP   1 // test for stop every minute
34
35 typedef struct
36    {
37    TCHAR szName[ cchSTRING ];
38    SOCKADDR_IN ipAddress;
39    DWORD timeLastPing;
40    } CLIENTINFO, *LPCLIENTINFO;
41
42 typedef struct
43    {
44    BOOL fInUse;
45    DWORD idClient;
46    LPASACTION pAction;
47    DWORD dwTickStart;
48    } OPERATION, *LPOPERATION;
49
50 static struct
51    {
52    BOOL fOperational;
53    LPCRITICAL_SECTION pcsAfsAdmSvr;
54
55    LPCLIENTINFO *aClients;
56    size_t cClients;
57    size_t cClientsAllocated;
58
59    LPNOTIFYCALLBACK pNotify;
60
61    BOOL fAutoShutdown;
62    HANDLE hThreadShutdown;
63    DWORD timeLastIdleStart;
64
65    OPERATION *aOperations;
66    size_t cOperations;
67    size_t cOperationsAllocated;
68    DWORD idActionLast;
69
70    DWORD dwScopeMin;
71    } l;
72
73
74 /*
75  * PROTOTYPES _________________________________________________________________
76  *
77  */
78
79 void AfsAdmSvr_TestShutdown (void);
80 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp);
81
82
83 /*
84  * SYNCHRONIZATION ____________________________________________________________
85  *
86  */
87
88 void AfsAdmSvr_Enter (void)
89 {
90    if (!l.pcsAfsAdmSvr)
91       {
92       l.pcsAfsAdmSvr = New (CRITICAL_SECTION);
93       InitializeCriticalSection (l.pcsAfsAdmSvr);
94       }
95    EnterCriticalSection (l.pcsAfsAdmSvr);
96 }
97
98 void AfsAdmSvr_Leave (void)
99 {
100    LeaveCriticalSection (l.pcsAfsAdmSvr);
101 }
102
103
104 /*
105  * CLIENT INFORMATION _________________________________________________________
106  *
107  */
108
109 BOOL AfsAdmSvr_fIsValidClient (DWORD idClient)
110 {
111    BOOL rc = FALSE;
112    AfsAdmSvr_Enter();
113
114    for (size_t iClient = 0; !rc && iClient < l.cClientsAllocated; ++iClient)
115       {
116       if (idClient == (DWORD)(l.aClients[ iClient ]))
117          {
118          if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING > AfsAdmSvr_GetCurrentTime())
119             rc = TRUE;
120          }
121       }
122
123    AfsAdmSvr_Leave();
124    return rc;
125 }
126
127
128 BOOL AfsAdmSvr_AttachClient (LPCTSTR pszName, DWORD *pidClient, ULONG *pStatus)
129 {
130    AfsAdmSvr_Enter();
131    for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
132       {
133       if (!l.aClients[ iClient ])
134          break;
135       }
136    if (!REALLOC (l.aClients, l.cClientsAllocated, 1+iClient, cREALLOC_CLIENTS))
137       {
138       *pidClient = 0;
139       return FALSE;
140       }
141    if ((l.aClients[ iClient ] = New (CLIENTINFO)) == NULL)
142       {
143       *pidClient = 0;
144       return FALSE;
145       }
146    memset (l.aClients[ iClient ], 0x00, sizeof(CLIENTINFO));
147    lstrcpy (l.aClients[ iClient ]->szName, pszName);
148    l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
149    l.cClients ++;
150
151    if (!AfsAdmSvr_ResolveName (&l.aClients[ iClient ]->ipAddress, l.aClients[ iClient ]->szName))
152       memset (&l.aClients[ iClient ]->ipAddress, 0x00, sizeof(SOCKADDR_IN));
153
154    *pidClient = (DWORD)(l.aClients[ iClient ]);
155    AfsAdmSvr_Leave();
156    return TRUE;
157 }
158
159
160 void AfsAdmSvr_DetachClient (DWORD idClient)
161 {
162    AfsAdmSvr_Enter();
163    for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
164       {
165       if (idClient == (DWORD)(l.aClients[ iClient ]))
166          break;
167       }
168    if (iClient < l.cClientsAllocated)
169       {
170       Delete (l.aClients[ iClient ]);
171       l.aClients[ iClient ] = NULL;
172       l.cClients --;
173       }
174    AfsAdmSvr_TestShutdown();
175    AfsAdmSvr_Leave();
176 }
177
178
179 LPCTSTR AfsAdmSvr_GetClientName (DWORD idClient)
180 {
181    static TCHAR szName[ cchSTRING ];
182    LPCTSTR pszName = NULL;
183    AfsAdmSvr_Enter();
184
185    for (size_t iClient = 0; !pszName && iClient < l.cClientsAllocated; ++iClient)
186       {
187       if (idClient == (DWORD)(l.aClients[ iClient ]))
188          {
189          lstrcpy (szName, l.aClients[ iClient ]->szName);
190          pszName = szName;
191          }
192       }
193
194    AfsAdmSvr_Leave();
195    return pszName;
196 }
197
198
199 LPSOCKADDR_IN AfsAdmSvr_GetClientAddress (DWORD idClient)
200 {
201    static SOCKADDR_IN ipAddress;
202    LPSOCKADDR_IN pAddress = NULL;
203    AfsAdmSvr_Enter();
204
205    for (size_t iClient = 0; !pAddress && iClient < l.cClientsAllocated; ++iClient)
206       {
207       if (idClient == (DWORD)(l.aClients[ iClient ]))
208          {
209          memcpy (&ipAddress, &l.aClients[ iClient ]->ipAddress, sizeof(SOCKADDR_IN));
210          pAddress = &ipAddress;
211          }
212       }
213
214    AfsAdmSvr_Leave();
215    return pAddress;
216 }
217
218
219 void AfsAdmSvr_PingClient (DWORD idClient)
220 {
221    AfsAdmSvr_Enter();
222
223    for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
224       {
225       if (idClient == (DWORD)(l.aClients[ iClient ]))
226          {
227          l.aClients[ iClient ]->timeLastPing = AfsAdmSvr_GetCurrentTime();
228          }
229       }
230
231    AfsAdmSvr_Leave();
232 }
233
234
235 DWORD AfsAdmSvr_GetCurrentTime (void) // returns counter in ~minute increments
236 {
237    static WORD wMonthish = 0;  // One "Monthish" is 49.7 days
238    static WORD wTickLast = 0;
239    DWORD dwTick = GetTickCount();
240    WORD wTickNow = HIWORD(dwTick);
241    if (wTickNow < wTickLast)  // wrapped over a Monthish?
242       ++wMonthish;
243    wTickLast = wTickNow;
244    return MAKELONG(wTickNow,wMonthish);
245 }
246
247
248 /*
249  * STARTUP/SHUTDOWN ___________________________________________________________
250  *
251  */
252
253 void AfsAdmSvr_Startup (void)
254 {
255    l.pNotify = New2 (NOTIFYCALLBACK,(AfsAdmSvr_NotifyCallback, 0));
256    l.fOperational = FALSE;
257
258    ULONG status;
259    if (AfsClass_Initialize (&status))
260       l.fOperational = TRUE;
261    else
262       {
263       Print (dlERROR, TEXT("Could not initialize AfsClass (fatal error 0x%08lX)"), status);
264       Print (dlERROR, TEXT("Remaining active to tell potential clients about the problem"));
265       }
266
267    if (!l.hThreadShutdown)
268       {
269       DWORD dwThreadID;
270       l.hThreadShutdown = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)AfsAdmSvr_AutoShutdownThread, (LPVOID)0, 0, &dwThreadID);
271       }
272 }
273
274
275 void AfsAdmSvr_Shutdown (void)
276 {
277    Delete (l.pNotify);
278    l.pNotify = NULL;
279    l.fOperational = FALSE;
280 }
281
282
283 /*
284  * GENERAL ____________________________________________________________________
285  *
286  */
287
288 BOOL FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
289 {
290    if (pStatus)
291       *pStatus = status;
292    if (iOp != (size_t)-2)
293       AfsAdmSvr_EndOperation (iOp);
294    return FALSE;
295 }
296
297 BOOL Leave_FALSE_ (ULONG status, ULONG *pStatus, size_t iOp)
298 {
299    AfsAdmSvr_Leave();
300    if (pStatus)
301       *pStatus = status;
302    if (iOp != (size_t)-2)
303       AfsAdmSvr_EndOperation (iOp);
304    return FALSE;
305 }
306
307 BOOL TRUE_ (ULONG *pStatus, size_t iOp)
308 {
309    if (pStatus)
310       *pStatus = 0;
311    if (iOp != (size_t)-2)
312       AfsAdmSvr_EndOperation (iOp);
313    return TRUE;
314 }
315
316 BOOL Leave_TRUE_ (ULONG *pStatus, size_t iOp)
317 {
318    AfsAdmSvr_Leave();
319    if (pStatus)
320       *pStatus = 0;
321    if (iOp != (size_t)-2)
322       AfsAdmSvr_EndOperation (iOp);
323    return TRUE;
324 }
325
326 IDENTTYPE GetAsidType (ASID idObject)
327 {
328    IDENTTYPE iType;
329    try {
330       iType = ((LPIDENT)idObject)->GetType();
331    } catch(...) {
332       iType = itUNUSED;
333    }
334    return iType;
335 }
336
337
338 BOOL AfsAdmSvr_ResolveName (LPSOCKADDR_IN pAddress, LPTSTR pszName)
339 {
340    if ((pszName[0] >= TEXT('0')) && (pszName[0] <= TEXT('9')))
341       {
342       int ipAddress;
343       if ((ipAddress = inet_addr (pszName)) == INADDR_NONE)
344          return FALSE;
345
346       memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
347       pAddress->sin_family = AF_INET;
348       pAddress->sin_addr.s_addr = ipAddress;
349
350       HOSTENT *pEntry;
351       if ((pEntry = gethostbyaddr ((char*)&ipAddress, sizeof(ipAddress), AF_INET)) != NULL)
352          lstrcpy (pszName, pEntry->h_name);
353       }
354    else // (!isdigit(szServer[0]))
355       {
356       HOSTENT *pEntry;
357       if ((pEntry = gethostbyname (pszName)) == NULL)
358          return FALSE;
359
360       memset (pAddress, 0x00, sizeof(SOCKADDR_IN));
361       pAddress->sin_family = AF_INET;
362       pAddress->sin_addr.s_addr = *(int *)pEntry->h_addr;
363
364       lstrcpy (pszName, pEntry->h_name);
365       }
366
367    return TRUE;
368 }
369
370
371 /*
372  * AUTO-SHUTDOWN ______________________________________________________________
373  *
374  */
375
376 DWORD WINAPI AfsAdmSvr_AutoShutdownThread (LPVOID lp)
377 {
378    for (;;)
379       {
380       AfsAdmSvr_Enter();
381
382       BOOL fShutdown = l.fAutoShutdown;
383
384       // If there are any clients connected, forcably disconnect any
385       // that haven't pinged us for too long
386       //
387       for (size_t iClient = 0; iClient < l.cClientsAllocated; ++iClient)
388          {
389          if (!l.aClients[ iClient ])
390             continue;
391          if (l.aClients[ iClient ]->timeLastPing + cminREQ_CLIENT_PING <= AfsAdmSvr_GetCurrentTime())
392             {
393             Print (dlCONNECTION, "Client 0x%08lX idle for too long; detaching", l.aClients[ iClient ]);
394             AfsAdmSvr_DetachClient ((DWORD)l.aClients[ iClient ]);
395             }
396          }
397
398       // If any operations are in progress, we can't shutdown.
399       //
400       if (l.cOperations)
401          fShutdown = FALSE;
402
403       // If any clients are still connected, we can't shutdown.
404       //
405       if (l.cClients)
406          fShutdown = FALSE;
407
408       // If we haven't been idle long enough, we can't shutdown
409       //
410       if (!l.timeLastIdleStart)
411          fShutdown = FALSE;
412       else if (l.timeLastIdleStart + cminAUTO_SHUTDOWN > AfsAdmSvr_GetCurrentTime())
413          fShutdown = FALSE;
414
415       // That's it; can we stop now?
416       //
417       if (fShutdown)
418          {
419          Print ("Idle for too long; shutting down.");
420          RpcMgmtStopServerListening (NULL);
421          AfsAdmSvr_StopCallbackManagers();
422          }
423
424       AfsAdmSvr_Leave();
425
426       if (fShutdown)
427          break;
428
429       Sleep (cminAUTO_SHUTDOWN_SLEEP * 60L * 1000L);
430       }
431
432    return 0;
433 }
434
435
436
437 void AfsAdmSvr_EnableAutoShutdown (BOOL fEnable)
438 {
439    AfsAdmSvr_Enter();
440
441    l.fAutoShutdown = fEnable;
442
443    if (fEnable)
444       Print (dlDETAIL, TEXT("Auto-shutdown enabled, trigger = %lu minutes idle time"), cminAUTO_SHUTDOWN);
445    else
446       Print (dlDETAIL, TEXT("Auto-shutdown on idle disabled"));
447
448    AfsAdmSvr_Leave();
449 }
450
451
452 void AfsAdmSvr_TestShutdown (void)
453 {
454    if (!l.cOperations && !l.cClients)
455       {
456       l.timeLastIdleStart = AfsAdmSvr_GetCurrentTime();
457       }
458 }
459
460
461 size_t AfsAdmSvr_BeginOperation (DWORD idClient, LPASACTION pAction)
462 {
463    AfsAdmSvr_Enter();
464
465    ++l.cOperations;
466
467    for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
468       {
469       if (!l.aOperations[ iOp ].fInUse)
470          break;
471       }
472    if (!REALLOC (l.aOperations, l.cOperationsAllocated, 1+iOp, cREALLOC_OPERATIONS))
473       {
474       AfsAdmSvr_Leave();
475       return (size_t)(-1);
476       }
477
478    l.aOperations[ iOp ].idClient = idClient;
479    l.aOperations[ iOp ].pAction = NULL;
480    l.aOperations[ iOp ].fInUse = TRUE;
481
482    if (pAction)
483       {
484       l.aOperations[ iOp ].pAction = New (ASACTION);
485       memcpy (l.aOperations[ iOp ].pAction, pAction, sizeof(ASACTION));
486       l.aOperations[ iOp ].pAction->idAction = ++l.idActionLast;
487       l.aOperations[ iOp ].pAction->idClient = idClient;
488       l.aOperations[ iOp ].pAction->csecActive = 0;
489
490       TCHAR szDesc[256];
491       switch (l.aOperations[ iOp ].pAction->Action)
492          {
493          case ACTION_REFRESH:
494             wsprintf (szDesc, TEXT("Refresh (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
495             break;
496          case ACTION_SCOUT:
497             wsprintf (szDesc, TEXT("Scout (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
498             break;
499          case ACTION_USER_CHANGE:
500             wsprintf (szDesc, TEXT("ChangeUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Change.idUser);
501             break;
502          case ACTION_USER_PW_CHANGE:
503             wsprintf (szDesc, TEXT("SetUserPassword (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Pw_Change.idUser);
504             break;
505          case ACTION_USER_UNLOCK:
506             wsprintf (szDesc, TEXT("UnlockUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Unlock.idUser);
507             break;
508          case ACTION_USER_CREATE:
509             wsprintf (szDesc, TEXT("CreateUser (user=%s)"), l.aOperations[ iOp ].pAction->u.User_Create.szUser);
510             break;
511          case ACTION_USER_DELETE:
512             wsprintf (szDesc, TEXT("CreateUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Delete.idUser);
513             break;
514          case ACTION_GROUP_CHANGE:
515             wsprintf (szDesc, TEXT("ChangeGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Change.idGroup);
516             break;
517          case ACTION_GROUP_MEMBER_ADD:
518             wsprintf (szDesc, TEXT("AddGroupMember (group=0x%08lX, user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Member_Add.idGroup, l.aOperations[ iOp ].pAction->u.Group_Member_Add.idUser);
519             break;
520          case ACTION_GROUP_MEMBER_REMOVE:
521             wsprintf (szDesc, TEXT("RemoveGroupMember (group=0x%08lX, user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Member_Remove.idGroup, l.aOperations[ iOp ].pAction->u.Group_Member_Remove.idUser);
522             break;
523          case ACTION_GROUP_RENAME:
524             wsprintf (szDesc, TEXT("RenameGroup (group=0x%08lX, new name=%s)"), l.aOperations[ iOp ].pAction->u.Group_Rename.idGroup, l.aOperations[ iOp ].pAction->u.Group_Rename.szNewName);
525             break;
526          case ACTION_GROUP_DELETE:
527             wsprintf (szDesc, TEXT("CreateGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Delete.idGroup);
528             break;
529          case ACTION_CELL_CHANGE:
530             wsprintf (szDesc, TEXT("ChangeCell (cell=0x%08lX)"), l.aOperations[ iOp ].pAction->idCell);
531             break;
532          default:
533             wsprintf (szDesc, TEXT("Unknown Action (#%lu)"), l.aOperations[ iOp ].pAction->Action);
534             break;
535          }
536       Print (dlOPERATION, TEXT("Starting action 0x%08lX: %s"), l.aOperations[ iOp ].pAction->idAction, szDesc);
537
538       AfsAdmSvr_PostCallback (cbtACTION, FALSE, l.aOperations[ iOp ].pAction);
539       }
540
541    l.aOperations[ iOp ].dwTickStart = GetTickCount();
542    AfsAdmSvr_Leave();
543    return iOp;
544 }
545
546
547 void AfsAdmSvr_EndOperation (size_t iOp)
548 {
549    AfsAdmSvr_Enter();
550
551    if ((iOp != (size_t)-1) && (iOp < l.cOperationsAllocated) && (l.aOperations[ iOp ].fInUse))
552       {
553       if (l.aOperations[ iOp ].pAction)
554          {
555          Print (dlOPERATION, TEXT("Ending action 0x%08lX"), l.aOperations[ iOp ].pAction->idAction);
556          AfsAdmSvr_PostCallback (cbtACTION, TRUE, l.aOperations[ iOp ].pAction);
557          Delete (l.aOperations[ iOp ].pAction);
558          }
559       memset (&l.aOperations[ iOp ], 0x00, sizeof(l.aOperations[ iOp ]));
560       l.cOperations --;
561       }
562
563    AfsAdmSvr_TestShutdown();
564    AfsAdmSvr_Leave();
565 }
566
567
568 BOOL AfsAdmSvr_GetOperation (DWORD idAction, LPASACTION pAction)
569 {
570    AfsAdmSvr_Enter();
571
572    for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
573       {
574       if (!l.aOperations[ iOp ].fInUse)
575          continue;
576       if (!l.aOperations[ iOp ].pAction)
577          continue;
578       if (l.aOperations[ iOp ].pAction->idAction != idAction)
579          continue;
580
581       memcpy (pAction, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
582       pAction->csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
583       AfsAdmSvr_Leave();
584       return TRUE;
585       }
586
587    AfsAdmSvr_Leave();
588    return FALSE;
589 }
590
591
592 LPASACTIONLIST AfsAdmSvr_GetOperations (DWORD idClientSearch, ASID idCellSearch)
593 {
594    LPASACTIONLIST pList = AfsAdmSvr_CreateActionList();
595    AfsAdmSvr_Enter();
596
597    for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
598       {
599       if (!l.aOperations[ iOp ].fInUse)
600          continue;
601       if (!l.aOperations[ iOp ].pAction)
602          continue;
603       if (idClientSearch && (idClientSearch != l.aOperations[ iOp ].pAction->idClient))
604          continue;
605       if (idCellSearch && (idCellSearch != l.aOperations[ iOp ].pAction->idCell))
606          continue;
607
608       ASACTION Action;
609       memcpy (&Action, l.aOperations[ iOp ].pAction, sizeof(ASACTION));
610       Action.csecActive = (GetTickCount() - l.aOperations[ iOp ].dwTickStart) / 1000;
611       if (!AfsAdmSvr_AddToActionList (&pList, &Action))
612          {
613          AfsAdmSvr_FreeActionList (&pList);
614          break;
615          }
616       }
617
618    AfsAdmSvr_Leave();
619    return pList;
620 }
621
622
623 void AfsAdmSvr_Action_StartRefresh (ASID idScope)
624 {
625    switch (GetAsidType (idScope))
626       {
627       case itCELL:
628          AfsAdmSvr_MarkRefreshThread (idScope);
629          // fall through
630
631       case itSERVER:
632          ASACTION Action;
633          memset (&Action, 0x00, sizeof(Action));
634          Action.Action = ACTION_REFRESH;
635          Action.idCell = (ASID)( ((LPIDENT)idScope)->GetCell() );
636          Action.u.Refresh.idScope = idScope;
637          (void)AfsAdmSvr_BeginOperation (0, &Action);
638          break;
639
640       default:
641          // Don't bother listing status-refreshes as ongoing operations
642          // for any granularity smaller than the server; they'll occur
643          // really frequently, and finish really quickly.
644          break;
645       }
646 }
647
648
649 void AfsAdmSvr_Action_StopRefresh (ASID idScope)
650 {
651    AfsAdmSvr_Enter();
652
653    for (size_t iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
654       {
655       if (!l.aOperations[ iOp ].fInUse)
656          continue;
657       if (!l.aOperations[ iOp ].pAction)
658          continue;
659       if (l.aOperations[ iOp ].pAction->Action != ACTION_REFRESH)
660          continue;
661       if (l.aOperations[ iOp ].pAction->u.Refresh.idScope != idScope)
662          continue;
663
664       AfsAdmSvr_EndOperation (iOp);
665       break;
666       }
667
668    if (GetAsidType (idScope) == itCELL)
669       {
670       AfsAdmSvr_MarkRefreshThread (idScope);
671       }
672
673    AfsAdmSvr_Leave();
674 }
675
676
677 DWORD WINAPI AfsAdmSvr_AutoOpen_ThreadProc (PVOID lp)
678 {
679    DWORD dwScope = (DWORD)lp;
680    ULONG status;
681
682    if (!l.fOperational)
683       return 0;
684
685    // First we'll have to find out which cell to open
686    //
687    TCHAR szCell[ cchNAME ];
688    if (!CELL::GetDefaultCell (szCell, &status))
689       {
690       Print (dlERROR, TEXT("CELL::GetDefaultCell failed; error 0x%08lX"), status);
691       }
692    else
693       {
694       // Then try to actually open the cell
695       //
696       Print (dlSTANDARD, TEXT("Auto-opening cell %s; scope=%s"), szCell, (dwScope == (AFSADMSVR_SCOPE_VOLUMES | AFSADMSVR_SCOPE_USERS)) ? TEXT("full") : (dwScope == AFSADMSVR_SCOPE_VOLUMES) ? TEXT("volumes") : TEXT("users"));
697
698       LPIDENT lpiCell;
699       if ((lpiCell = CELL::OpenCell ((LPTSTR)szCell, &status)) == NULL)
700          {
701          Print (dlERROR, TEXT("Auto-open of cell %s failed; error 0x%08lX"), szCell, status);
702          }
703       else
704          {
705          LPCELL lpCell;
706          if ((lpCell = lpiCell->OpenCell (&status)) == NULL)
707             {
708             Print (dlERROR, TEXT("Auto-open: OpenCell failed; error 0x%08lX"), status);
709             }
710          else
711             {
712             AfsAdmSvr_AddToMinScope (dwScope);
713             if (!lpCell->RefreshAll (&status))
714                Print (dlERROR, TEXT("Auto-open: RefreshCell failed; error 0x%08lX"), status);
715             else
716                Print (dlSTANDARD, TEXT("Auto-open of cell %s successful"), szCell);
717             lpCell->Close();
718
719             // We intentionally do not call CELL::CloseCell() here--as would
720             // ordinarily be necessary to balance our CELL::OpenCell() call
721             // above--because we never want to close our cache for this cell.
722             // The point of calling AutoOpen() up front is to keep an admin
723             // server alive and ready for use on a particular cell--calling
724             // CELL::CloseCell() here negates that purpose.
725
726             }
727          }
728       }
729
730    return 0;
731 }
732
733
734 void AfsAdmSvr_AddToMinScope (DWORD dwScope)
735 {
736    l.dwScopeMin |= dwScope;
737    AfsClass_SpecifyRefreshDomain (l.dwScopeMin);
738 }
739
740
741 void AfsAdmSvr_SetMinScope (DWORD dwScope)
742 {
743    l.dwScopeMin = dwScope;
744 }
745
746
747 DWORD AfsAdmSvr_GetMinScope (void)
748 {
749    return l.dwScopeMin;
750 }
751