avoid-long-windows-shell-timeouts-20040105
[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 extern void afsi_log(char *pattern, ...);
32
33 HANDLE WaitToTerminate;
34
35 int GlobalStatus;
36
37 unsigned int MainThreadId;
38 jmp_buf notifier_jmp;
39
40 extern int traceOnPanic;
41
42 /*
43  * Notifier function for use by osi_panic
44  */
45 static void afsd_notifier(char *msgp, char *filep, long line)
46 {
47         char tbuffer[100];
48         char *ptbuf[1];
49         HANDLE h;
50
51         if (filep)
52                 sprintf(tbuffer, "Error at file %s, line %d: %s",
53                         filep, line, msgp);
54         else
55                 sprintf(tbuffer, "Error at unknown location: %s", msgp);
56
57         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
58         ptbuf[0] = tbuffer;
59         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, line, NULL, 1, 0, ptbuf, NULL);
60         DeregisterEventSource(h);
61
62         GlobalStatus = line;
63
64         osi_LogEnable(afsd_logp);
65
66         afsd_ForceTrace(TRUE);
67
68         if (traceOnPanic) {
69                 _asm int 3h;
70         }
71
72         SetEvent(WaitToTerminate);
73
74         if (GetCurrentThreadId() == MainThreadId)
75                 longjmp(notifier_jmp, 1);
76         else
77                 ExitThread(1);
78 }
79
80 /*
81  * For use miscellaneously in smb.c; need to do better
82  */
83 static int DummyMessageBox(HWND h, LPCTSTR l1, LPCTSTR l2, UINT ui)
84 {
85         return 0;
86 }
87
88 static SERVICE_STATUS           ServiceStatus;
89 static SERVICE_STATUS_HANDLE    StatusHandle;
90
91 void afsd_ServiceControlHandler(DWORD ctrlCode)
92 {
93         HKEY parmKey;
94         DWORD dummyLen, doTrace;
95         long code;
96
97         switch (ctrlCode) {
98                 case SERVICE_CONTROL_STOP:
99                         /* Shutdown RPC */
100                         RpcMgmtStopServerListening(NULL);
101
102                         /* Force trace if requested */
103                         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
104                                             AFSConfigKeyName,
105                                             0, KEY_QUERY_VALUE, &parmKey);
106                         if (code != ERROR_SUCCESS)
107                                 goto doneTrace;
108
109                         dummyLen = sizeof(doTrace);
110                         code = RegQueryValueEx(parmKey, "TraceOnShutdown",
111                                                 NULL, NULL,
112                                                 (BYTE *) &doTrace, &dummyLen);
113                         RegCloseKey (parmKey);
114                         if (code != ERROR_SUCCESS)
115                                 doTrace = 0;
116                         if (doTrace)
117                                 afsd_ForceTrace(FALSE);
118
119 doneTrace:
120                         ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
121                         ServiceStatus.dwWin32ExitCode = NO_ERROR;
122                         ServiceStatus.dwCheckPoint = 1;
123                         ServiceStatus.dwWaitHint = 10000;
124                         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
125                         SetServiceStatus(StatusHandle, &ServiceStatus);
126                         SetEvent(WaitToTerminate);
127                         break;
128                 case SERVICE_CONTROL_INTERROGATE:
129                         ServiceStatus.dwCurrentState = SERVICE_RUNNING;
130                         ServiceStatus.dwWin32ExitCode = NO_ERROR;
131                         ServiceStatus.dwCheckPoint = 0;
132                         ServiceStatus.dwWaitHint = 0;
133                         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
134                         SetServiceStatus(StatusHandle, &ServiceStatus);
135                         break;
136                 /* XXX handle system shutdown */
137                 /* XXX handle pause & continue */
138         }
139 }
140
141 #if 1
142 /* This code was moved to Drivemap.cpp*/
143 /* Mount a drive into AFS if the user wants us to */
144 /* DEE Could check first if we are run as SYSTEM */
145 void CheckMountDrive()
146 {
147         char szAfsPath[_MAX_PATH];
148         char szDriveToMapTo[5];
149         DWORD dwResult;
150         char szKeyName[256];
151         HKEY hKey;
152         DWORD dwIndex = 0;
153         DWORD dwDriveSize;
154         DWORD dwSubMountSize;
155         char szSubMount[256];
156         DWORD dwType;
157
158         sprintf(szKeyName, "%s\\GlobalAutoMapper", AFSConfigKeyName);
159
160         dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey);
161         if (dwResult != ERROR_SUCCESS)
162                 return;
163
164         while (1) {
165                 dwDriveSize = sizeof(szDriveToMapTo);
166                 dwSubMountSize = sizeof(szSubMount);
167                 dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 0, &dwType, szSubMount, &dwSubMountSize);
168                 if (dwResult != ERROR_MORE_DATA) {
169                         if (dwResult != ERROR_SUCCESS) {
170                                 if (dwResult != ERROR_NO_MORE_ITEMS)
171                                         afsi_log("Failed to read GlobalAutoMapper values: %d\n", dwResult);
172                                 break;
173                         }
174                 }
175                 
176 #if 0
177                 sprintf(szAfsPath, "\\Device\\LanmanRedirector\\%s\\%s-AFS\\%s", szDriveToMapTo, cm_HostName, szSubMount);
178         
179                 dwResult = DefineDosDevice(DDD_RAW_TARGET_PATH, szDriveToMapTo, szAfsPath);
180 #else
181                 {
182                     NETRESOURCE nr;
183                     memset (&nr, 0x00, sizeof(NETRESOURCE));
184  
185                     sprintf(szAfsPath,"\\\\%s-AFS\\%s",cm_HostName,szSubMount);
186                     
187                     nr.dwScope = RESOURCE_GLOBALNET;
188                     nr.dwType=RESOURCETYPE_DISK;
189                     nr.lpLocalName=szDriveToMapTo;
190                     nr.lpRemoteName=szAfsPath;
191                     nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
192                     nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
193
194                     dwResult = WNetAddConnection2(&nr,NULL,NULL,FALSE);
195                 }
196 #endif
197                 afsi_log("GlobalAutoMap of %s to %s %s", szDriveToMapTo, szSubMount, dwResult ? "succeeded" : "failed");
198         }        
199
200         RegCloseKey(hKey);
201 }
202 #endif
203
204 typedef BOOL ( APIENTRY * AfsdInitHook )(void);
205 #define AFSD_INIT_HOOK "AfsdInitHook"
206 #define AFSD_HOOK_DLL  "afsdhook.dll"
207
208 void afsd_Main()
209 {
210         long code;
211         char *reason;
212         int jmpret;
213     HANDLE hInitHookDll;
214     AfsdInitHook initHook;
215
216 #ifdef _DEBUG
217     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
218                    _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
219 #endif 
220
221         osi_InitPanic(afsd_notifier);
222         osi_InitTraceOption();
223
224         GlobalStatus = 0;
225
226         WaitToTerminate = CreateEvent(NULL, TRUE, FALSE, NULL);
227
228 #ifndef NOTSERVICE
229         StatusHandle = RegisterServiceCtrlHandler(AFS_DAEMON_SERVICE_NAME,
230                         (LPHANDLER_FUNCTION) afsd_ServiceControlHandler);
231
232         ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
233         ServiceStatus.dwServiceSpecificExitCode = 0;
234         ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
235         ServiceStatus.dwWin32ExitCode = NO_ERROR;
236         ServiceStatus.dwCheckPoint = 1;
237         ServiceStatus.dwWaitHint = 15000;
238         ServiceStatus.dwControlsAccepted = 0;
239         SetServiceStatus(StatusHandle, &ServiceStatus);
240 #endif
241     {       
242     HANDLE h; char *ptbuf[1];
243     h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
244     ptbuf[0] = "AFS start pending";
245     ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
246     DeregisterEventSource(h);
247     }
248
249         afsi_start();
250
251     /* allow an exit to be called prior to any initialization */
252     hInitHookDll = LoadLibrary(AFSD_HOOK_DLL);
253     if (hInitHookDll)
254     {
255         BOOL hookRc = FALSE;
256         initHook = ( AfsdInitHook ) GetProcAddress(hInitHookDll, AFSD_INIT_HOOK);
257         if (initHook)
258         {
259             hookRc = initHook();
260         }
261         FreeLibrary(hInitHookDll);
262                
263         if (hookRc == FALSE)
264         {
265             ServiceStatus.dwCurrentState = SERVICE_STOPPED;
266             ServiceStatus.dwWin32ExitCode = NO_ERROR;
267             ServiceStatus.dwCheckPoint = 0;
268             ServiceStatus.dwWaitHint = 0;
269             ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
270             SetServiceStatus(StatusHandle, &ServiceStatus);
271                        
272             /* exit if initialization failed */
273             return;
274         }
275         else
276         {
277             /* allow another 15 seconds to start */
278             ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
279             ServiceStatus.dwServiceSpecificExitCode = 0;
280             ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
281             ServiceStatus.dwWin32ExitCode = NO_ERROR;
282             ServiceStatus.dwCheckPoint = 2;
283             ServiceStatus.dwWaitHint = 15000;
284             ServiceStatus.dwControlsAccepted = 0;
285             SetServiceStatus(StatusHandle, &ServiceStatus);
286         }
287     }
288
289     MainThreadId = GetCurrentThreadId();
290         jmpret = setjmp(notifier_jmp);
291
292         if (jmpret == 0) {
293                 code = afsd_InitCM(&reason);
294                 if (code != 0)
295                         osi_panic(reason, __FILE__, __LINE__);
296
297                 code = afsd_InitDaemons(&reason);
298                 if (code != 0)
299                         osi_panic(reason, __FILE__, __LINE__);
300
301                 code = afsd_InitSMB(&reason, DummyMessageBox);
302                 if (code != 0)
303                         osi_panic(reason, __FILE__, __LINE__);
304
305 #ifndef NOTSERVICE
306                 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
307                 ServiceStatus.dwWin32ExitCode = NO_ERROR;
308                 ServiceStatus.dwCheckPoint = 0;
309                 ServiceStatus.dwWaitHint = 0;
310                 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
311                 SetServiceStatus(StatusHandle, &ServiceStatus);
312 #endif
313         {
314             HANDLE h; char *ptbuf[1];
315                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
316                 ptbuf[0] = "AFS running";
317                 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
318                 DeregisterEventSource(h);
319         }
320         }
321
322     /* Check if we should mount a drive into AFS */
323     CheckMountDrive();
324
325         WaitForSingleObject(WaitToTerminate, INFINITE);
326         
327     {   
328     HANDLE h; char *ptbuf[1];
329         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
330         ptbuf[0] = "AFS quitting";
331         ReportEvent(h, GlobalStatus ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
332                 0, 0, NULL, 1, 0, ptbuf, NULL);
333     DeregisterEventSource(h);
334     }
335
336         ServiceStatus.dwCurrentState = SERVICE_STOPPED;
337         ServiceStatus.dwWin32ExitCode = GlobalStatus ? ERROR_EXCEPTION_IN_SERVICE : NO_ERROR;
338         ServiceStatus.dwCheckPoint = 0;
339         ServiceStatus.dwWaitHint = 0;
340         ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
341         SetServiceStatus(StatusHandle, &ServiceStatus);
342 }
343
344 DWORD __stdcall afsdMain_thread(void* notUsed)
345 {
346         afsd_Main();
347     return(0);
348 }
349
350 void main()
351 {
352         SERVICE_TABLE_ENTRY dispatchTable[] = {
353                 {AFS_DAEMON_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) afsd_Main},
354                 {NULL, NULL}
355         };
356
357     afsd_SetUnhandledExceptionFilter();
358
359         if (!StartServiceCtrlDispatcher(dispatchTable))
360     {
361         LONG status = GetLastError();
362             if (status == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
363         {
364             DWORD tid;
365             CreateThread(NULL, 0, afsdMain_thread, 0, 0, &tid);
366                 
367             printf("Hit <Enter> to terminate OpenAFS Client Service\n");
368             getchar();              
369             SetEvent(WaitToTerminate);
370         }
371     }
372 }