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