winnt-dont-display-ibm-legal-message-20040326
[openafs.git] / src / WINNT / afsd / afsd_service.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <string.h>
15 #include <setjmp.h>
16 #include "afsd.h"
17 #include "afsd_init.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <winsock2.h>
21
22 #include <osi.h>
23
24 #ifdef DEBUG
25 //#define NOTSERVICE
26 #endif
27 #ifdef _DEBUG
28 #include <crtdbg.h>
29 #endif
30
31 /*
32 // The following is defined if you want to receive Power notifications,
33 // including Hibernation, and also subsequent flushing of AFS volumes
34 //
35 #define REGISTER_POWER_NOTIFICATIONS
36 //
37 // Check
38 */
39 #include "afsd_flushvol.h"
40
41 extern void afsi_log(char *pattern, ...);
42
43 HANDLE hAFSDMainThread = NULL;
44
45 HANDLE WaitToTerminate;
46
47 int GlobalStatus;
48
49 #ifdef JUMP
50 unsigned int MainThreadId;
51 jmp_buf notifier_jmp;
52 #endif /* JUMP */
53
54 extern int traceOnPanic;
55 extern HANDLE afsi_file;
56
57 /*
58  * Notifier function for use by osi_panic
59  */
60 static void afsd_notifier(char *msgp, char *filep, long line)
61 {
62         char tbuffer[100];
63         char *ptbuf[1];
64         HANDLE h;
65
66         if (filep)
67                 sprintf(tbuffer, "Error at file %s, line %d: %s",
68                         filep, line, msgp);
69         else
70                 sprintf(tbuffer, "Error at unknown location: %s", msgp);
71
72         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
73         ptbuf[0] = tbuffer;
74         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
75         DeregisterEventSource(h);
76
77         GlobalStatus = line;
78
79         osi_LogEnable(afsd_logp);
80
81         afsd_ForceTrace(TRUE);
82
83     afsi_log("--- begin dump ---");
84     cm_DumpSCache(afsi_file, "a");
85 #ifdef keisa
86     cm_dnlcDump(afsi_file, "a");
87 #endif
88     cm_DumpBufHashTable(afsi_file, "a");
89     smb_DumpVCP(afsi_file, "a");                        
90     afsi_log("--- end   dump ---");
91     
92     DebugBreak();       
93
94         SetEvent(WaitToTerminate);
95
96 #ifdef JUMP
97         if (GetCurrentThreadId() == MainThreadId)
98                 longjmp(notifier_jmp, 1);
99         else
100 #endif /* JUMP */
101                 ExitThread(1);
102 }
103
104 /*
105  * For use miscellaneously in smb.c; need to do better
106  */
107 static int DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
108 {
109         return 0;
110 }
111
112 static SERVICE_STATUS           ServiceStatus;
113 static SERVICE_STATUS_HANDLE    StatusHandle;
114
115 DWORD
116 afsd_ServiceFlushVolume(DWORD dwlpEventData)
117 {
118     DWORD   dwRet = ERROR_NETWORK_BUSY; /* or NO_ERROR */
119
120     /*
121     **  If UI bit is not set, user interaction is not possible
122     **      BUT, since we are a NON-interactive service, and therefore
123     **  have NO user I/O, it doesn't much matter.
124     **  This benign code left here as example of how to find this out
125     */
126     BOOL bUI = (dwlpEventData & 1);
127
128     /* flush volume */
129     if ( PowerNotificationThreadNotify() )
130     {
131         dwRet = NO_ERROR;
132     }
133
134     else
135     {
136         /* flush was unsuccessful, or timeout - deny shutdown */
137         dwRet = ERROR_NETWORK_BUSY;
138     }
139
140     /*      to deny hibernate, simply return
141     //      any value besides NO_ERROR.
142     //      For example:
143     //      dwRet = ERROR_NETWORK_BUSY;
144     */
145
146     return dwRet;
147 }
148
149 /*
150 **    Extended ServiceControlHandler that provides Event types
151 **    for monitoring Power events, for example.
152 */
153 DWORD
154 afsd_ServiceControlHandlerEx(
155               DWORD  ctrlCode,
156               DWORD  dwEventType,
157               LPVOID lpEventData,
158               LPVOID lpContext
159               )
160 {
161         HKEY parmKey;
162         DWORD dummyLen, doTrace;
163         long code;
164     DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
165
166         switch (ctrlCode) 
167     {
168     case SERVICE_CONTROL_STOP:
169         /* Shutdown RPC */
170         RpcMgmtStopServerListening(NULL);
171
172         /* Force trace if requested */
173         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
174                             AFSConfigKeyName,
175                             0, KEY_QUERY_VALUE, &parmKey);
176         if (code != ERROR_SUCCESS)
177             goto doneTrace;
178
179         dummyLen = sizeof(doTrace);
180         code = RegQueryValueEx(parmKey, "TraceOnShutdown",
181                                NULL, NULL,
182                                (BYTE *) &doTrace, &dummyLen);
183         RegCloseKey (parmKey);
184         if (code != ERROR_SUCCESS)
185             doTrace = 0;
186         if (doTrace)
187             afsd_ForceTrace(FALSE);
188
189       doneTrace:
190         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
191         ServiceStatus.dwWin32ExitCode = NO_ERROR;
192         ServiceStatus.dwCheckPoint = 1;
193         ServiceStatus.dwWaitHint = 10000;
194         ServiceStatus.dwControlsAccepted = 0;
195         SetServiceStatus(StatusHandle, &ServiceStatus);
196         SetEvent(WaitToTerminate);
197         dwRet = NO_ERROR;
198         break;
199
200     case SERVICE_CONTROL_INTERROGATE:
201         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
202         ServiceStatus.dwWin32ExitCode = NO_ERROR;
203         ServiceStatus.dwCheckPoint = 0;
204         ServiceStatus.dwWaitHint = 0;
205         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
206         SetServiceStatus(StatusHandle, &ServiceStatus);
207         dwRet = NO_ERROR;
208         break;
209
210                 /* XXX handle system shutdown */
211                 /* XXX handle pause & continue */
212                 case SERVICE_CONTROL_POWEREVENT:                                              
213                 {                                                                                     
214                         /*                                                                                
215             **  dwEventType of this notification == WPARAM of WM_POWERBROADCAST               
216                         **      Return NO_ERROR == return TRUE for that message, i.e. accept request          
217                         **      Return any error code to deny request,                                        
218                         **      i.e. as if returning BROADCAST_QUERY_DENY                                     
219                         */                                                                                
220                         switch((int) dwEventType)                                                         
221             {                                                                               
222                         case PBT_APMQUERYSUSPEND:                                                         
223                         case PBT_APMQUERYSTANDBY:                                                         
224                                                                                             
225 #ifdef  REGISTER_POWER_NOTIFICATIONS                                                                  
226                                 /* handle event */                                                            
227                                 dwRet = afsd_ServiceFlushVolume((DWORD) lpEventData);                         
228 #else                                                                                       
229                                 dwRet = NO_ERROR;                                                             
230 #endif                                                                                      
231                                 break;                                                                        
232                                                                                                                           
233             /* allow remaining case PBT_WhatEver */                                           
234                         case PBT_APMSUSPEND:                                                              
235                         case PBT_APMSTANDBY:                                                              
236                         case PBT_APMRESUMECRITICAL:                                                       
237                         case PBT_APMRESUMESUSPEND:                                                        
238                         case PBT_APMRESUMESTANDBY:                                                        
239                         case PBT_APMBATTERYLOW:                                                           
240                         case PBT_APMPOWERSTATUSCHANGE:                                                    
241                         case PBT_APMOEMEVENT:                                                             
242                         case PBT_APMRESUMEAUTOMATIC:                                                      
243                         default:                                                                          
244                                 dwRet = NO_ERROR;                                                             
245             }
246         }
247     }           /* end switch(ctrlCode) */                                                        
248         return dwRet;   
249 }
250
251 #if 1
252 /* This code was moved to Drivemap.cpp*/
253 /* Mount a drive into AFS if the user wants us to */
254 /* DEE Could check first if we are run as SYSTEM */
255 void CheckMountDrive()
256 {
257         char szAfsPath[_MAX_PATH];
258         char szDriveToMapTo[5];
259         DWORD dwResult;
260         char szKeyName[256];
261         HKEY hKey;
262         DWORD dwIndex = 0;
263         DWORD dwDriveSize;
264         DWORD dwSubMountSize;
265         char szSubMount[256];
266         DWORD dwType;
267
268         sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
269
270         dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
271         if (dwResult != ERROR_SUCCESS)
272                 return;
273
274         while (1) {
275                 dwDriveSize = sizeof(szDriveToMapTo);
276                 dwSubMountSize = sizeof(szSubMount);
277                 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
278                 if (dwResult != ERROR_MORE_DATA) {
279                         if (dwResult != ERROR_SUCCESS) {
280                                 if (dwResult != ERROR_NO_MORE_ITEMS)
281                                         afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
282                                 break;
283                         }
284                 }
285                 
286 #if 0
287                 sprintf(szAfsPath, "\\Device\\LanmanRedirector\\%s\\%s-AFS\\%s", szDriveToMapTo, cm_HostName, szSubMount);
288         
289                 dwResult = DefineDosDevice(DDD_RAW_TARGET_PATH, szDriveToMapTo, szAfsPath);
290 #else
291                 {
292                     NETRESOURCE nr;
293                     memset (&nr, 0x00, sizeof(NETRESOURCE));
294  
295                     sprintf(szAfsPath,"\\\\%s-AFS\\%s",cm_HostName,szSubMount);
296                     
297                     nr.dwScope = RESOURCE_GLOBALNET;
298                     nr.dwType=RESOURCETYPE_DISK;
299                     nr.lpLocalName=szDriveToMapTo;
300                     nr.lpRemoteName=szAfsPath;
301                     nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
302                     nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
303
304                     dwResult = WNetAddConnection2(&nr,NULL,NULL,FALSE);
305                 }
306 #endif
307                 afsi_log("GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
308         }        
309
310         RegCloseKey(hKey);
311 }
312 #endif
313
314 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
315 #define AFSD_INIT_HOOK "AfsdInitHook"
316 #define AFSD_HOOK_DLL  "afsdhook.dll"
317
318 void afsd_Main(DWORD argc, LPTSTR *argv)
319 {
320         long code;
321         char *reason;
322 #ifdef JUMP
323         int jmpret;
324 #endif /* JUMP */
325     HANDLE hInitHookDll;
326     AfsdInitHook initHook;
327
328 #ifdef _DEBUG
329     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
330                    _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
331 #endif 
332
333         osi_InitPanic(afsd_notifier);
334         osi_InitTraceOption();
335
336         GlobalStatus = 0;
337
338         afsi_start();
339
340         WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, TEXT("afsd_service_WaitToTerminate"));
341     if ( GetLastError() == ERROR_ALREADY_EXISTS )
342         afsi_log("Event Object Already Exists: %s", TEXT("afsd_service_WaitToTerminate"));
343
344 #ifndef NOTSERVICE
345         StatusHandle = RegisterServiceCtrlHandlerEx(AFS_DAEMON_SERVICE_NAME,
346                         (LPHANDLER_FUNCTION_EX) afsd_ServiceControlHandlerEx,
347                                                  NULL /* user context */
348                                                  );
349
350         ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
351         ServiceStatus.dwServiceSpecificExitCode = 0;
352         ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
353         ServiceStatus.dwWin32ExitCode = NO_ERROR;
354         ServiceStatus.dwCheckPoint = 1;
355         ServiceStatus.dwWaitHint = 30000;
356     /* accept Power Events */
357         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
358         SetServiceStatus(StatusHandle, &ServiceStatus);
359 #endif
360
361     {       
362     HANDLE h; char *ptbuf[1];
363     h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
364     ptbuf[0] = "AFS start pending";
365     ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
366     DeregisterEventSource(h);
367     }
368
369 #ifdef REGISTER_POWER_NOTIFICATIONS
370     /* create thread used to flush cache */
371     PowerNotificationThreadCreate();
372 #endif
373
374     /* allow an exit to be called prior to any initialization */
375     hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
376     if (hInitHookDll)
377     {
378         BOOL hookRc = FALSE;
379         initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
380         if (initHook)
381         {
382             hookRc = initHook();
383         }
384         FreeLibrary(hInitHookDll);
385                
386         if (hookRc == FALSE)
387         {
388             ServiceStatus.dwCurrentState = SERVICE_STOPPED;
389             ServiceStatus.dwWin32ExitCode = NO_ERROR;
390             ServiceStatus.dwCheckPoint = 0;
391             ServiceStatus.dwWaitHint = 0;
392             ServiceStatus.dwControlsAccepted = 0;
393             SetServiceStatus(StatusHandle, &ServiceStatus);
394                        
395             /* exit if initialization failed */
396             return;
397         }
398         else
399         {
400             /* allow another 15 seconds to start */
401             ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
402             ServiceStatus.dwServiceSpecificExitCode = 0;
403             ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
404             ServiceStatus.dwWin32ExitCode = NO_ERROR;
405             ServiceStatus.dwCheckPoint = 2;
406             ServiceStatus.dwWaitHint = 20000;
407             /* accept Power Events */
408             ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT;
409             SetServiceStatus(StatusHandle, &ServiceStatus);
410         }
411     }
412
413 #ifdef JUMP
414     MainThreadId = GetCurrentThreadId();
415         jmpret = setjmp(notifier_jmp);
416
417         if (jmpret == 0) 
418 #endif /* JUMP */
419     {
420                 code = afsd_InitCM(&reason);
421                 if (code != 0)
422                         osi_panic(reason, __FILE__, __LINE__);
423
424 #ifndef NOTSERVICE
425         ServiceStatus.dwCheckPoint++;
426         ServiceStatus.dwWaitHint -= 5000;
427         SetServiceStatus(StatusHandle, &ServiceStatus);
428 #endif
429                 code = afsd_InitDaemons(&reason);
430                 if (code != 0)
431                         osi_panic(reason, __FILE__, __LINE__);
432
433 #ifndef NOTSERVICE
434         ServiceStatus.dwCheckPoint++;
435         ServiceStatus.dwWaitHint -= 5000;
436         SetServiceStatus(StatusHandle, &ServiceStatus);
437 #endif
438                 code = afsd_InitSMB(&reason, DummyMessageBox);
439                 if (code != 0)
440                         osi_panic(reason, __FILE__, __LINE__);
441
442 #ifndef NOTSERVICE
443                 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
444                 ServiceStatus.dwWin32ExitCode = NO_ERROR;
445                 ServiceStatus.dwCheckPoint = 0;
446                 ServiceStatus.dwWaitHint = 0;
447
448         /* accept Power events */
449                 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
450                 SetServiceStatus(StatusHandle, &ServiceStatus);
451 #endif
452         {
453             HANDLE h; char *ptbuf[1];
454                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
455                 ptbuf[0] = "AFS running";
456                 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
457                 DeregisterEventSource(h);
458         }
459         }
460
461     /* Check if we should mount a drive into AFS */
462     CheckMountDrive();
463
464         WaitForSingleObject(WaitToTerminate, INFINITE);
465
466     {   
467     HANDLE h; char *ptbuf[1];
468         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
469         ptbuf[0] = "AFS quitting";
470         ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
471                 0, 0, NULL, 1, 0, ptbuf, NULL);
472     DeregisterEventSource(h);
473     }
474
475 #ifdef  REGISTER_POWER_NOTIFICATIONS
476         /* terminate thread used to flush cache */
477         PowerNotificationThreadExit();
478 #endif
479
480     /* Remove the ExceptionFilter */
481     SetUnhandledExceptionFilter(NULL);
482
483     if ( hInitHookDll )
484         FreeLibrary(hInitHookDll);
485
486     ServiceStatus.dwCurrentState = SERVICE_STOPPED;
487         ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
488         ServiceStatus.dwCheckPoint = 0;
489         ServiceStatus.dwWaitHint = 0;
490         ServiceStatus.dwControlsAccepted = 0;
491         SetServiceStatus(StatusHandle, &ServiceStatus);
492 }
493
494 DWORD __stdcall afsdMain_thread(void* notUsed)
495 {
496         afsd_Main(0, (LPTSTR*)NULL);
497     exit(0);
498 }
499
500 int
501 main(void)
502 {
503         static SERVICE_TABLE_ENTRY dispatchTable[] = {
504                 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
505                 {NULL, NULL}
506         };
507
508         if (!StartServiceCtrlDispatcher(dispatchTable))
509     {
510         LONG status = GetLastError();
511             if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
512         {
513             DWORD tid;
514             hAFSDMainThread = CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
515                 
516             printf("Hit <Enter> to terminate OpenAFS Client Service\n");
517             getchar();              
518             SetEvent(WaitToTerminate);
519         }
520     }
521
522     if ( hAFSDMainThread ) {
523         WaitForSingleObject( hAFSDMainThread, INFINITE );
524         CloseHandle( hAFSDMainThread );
525     }
526     return(0);
527 }