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