3db3f32e805336326b66d6891def43c8b408b241
[openafs.git] / src / WINNT / afsd / afsd_init.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 <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <afs/stds.h>
16 #include <afs/afs_args.h>
17
18 #include <windows.h>
19 #include <string.h>
20 #include <nb30.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <locale.h>
24 #include <mbctype.h>
25 #include <winsock2.h>
26 #include <ErrorRep.h>
27
28 #include <osi.h>
29 #include "afsd.h"
30 #ifdef USE_BPLUS
31 #include "cm_btree.h"
32 #endif
33 #include <rx\rx.h>
34 #include <rx\rx_null.h>
35 #include <rx\rxstat.h>
36 #include <WINNT/syscfg.h>
37 #include <WINNT/afsreg.h>
38 #include <afs\afscbint.h>
39
40 #include "smb.h"
41 #include "cm_rpc.h"
42 #include "lanahelper.h"
43 #include <strsafe.h>
44 #include "cm_memmap.h"
45 #include "msrpc.h"
46 #ifdef DEBUG
47 #include <crtdbg.h>
48 #endif
49
50 extern afs_uint32 cryptall;
51 extern afs_uint32 cm_anonvldb;
52 extern int cm_enableServerLocks;
53 extern int cm_followBackupPath;
54 extern int cm_deleteReadOnly;
55 #ifdef USE_BPLUS
56 extern afs_int32 cm_BPlusTrees;
57 #endif
58 extern afs_int32 cm_OfflineROIsValid;
59 extern afs_int32 cm_giveUpAllCBs;
60 extern const clientchar_t **smb_ExecutableExtensions;
61
62 osi_log_t *afsd_logp;
63
64 cm_config_data_t        cm_data;
65
66 fschar_t cm_rootVolumeName[VL_MAXNAMELEN];
67 DWORD cm_rootVolumeNameLen;
68
69 fschar_t cm_mountRoot[1024];
70 DWORD cm_mountRootLen;
71
72 clientchar_t cm_mountRootC[1024];
73 DWORD cm_mountRootCLen;
74
75 int cm_readonlyVolumeVersioning = 0;
76 int cm_logChunkSize;
77 int cm_chunkSize;
78 int cm_virtualCache = 0;
79
80 int smb_UseV3 = 1;
81 afs_uint32 smb_Enabled = 1;
82
83 int LANadapter;
84
85 int numBkgD;
86 int numSvThreads;
87 long rx_mtu = -1;
88 int traceOnPanic = 0;
89
90 int logReady = 0;
91
92 char cm_HostName[200];
93 long cm_HostAddr;
94 unsigned short cm_callbackport = CM_DEFAULT_CALLBACKPORT;
95
96 char cm_NetbiosName[MAX_NB_NAME_LENGTH] = "NOT.YET.SET";
97 clientchar_t cm_NetbiosNameC[MAX_NB_NAME_LENGTH] = _C("NOT.YET.SET");
98
99 char cm_CachePath[MAX_PATH];
100 DWORD cm_ValidateCache = 1;
101
102 BOOL reportSessionStartups = FALSE;
103
104 cm_initparams_v1 cm_initParams;
105
106 clientchar_t *cm_sysName = 0;
107 unsigned int  cm_sysNameCount = 0;
108 clientchar_t *cm_sysNameList[MAXNUMSYSNAMES];
109
110 DWORD TraceOption = 0;
111
112 /*
113  * AFSD Initialization Log
114  *
115  * This is distinct from the regular debug logging facility.
116  * Log items go directly to a file, not to an array in memory, so that even
117  * if AFSD crashes, the log can be inspected.
118  */
119
120 HANDLE afsi_file;
121
122 int cm_dnsEnabled = 1;
123
124
125 static int afsi_log_useTimestamp = 1;
126
127 void
128 afsi_log(char *pattern, ...)
129 {
130     char s[256], t[100], d[100], u[512];
131     DWORD zilch;
132     va_list ap;
133     va_start(ap, pattern);
134
135     StringCbVPrintfA(s, sizeof(s), pattern, ap);
136     if ( afsi_log_useTimestamp ) {
137         GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, t, sizeof(t));
138         GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, d, sizeof(d));
139         StringCbPrintfA(u, sizeof(u), "%s %s: %s\r\n", d, t, s);
140         if (afsi_file != INVALID_HANDLE_VALUE)
141             WriteFile(afsi_file, u, (DWORD)strlen(u), &zilch, NULL);
142 #ifdef NOTSERVICE
143         printf("%s", u);
144 #endif
145     } else {
146         if (afsi_file != INVALID_HANDLE_VALUE)
147             WriteFile(afsi_file, s, (DWORD)strlen(s), &zilch, NULL);
148     }
149 }
150
151 void
152 afsi_start()
153 {
154     char wd[MAX_PATH+1];
155     char t[100], u[100], *p, *path;
156     int zilch;
157     DWORD code;
158     DWORD dwLow, dwHigh;
159     HKEY parmKey;
160     DWORD dummyLen;
161     DWORD maxLogSize = 100 * 1024;
162
163     afsi_file = INVALID_HANDLE_VALUE;
164     code = GetTempPath(sizeof(wd)-15, wd);
165     if ( code == 0 || code > (sizeof(wd)-15) )
166         return;         /* unable to create a log */
167
168     StringCbCatA(wd, sizeof(wd), "\\afsd_init.log");
169     GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, t, sizeof(t));
170     afsi_file = CreateFile(wd, GENERIC_WRITE, FILE_SHARE_READ, NULL,
171                            OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
172
173     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
174                          0, KEY_QUERY_VALUE, &parmKey);
175     if (code == ERROR_SUCCESS) {
176         dummyLen = sizeof(maxLogSize);
177         code = RegQueryValueEx(parmKey, "MaxLogSize", NULL, NULL,
178                                 (BYTE *) &maxLogSize, &dummyLen);
179         RegCloseKey (parmKey);
180     }
181
182     if (maxLogSize) {
183         dwLow = GetFileSize( afsi_file, &dwHigh );
184         if ( dwHigh > 0 || dwLow >= maxLogSize ) {
185             CloseHandle(afsi_file);
186             afsi_file = CreateFile( wd, GENERIC_WRITE, FILE_SHARE_READ, NULL,
187                                     CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
188         }
189     }
190
191     SetFilePointer(afsi_file, 0, NULL, FILE_END);
192     GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, u, sizeof(u));
193     StringCbCatA(t, sizeof(t), ": Create log file\r\n");
194     StringCbCatA(u, sizeof(u), ": Created log file\r\n");
195     WriteFile(afsi_file, t, (DWORD)strlen(t), &zilch, NULL);
196     WriteFile(afsi_file, u, (DWORD)strlen(u), &zilch, NULL);
197     p = "PATH=";
198     code = GetEnvironmentVariable("PATH", NULL, 0);
199     path = malloc(code);
200     code = GetEnvironmentVariable("PATH", path, code);
201     WriteFile(afsi_file, p, (DWORD)strlen(p), &zilch, NULL);
202     WriteFile(afsi_file, path, (DWORD)strlen(path), &zilch, NULL);
203     WriteFile(afsi_file, "\r\n", (DWORD)1, &zilch, NULL);
204     free(path);
205
206     /* Initialize C RTL Code Page conversion functions */
207     /* All of the path info obtained from the SMB client is in the OEM code page */
208     afsi_log("OEM Code Page = %d", GetOEMCP());
209     afsi_log("locale =  %s", setlocale(LC_ALL,NULL));
210 #ifdef COMMENT
211     /* Two things to look into.  First, should mbstowcs() be performing
212      * character set translations from OEM to Unicode in smb3.c;
213      * Second, do we need to set this translation in each function
214      * due to multi-threading.
215      */
216     afsi_log("locale -> %s", setlocale(LC_ALL, ".OCP"));
217     afsi_log("_setmbcp = %d -> %d", _setmbcp(_MB_CP_OEM), _getmbcp());
218 #endif /* COMMENT */
219 }
220
221 /*
222  * Standard AFSD trace
223  */
224
225 void afsd_ForceTrace(BOOL flush)
226 {
227     HANDLE handle;
228     int len;
229     char buf[256];
230
231     if (!logReady)
232         return;
233
234     len = GetTempPath(sizeof(buf)-10, buf);
235     StringCbCopyA(&buf[len], sizeof(buf)-len, "/afsd.log");
236     handle = CreateFile(buf, GENERIC_WRITE, FILE_SHARE_READ,
237                          NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
238     if (handle == INVALID_HANDLE_VALUE) {
239         logReady = 0;
240         osi_panic("Cannot create log file", __FILE__, __LINE__);
241     }
242     osi_LogPrint(afsd_logp, handle);
243     if (flush)
244         FlushFileBuffers(handle);
245     CloseHandle(handle);
246 }
247
248 static void afsd_InitServerPreferences(void)
249 {
250     HKEY hkPrefs = 0;
251     DWORD dwType, dwSize;
252     DWORD dwPrefs = 0;
253     DWORD dwIndex;
254     TCHAR szHost[256];
255     DWORD dwHostSize = 256;
256     DWORD dwRank;
257     struct sockaddr_in  saddr;
258     cm_server_t       *tsp;
259
260     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
261                       AFSREG_CLT_OPENAFS_SUBKEY "\\Server Preferences\\VLDB",
262                       0,
263                       KEY_READ|KEY_QUERY_VALUE,
264                       &hkPrefs) == ERROR_SUCCESS) {
265
266         RegQueryInfoKey( hkPrefs,
267                          NULL,  /* lpClass */
268                          NULL,  /* lpcClass */
269                          NULL,  /* lpReserved */
270                          NULL,  /* lpcSubKeys */
271                          NULL,  /* lpcMaxSubKeyLen */
272                          NULL,  /* lpcMaxClassLen */
273                          &dwPrefs, /* lpcValues */
274                          NULL,  /* lpcMaxValueNameLen */
275                          NULL,  /* lpcMaxValueLen */
276                          NULL,  /* lpcbSecurityDescriptor */
277                          NULL   /* lpftLastWriteTime */
278                          );
279
280         for ( dwIndex = 0 ; dwIndex < dwPrefs; dwIndex++ ) {
281
282             dwSize = sizeof(DWORD);
283             dwHostSize = 256;
284
285             if (RegEnumValue( hkPrefs, dwIndex, szHost, &dwHostSize, NULL,
286                               &dwType, (LPBYTE)&dwRank, &dwSize))
287             {
288                 afsi_log("RegEnumValue(hkPrefs) failed");
289                 continue;
290             }
291
292             afsi_log("VLDB Server Preference: %s = %d",szHost, dwRank);
293
294             if (isdigit(szHost[0]))
295             {
296                 if ((saddr.sin_addr.S_un.S_addr = inet_addr (szHost)) == INADDR_NONE)
297                     continue;
298             } else {
299                 HOSTENT *pEntry;
300                 if ((pEntry = gethostbyname (szHost)) == NULL)
301                     continue;
302
303                 saddr.sin_addr.S_un.S_addr = *(unsigned long *)pEntry->h_addr;
304             }
305             saddr.sin_port = htons(7003);
306             saddr.sin_family = AF_INET;
307             dwRank += (rand() & 0x000f);
308
309             tsp = cm_FindServer(&saddr, CM_SERVER_VLDB, FALSE);
310             if ( tsp )          /* an existing server - ref count increased */
311             {
312                 lock_ObtainMutex(&tsp->mx);
313                 tsp->ipRank = (USHORT)dwRank;
314                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
315                 tsp->adminRank = tsp->ipRank;
316                 lock_ReleaseMutex(&tsp->mx);
317
318                 /* set preferences for an existing vlserver */
319                 cm_ChangeRankCellVLServer(tsp);
320                 cm_PutServer(tsp);  /* decrease refcount */
321             }
322             else        /* add a new server without a cell */
323             {
324                 tsp = cm_NewServer(&saddr, CM_SERVER_VLDB, NULL, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
325                 lock_ObtainMutex(&tsp->mx);
326                 tsp->ipRank = (USHORT)dwRank;
327                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
328                 tsp->adminRank = tsp->ipRank;
329                 lock_ReleaseMutex(&tsp->mx);
330             }
331         }
332
333         RegCloseKey(hkPrefs);
334     }
335
336     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
337                       AFSREG_CLT_OPENAFS_SUBKEY "\\Server Preferences\\File",
338                       0,
339                       KEY_READ|KEY_QUERY_VALUE,
340                       &hkPrefs) == ERROR_SUCCESS) {
341
342         RegQueryInfoKey( hkPrefs,
343                          NULL,  /* lpClass */
344                          NULL,  /* lpcClass */
345                          NULL,  /* lpReserved */
346                          NULL,  /* lpcSubKeys */
347                          NULL,  /* lpcMaxSubKeyLen */
348                          NULL,  /* lpcMaxClassLen */
349                          &dwPrefs, /* lpcValues */
350                          NULL,  /* lpcMaxValueNameLen */
351                          NULL,  /* lpcMaxValueLen */
352                          NULL,  /* lpcbSecurityDescriptor */
353                          NULL   /* lpftLastWriteTime */
354                          );
355
356         for ( dwIndex = 0 ; dwIndex < dwPrefs; dwIndex++ ) {
357
358             dwSize = sizeof(DWORD);
359             dwHostSize = 256;
360
361             if (RegEnumValue( hkPrefs, dwIndex, szHost, &dwHostSize, NULL,
362                               &dwType, (LPBYTE)&dwRank, &dwSize))
363             {
364                 afsi_log("RegEnumValue(hkPrefs) failed");
365                 continue;
366             }
367
368             afsi_log("File Server Preference: %s = %d",szHost, dwRank);
369
370             if (isdigit(szHost[0]))
371             {
372                 if ((saddr.sin_addr.S_un.S_addr = inet_addr (szHost)) == INADDR_NONE)
373                     continue;
374             } else {
375                 HOSTENT *pEntry;
376                 if ((pEntry = gethostbyname (szHost)) == NULL)
377                     continue;
378
379                 saddr.sin_addr.S_un.S_addr = *(unsigned long *)pEntry->h_addr;
380             }
381             saddr.sin_port = htons(7000);
382             saddr.sin_family = AF_INET;
383             dwRank += (rand() & 0x000f);
384
385             tsp = cm_FindServer(&saddr, CM_SERVER_FILE, FALSE);
386             if ( tsp )          /* an existing server - ref count increased */
387             {
388                 lock_ObtainMutex(&tsp->mx);
389                 tsp->ipRank = (USHORT)dwRank;
390                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
391                 tsp->adminRank = tsp->ipRank;
392                 lock_ReleaseMutex(&tsp->mx);
393
394                 /* find volumes which might have RO copy
395                 /* on server and change the ordering of
396                  * their RO list
397                  */
398                 cm_ChangeRankVolume(tsp);
399                 cm_PutServer(tsp);  /* decrease refcount */
400             }
401             else        /* add a new server without a cell */
402             {
403                 tsp = cm_NewServer(&saddr, CM_SERVER_FILE, NULL, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
404                 lock_ObtainMutex(&tsp->mx);
405                 tsp->ipRank = (USHORT)dwRank;
406                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
407                 tsp->adminRank = tsp->ipRank;
408                 lock_ReleaseMutex(&tsp->mx);
409             }
410         }
411
412         RegCloseKey(hkPrefs);
413     }
414 }
415
416
417 #ifndef _WIN64
418 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
419
420 static BOOL
421 is_wow64(void)
422 {
423     static BOOL bChecked = FALSE;
424     static BOOL bIsWow64 = FALSE;
425
426     if (!bChecked)
427     {
428         HANDLE h1 = NULL;
429         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
430
431         h1 = GetModuleHandle("kernel32.dll");
432         fnIsWow64Process =
433             (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
434
435         /* If we don't find the fnIsWow64Process function then we
436          * are not running in a broken Wow64
437          */
438         if (fnIsWow64Process)
439             fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
440
441         bChecked = TRUE;
442     }
443
444     return bIsWow64;
445 }
446 #endif /* _WIN64 */
447
448 /*
449  * AFSD Initialization
450  */
451
452 static int
453 afsd_InitRoot(char **reasonP)
454 {
455     long code;
456     cm_req_t req;
457
458     cm_InitReq(&req);
459
460     if (cm_freelanceEnabled) {
461         cm_FakeRootFid(&cm_data.rootFid);
462     } else {
463         int attempts = 10;
464
465         osi_Log0(afsd_logp, "Loading Root Volume from cell");
466         do {
467             code = cm_FindVolumeByName(cm_data.rootCellp, cm_rootVolumeName, cm_rootUserp,
468                                        &req, CM_GETVOL_FLAG_CREATE, &cm_data.rootVolumep);
469             afsi_log("cm_FindVolumeByName code %x root vol %x", code,
470                       (code ? (cm_volume_t *)-1 : cm_data.rootVolumep));
471         } while (code && --attempts);
472         if (code != 0) {
473             *reasonP = "can't find root volume in root cell";
474             return -1;
475         }
476
477         /* compute the root fid */
478         cm_SetFid(&cm_data.rootFid, cm_data.rootCellp->cellID, cm_GetROVolumeID(cm_data.rootVolumep), 1, 1);
479     }
480
481     code = cm_GetSCache(&cm_data.rootFid, &cm_data.rootSCachep, cm_rootUserp, &req);
482     afsi_log("cm_GetSCache code %x scache %x", code,
483              (code ? (cm_scache_t *)-1 : cm_data.rootSCachep));
484     if (code != 0) {
485         *reasonP = "unknown error";
486         return -1;
487     }
488
489     return 0;
490 }
491
492 int
493 afsd_InitCM(char **reasonP)
494 {
495     osi_uid_t debugID;
496     afs_uint64 cacheBlocks;
497     DWORD cacheSize;
498     DWORD blockSize;
499     long logChunkSize;
500     DWORD stats;
501     DWORD volumes;
502     DWORD cells;
503     DWORD dwValue;
504     DWORD rx_enable_peer_stats;
505     DWORD rx_enable_process_stats;
506     DWORD rx_udpbufsize = -1;
507     DWORD lockOrderValidation;
508     long traceBufSize;
509     long maxcpus;
510     long ltt, ltto;
511     long rx_nojumbo;
512     int  rx_max_rwin_size;
513     int  rx_max_swin_size;
514     int  rx_min_peer_timeout;
515     DWORD virtualCache = 0;
516     fschar_t rootCellName[256];
517     struct rx_service *serverp;
518     static struct rx_securityClass *nullServerSecurityClassp;
519     struct hostent *thp;
520     char *msgBuf;
521     char buf[1024];
522     HKEY parmKey;
523     DWORD dummyLen;
524     DWORD regType;
525     long code;
526     /*int freelanceEnabled;*/
527     WSADATA WSAjunk;
528     int i;
529     int cm_noIPAddr;         /* number of client network interfaces */
530     int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
531     int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
532     int cm_NetMtu[CM_MAXINTERFACE_ADDR];    /* client's MTU sizes */
533     int cm_NetFlags[CM_MAXINTERFACE_ADDR];  /* network flags */
534     DWORD dwPriority;
535
536     WSAStartup(0x0101, &WSAjunk);
537
538     init_et_to_sys_error();
539
540     cm_utilsInit();
541
542     /* setup osidebug server at RPC slot 1000 */
543     osi_LongToUID(1000, &debugID);
544     code = osi_InitDebug(&debugID);
545     afsi_log("osi_InitDebug code %d", code);
546
547 #ifndef _WIN64
548     if (is_wow64())
549     {
550         *reasonP = "32-bit OpenAFS Service is incompatible with the WOW64 environment";
551         return -1;
552     }
553 #endif
554
555     //  osi_LockTypeSetDefault("stat"); /* comment this out for speed */
556     if (code != 0) {
557         if (code == RPC_S_NO_PROTSEQS)
558             *reasonP = "No RPC Protocol Sequences registered.  Check HKLM\\SOFTWARE\\Microsoft\\RPC\\ClientProtocols";
559         else
560             *reasonP = "unknown error";
561         return -1;
562     }
563
564     /* who are we ? */
565     gethostname(cm_HostName, sizeof(cm_HostName));
566     afsi_log("gethostname %s", cm_HostName);
567     thp = gethostbyname(cm_HostName);
568     memcpy(&cm_HostAddr, thp->h_addr_list[0], 4);
569
570     /* seed random number generator */
571     srand(ntohl(cm_HostAddr));
572
573     /* Look up configuration parameters in Registry */
574     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
575                         0, KEY_QUERY_VALUE, &parmKey);
576     if (code != ERROR_SUCCESS) {
577         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
578                        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
579                        NULL, code, 0, (LPTSTR)&msgBuf, 0, NULL);
580         StringCbPrintfA(buf, sizeof(buf),
581                          "Failure in configuration while opening Registry: %s",
582                          msgBuf);
583         osi_panic(buf, __FILE__, __LINE__);
584     }
585
586     dummyLen = sizeof(dwPriority);
587     code = RegQueryValueEx(parmKey, "PriorityClass", NULL, NULL,
588                             (BYTE *) &dwPriority, &dummyLen);
589     if (code != ERROR_SUCCESS || dwPriority == 0) {
590         dwPriority = HIGH_PRIORITY_CLASS;
591     }
592     if (dwPriority != GetPriorityClass(GetCurrentProcess()))
593         SetPriorityClass(GetCurrentProcess(), dwPriority);
594     afsi_log("PriorityClass 0x%x", GetPriorityClass(GetCurrentProcess()));
595
596     dummyLen = sizeof(lockOrderValidation);
597     code = RegQueryValueEx(parmKey, "LockOrderValidation", NULL, NULL,
598                             (BYTE *) &lockOrderValidation, &dummyLen);
599     if (code != ERROR_SUCCESS) {
600 #ifdef DEBUG
601         lockOrderValidation = 1;
602 #else
603         lockOrderValidation = 0;
604 #endif
605     }
606     osi_SetLockOrderValidation(lockOrderValidation);
607     afsi_log("Lock Order Validation %s", lockOrderValidation ? "On" : "Off");
608
609     dummyLen = sizeof(maxcpus);
610     code = RegQueryValueEx(parmKey, "MaxCPUs", NULL, NULL,
611                             (BYTE *) &maxcpus, &dummyLen);
612     if (code == ERROR_SUCCESS) {
613         HANDLE hProcess;
614         DWORD_PTR processAffinityMask, systemAffinityMask;
615
616         hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION,
617                                FALSE, GetCurrentProcessId());
618         if ( hProcess != NULL &&
619              GetProcessAffinityMask(hProcess, &processAffinityMask, &systemAffinityMask) )
620         {
621             int i, n, bits;
622             DWORD_PTR mask, newAffinityMask;
623
624 #if defined(_WIN64)
625             bits = 64;
626 #else
627             bits = 32;
628 #endif
629             for ( i=0, n=0, mask=1, newAffinityMask=0; i<bits && n<maxcpus; i++ ) {
630                 if ( processAffinityMask & mask ) {
631                     newAffinityMask |= mask;
632                     n++;
633                 }
634                 mask *= 2;
635             }
636
637             SetProcessAffinityMask(hProcess, newAffinityMask);
638             CloseHandle(hProcess);
639             afsi_log("CPU Restrictions set to %d cpu(s); %d cpu(s) available", maxcpus, n);
640         } else {
641             afsi_log("CPU Restrictions set to %d cpu(s); unable to access process information", maxcpus);
642         }
643     }
644
645     dummyLen = sizeof(TraceOption);
646     code = RegQueryValueEx(parmKey, "TraceOption", NULL, NULL,
647                             (BYTE *) &TraceOption, &dummyLen);
648     afsi_log("Trace Options = %lX", TraceOption);
649
650     dummyLen = sizeof(traceBufSize);
651     code = RegQueryValueEx(parmKey, "TraceBufferSize", NULL, NULL,
652                             (BYTE *) &traceBufSize, &dummyLen);
653     if (code == ERROR_SUCCESS)
654         afsi_log("Trace Buffer size %d", traceBufSize);
655     else {
656         traceBufSize = CM_CONFIGDEFAULT_TRACEBUFSIZE;
657         afsi_log("Default trace buffer size %d", traceBufSize);
658     }
659
660     /* setup and enable debug log */
661     afsd_logp = osi_LogCreate("afsd", traceBufSize);
662     afsi_log("osi_LogCreate log addr %x", PtrToUlong(afsd_logp));
663     if ((TraceOption & 0x8)
664 #ifdef DEBUG
665          || 1
666 #endif
667          ) {
668         osi_LogEnable(afsd_logp);
669     }
670     logReady = 1;
671
672     osi_Log0(afsd_logp, "Log init");
673
674     dummyLen = sizeof(smb_monitorReqs);
675     code = RegQueryValueEx(parmKey, "SMBRequestMonitor", NULL, NULL,
676                            (BYTE *) &smb_monitorReqs, &dummyLen);
677     afsi_log("SMB request monitoring is %s", (smb_monitorReqs != 0)? "enabled": "disabled");
678
679     dummyLen = sizeof(virtualCache);
680     code = RegQueryValueEx(parmKey, "NonPersistentCaching", NULL, NULL,
681                             (LPBYTE)&virtualCache, &dummyLen);
682     if (!code)
683         cm_virtualCache = virtualCache ? 1 : 0;
684     afsi_log("Cache type is %s", (cm_virtualCache?"VIRTUAL":"FILE"));
685
686     if (!cm_virtualCache) {
687         dummyLen = sizeof(cm_ValidateCache);
688         code = RegQueryValueEx(parmKey, "ValidateCache", NULL, NULL,
689                                (LPBYTE)&cm_ValidateCache, &dummyLen);
690         if ( cm_ValidateCache < 0 || cm_ValidateCache > 2 )
691             cm_ValidateCache = 1;
692         switch (cm_ValidateCache) {
693         case 0:
694             afsi_log("Cache Validation disabled");
695             break;
696         case 1:
697             afsi_log("Cache Validation on Startup");
698             break;
699         case 2:
700             afsi_log("Cache Validation on Startup and Shutdown");
701             break;
702         }
703     }
704
705     dummyLen = sizeof(cacheSize);
706     code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
707                             (BYTE *) &cacheSize, &dummyLen);
708     if (code != ERROR_SUCCESS)
709         cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
710
711     if (cm_virtualCache) {
712         MEMORYSTATUSEX memStatus;
713         DWORD maxCacheSize;
714
715         memStatus.dwLength = sizeof(memStatus);
716         if (GlobalMemoryStatusEx(&memStatus)) {
717             /* Set maxCacheSize to 10% of physical memory */
718             maxCacheSize = (DWORD)(memStatus.ullTotalPhys / 1024 / 10);
719         } else {
720             /* Cannot determine physical memory, set limit to 64MB */
721             maxCacheSize = 65536;
722         }
723         if (cacheSize > maxCacheSize) {
724             afsi_log("Requested Cache size %u", cacheSize);
725             cacheSize = maxCacheSize;
726         }
727     }
728     afsi_log("Allocated Cache size %u", cacheSize);
729
730     dummyLen = sizeof(logChunkSize);
731     code = RegQueryValueEx(parmKey, "ChunkSize", NULL, NULL,
732                             (BYTE *) &logChunkSize, &dummyLen);
733     if (code == ERROR_SUCCESS) {
734         if (logChunkSize < 12 || logChunkSize > 30) {
735             afsi_log("Invalid chunk size %d, using default",
736                       logChunkSize);
737             logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
738         }
739     } else {
740         logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
741     }
742     cm_logChunkSize = logChunkSize;
743     cm_chunkSize = 1 << logChunkSize;
744     afsi_log("Chunk size %u (%d)", cm_chunkSize, cm_logChunkSize);
745
746     dummyLen = sizeof(blockSize);
747     code = RegQueryValueEx(parmKey, "blockSize", NULL, NULL,
748                             (BYTE *) &blockSize, &dummyLen);
749     if (code == ERROR_SUCCESS) {
750         if (blockSize < 1 ||
751             (blockSize > 1024 && (blockSize % CM_CONFIGDEFAULT_BLOCKSIZE != 0)))
752         {
753             afsi_log("Invalid block size %u specified, using default", blockSize);
754             blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
755         } else {
756             /*
757              * if the blockSize is less than 1024 we permit the blockSize to be
758              * specified in multiples of the default blocksize
759              */
760             if (blockSize <= 1024)
761                 blockSize *= CM_CONFIGDEFAULT_BLOCKSIZE;
762         }
763     } else {
764         blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
765     }
766     if (blockSize > cm_chunkSize) {
767         afsi_log("Block size (%d) cannot be larger than Chunk size (%d).",
768                   blockSize, cm_chunkSize);
769         blockSize = cm_chunkSize;
770     }
771     if (cm_chunkSize % blockSize != 0) {
772         afsi_log("Block size (%d) must be a factor of Chunk size (%d).",
773                   blockSize, cm_chunkSize);
774         blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
775     }
776     afsi_log("Block size %u", blockSize);
777
778     dummyLen = sizeof(numBkgD);
779     code = RegQueryValueEx(parmKey, "Daemons", NULL, NULL,
780                             (BYTE *) &numBkgD, &dummyLen);
781     if (code == ERROR_SUCCESS) {
782         if (numBkgD > CM_MAX_DAEMONS)
783             numBkgD = CM_MAX_DAEMONS;
784         afsi_log("%d background daemons", numBkgD);
785     } else {
786         numBkgD = CM_CONFIGDEFAULT_DAEMONS;
787         afsi_log("Defaulting to %d background daemons", numBkgD);
788     }
789
790     dummyLen = sizeof(numSvThreads);
791     code = RegQueryValueEx(parmKey, "ServerThreads", NULL, NULL,
792                             (BYTE *) &numSvThreads, &dummyLen);
793     if (code == ERROR_SUCCESS)
794         afsi_log("%d server threads", numSvThreads);
795     else {
796         numSvThreads = CM_CONFIGDEFAULT_SVTHREADS;
797         afsi_log("Defaulting to %d server threads", numSvThreads);
798     }
799
800     dummyLen = sizeof(stats);
801     code = RegQueryValueEx(parmKey, "Stats", NULL, NULL,
802                             (BYTE *) &stats, &dummyLen);
803     if (code == ERROR_SUCCESS)
804         afsi_log("Status cache entries: %d", stats);
805     else {
806         stats = CM_CONFIGDEFAULT_STATS;
807         afsi_log("Default status cache entries: %d", stats);
808     }
809
810     dummyLen = sizeof(volumes);
811     code = RegQueryValueEx(parmKey, "Volumes", NULL, NULL,
812                             (BYTE *) &volumes, &dummyLen);
813     if (code == ERROR_SUCCESS)
814         afsi_log("Volumes cache entries: %d", volumes);
815     else {
816         volumes = CM_CONFIGDEFAULT_STATS / 3;
817         afsi_log("Default volume cache entries: %d", volumes);
818     }
819
820     dummyLen = sizeof(cells);
821     code = RegQueryValueEx(parmKey, "Cells", NULL, NULL,
822                             (BYTE *) &cells, &dummyLen);
823     if (code == ERROR_SUCCESS)
824         afsi_log("Cell cache entries: %d", cells);
825     else {
826         cells = CM_CONFIGDEFAULT_CELLS;
827         afsi_log("Default cell cache entries: %d", cells);
828     }
829
830     dummyLen = sizeof(ltt);
831     code = RegQueryValueEx(parmKey, "LogoffTokenTransfer", NULL, NULL,
832                             (BYTE *) &ltt, &dummyLen);
833     if (code != ERROR_SUCCESS)
834         ltt = 1;
835     smb_LogoffTokenTransfer = ltt;
836     afsi_log("Logoff token transfer %s",  (ltt ? "on" : "off"));
837
838     if (ltt) {
839         dummyLen = sizeof(ltto);
840         code = RegQueryValueEx(parmKey, "LogoffTokenTransferTimeout",
841                                 NULL, NULL, (BYTE *) &ltto, &dummyLen);
842         if (code != ERROR_SUCCESS)
843             ltto = 120;
844     } else {
845         ltto = 0;
846     }
847     smb_LogoffTransferTimeout = ltto;
848     afsi_log("Logoff token transfer timeout %d seconds", ltto);
849
850     dummyLen = sizeof(cm_rootVolumeName);
851     code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
852                             (LPBYTE) cm_rootVolumeName, &dummyLen);
853     if (code == ERROR_SUCCESS)
854         afsi_log("Root volume %s", cm_rootVolumeName);
855     else {
856         cm_FsStrCpy(cm_rootVolumeName, lengthof(cm_rootVolumeName), "root.afs");
857         afsi_log("Default root volume name root.afs");
858     }
859
860     cm_mountRootCLen = sizeof(cm_mountRootC);
861     code = RegQueryValueExW(parmKey, L"MountRoot", NULL, NULL,
862                             (LPBYTE) cm_mountRootC, &cm_mountRootCLen);
863     if (code == ERROR_SUCCESS) {
864         afsi_log("Mount root %S", cm_mountRootC);
865         cm_mountRootCLen = (DWORD)cm_ClientStrLen(cm_mountRootC);
866     } else {
867         cm_ClientStrCpy(cm_mountRootC, lengthof(cm_mountRootC), _C("/afs"));
868         cm_mountRootCLen = (DWORD)cm_ClientStrLen(cm_mountRootC);
869         /* Don't log */
870     }
871
872     cm_ClientStringToFsString(cm_mountRootC, -1, cm_mountRoot, lengthof(cm_mountRoot));
873     cm_mountRootLen = (DWORD)cm_FsStrLen(cm_mountRoot);
874
875     dummyLen = sizeof(buf);
876     code = RegQueryValueEx(parmKey, "CachePath", NULL, &regType,
877                            buf, &dummyLen);
878     if (code == ERROR_SUCCESS && buf[0]) {
879         if (regType == REG_EXPAND_SZ) {
880             dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
881             if (dummyLen > sizeof(cm_CachePath)) {
882                 afsi_log("Cache path [%s] longer than %d after expanding env strings", buf, sizeof(cm_CachePath));
883                 osi_panic("CachePath too long", __FILE__, __LINE__);
884             }
885         } else {
886             StringCbCopyA(cm_CachePath, sizeof(cm_CachePath), buf);
887         }
888         afsi_log("Cache path %s", cm_CachePath);
889     } else {
890         dummyLen = ExpandEnvironmentStrings("%TEMP%\\AFSCache", cm_CachePath, sizeof(cm_CachePath));
891         if (dummyLen > sizeof(cm_CachePath)) {
892             afsi_log("Cache path [%%TEMP%%\\AFSCache] longer than %d after expanding env strings",
893                      sizeof(cm_CachePath));
894             osi_panic("CachePath too long", __FILE__, __LINE__);
895         }
896         afsi_log("Default cache path %s", cm_CachePath);
897     }
898
899     dummyLen = sizeof(traceOnPanic);
900     code = RegQueryValueEx(parmKey, "TrapOnPanic", NULL, NULL,
901                             (BYTE *) &traceOnPanic, &dummyLen);
902     if (code != ERROR_SUCCESS)
903         traceOnPanic = 1;              /* log */
904     afsi_log("Set to %s on panic", traceOnPanic ? "trap" : "not trap");
905
906     dummyLen = sizeof(reportSessionStartups);
907     code = RegQueryValueEx(parmKey, "ReportSessionStartups", NULL, NULL,
908                             (BYTE *) &reportSessionStartups, &dummyLen);
909     if (code == ERROR_SUCCESS)
910         afsi_log("Session startups %s be recorded in the Event Log",
911                   reportSessionStartups ? "will" : "will not");
912     else {
913         reportSessionStartups = 0;
914         /* Don't log */
915     }
916
917     for ( i=0; i < MAXNUMSYSNAMES; i++ ) {
918         cm_sysNameList[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
919         cm_sysNameList[i][0] = '\0';
920     }
921     cm_sysName = cm_sysNameList[0];
922
923     {
924         clientchar_t *p, *q;
925         clientchar_t * cbuf = (clientchar_t *) buf;
926         dummyLen = sizeof(buf);
927         code = RegQueryValueExW(parmKey, L"SysName", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
928         if (code != ERROR_SUCCESS || !cbuf[0]) {
929 #if defined(_IA64_)
930             cm_ClientStrCpy(cbuf, lengthof(buf), _C("ia64_win64"));
931 #elif defined(_AMD64_)
932             cm_ClientStrCpy(cbuf, lengthof(buf), _C("amd64_win64 x86_win32 i386_w2k"));
933 #else /* assume x86 32-bit */
934             cm_ClientStrCpy(cbuf, lengthof(buf), _C("x86_win32 i386_w2k i386_nt40"));
935 #endif
936         }
937         afsi_log("Sys name %S", cbuf);
938
939         /* breakup buf into individual search string entries */
940         for (p = q = cbuf; p < cbuf + dummyLen; p++) {
941             if (*p == '\0' || iswspace(*p)) {
942                 memcpy(cm_sysNameList[cm_sysNameCount],q,(p-q) * sizeof(clientchar_t));
943                 cm_sysNameList[cm_sysNameCount][p-q] = '\0';
944                 cm_sysNameCount++;
945                 do {
946                     if (*p == '\0')
947                         goto done_sysname;
948                     p++;
949                 } while (*p == '\0' || isspace(*p));
950                 q = p;
951                 p--;
952             }
953         }
954     }
955   done_sysname:
956     cm_ClientStrCpy(cm_sysName, MAXSYSNAME, cm_sysNameList[0]);
957
958     dummyLen = sizeof(cryptall);
959     code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
960                            (BYTE *) &cryptall, &dummyLen);
961     if (code == ERROR_SUCCESS) {
962         afsi_log("SecurityLevel is %s", cryptall == 1?"crypt": cryptall == 2?"auth":"clear");
963     } else {
964         cryptall = 0;
965         afsi_log("Default SecurityLevel is clear");
966     }
967
968     if (cryptall == 1)
969         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
970     else if (cryptall == 2)
971         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_AUTH);
972     else
973         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
974
975     dummyLen = sizeof(cryptall);
976     code = RegQueryValueEx(parmKey, "ForceAnonVLDB", NULL, NULL,
977                             (BYTE *) &cm_anonvldb, &dummyLen);
978     afsi_log("CM ForceAnonVLDB is %s", cm_anonvldb ? "on" : "off");
979
980     dummyLen = sizeof(cm_dnsEnabled);
981     code = RegQueryValueEx(parmKey, "UseDNS", NULL, NULL,
982                             (BYTE *) &cm_dnsEnabled, &dummyLen);
983     if (code == ERROR_SUCCESS) {
984         afsi_log("DNS %s be used to find AFS cell servers",
985                   cm_dnsEnabled ? "will" : "will not");
986     }
987     else {
988         cm_dnsEnabled = 1;   /* default on */
989         afsi_log("Default to use DNS to find AFS cell servers");
990     }
991
992 #ifdef AFS_FREELANCE_CLIENT
993     dummyLen = sizeof(cm_freelanceEnabled);
994     code = RegQueryValueEx(parmKey, "FreelanceClient", NULL, NULL,
995                             (BYTE *) &cm_freelanceEnabled, &dummyLen);
996     afsi_log("Freelance client feature %s activated",
997               cm_freelanceEnabled ? "is" : "is not");
998
999     dummyLen = sizeof(cm_freelanceImportCellServDB);
1000     code = RegQueryValueEx(parmKey, "FreelanceImportCellServDB", NULL, NULL,
1001                             (BYTE *) &cm_freelanceImportCellServDB, &dummyLen);
1002     afsi_log("Freelance client %s import CellServDB",
1003               cm_freelanceImportCellServDB ? "does" : "does not");
1004 #endif /* AFS_FREELANCE_CLIENT */
1005
1006     dummyLen = sizeof(smb_UseUnicode);
1007     code = RegQueryValueEx(parmKey, "NegotiateUnicode", NULL, NULL,
1008                            (BYTE *) &smb_UseUnicode, &dummyLen);
1009     if (code != ERROR_SUCCESS) {
1010         smb_UseUnicode = 1; /* default on */
1011     }
1012     afsi_log("SMB Server Unicode Support is %s",
1013               smb_UseUnicode ? "enabled" : "disabled");
1014
1015     dummyLen = sizeof(smb_hideDotFiles);
1016     code = RegQueryValueEx(parmKey, "HideDotFiles", NULL, NULL,
1017                            (BYTE *) &smb_hideDotFiles, &dummyLen);
1018     if (code != ERROR_SUCCESS) {
1019         smb_hideDotFiles = 1; /* default on */
1020     }
1021     afsi_log("Dot files/dirs will %sbe marked hidden",
1022               smb_hideDotFiles ? "" : "not ");
1023
1024     dummyLen = sizeof(dwValue);
1025     code = RegQueryValueEx(parmKey, "UnixModeFileDefault", NULL, NULL,
1026                            (BYTE *) &dwValue, &dummyLen);
1027     if (code == ERROR_SUCCESS) {
1028         smb_unixModeDefaultFile = (dwValue & 07777);
1029     }
1030     afsi_log("Default unix mode bits for files is 0%04o", smb_unixModeDefaultFile);
1031
1032     dummyLen = sizeof(dwValue);
1033     code = RegQueryValueEx(parmKey, "UnixModeDirDefault", NULL, NULL,
1034                            (BYTE *) &dwValue, &dummyLen);
1035     if (code == ERROR_SUCCESS) {
1036         smb_unixModeDefaultDir = (dwValue & 07777);
1037     }
1038     afsi_log("Default unix mode bits for directories is 0%04o", smb_unixModeDefaultDir);
1039
1040     dummyLen = sizeof(smb_maxMpxRequests);
1041     code = RegQueryValueEx(parmKey, "MaxMpxRequests", NULL, NULL,
1042                            (BYTE *) &smb_maxMpxRequests, &dummyLen);
1043     if (code != ERROR_SUCCESS) {
1044         smb_maxMpxRequests = 50;
1045     }
1046     afsi_log("Maximum number of multiplexed sessions is %d", smb_maxMpxRequests);
1047
1048     dummyLen = sizeof(smb_maxVCPerServer);
1049     code = RegQueryValueEx(parmKey, "MaxVCPerServer", NULL, NULL,
1050                            (BYTE *) &smb_maxVCPerServer, &dummyLen);
1051     if (code != ERROR_SUCCESS) {
1052         smb_maxVCPerServer = 100;
1053     }
1054     afsi_log("Maximum number of VCs per server is %d", smb_maxVCPerServer);
1055
1056     dummyLen = sizeof(smb_authType);
1057     code = RegQueryValueEx(parmKey, "SMBAuthType", NULL, NULL,
1058                             (BYTE *) &smb_authType, &dummyLen);
1059
1060     if (code != ERROR_SUCCESS ||
1061          (smb_authType != SMB_AUTH_EXTENDED && smb_authType != SMB_AUTH_NTLM && smb_authType != SMB_AUTH_NONE)) {
1062         smb_authType = SMB_AUTH_EXTENDED; /* default is to use extended authentication */
1063     }
1064     afsi_log("SMB authentication type is %s", ((smb_authType == SMB_AUTH_NONE)?"NONE":((smb_authType == SMB_AUTH_EXTENDED)?"EXTENDED":"NTLM")));
1065
1066     dummyLen = sizeof(rx_max_rwin_size);
1067     code = RegQueryValueEx(parmKey, "RxMaxRecvWinSize", NULL, NULL,
1068                            (BYTE *) &rx_max_rwin_size, &dummyLen);
1069     if (code == ERROR_SUCCESS)
1070         rx_SetMaxReceiveWindow(rx_max_rwin_size);
1071     afsi_log("Rx Maximum Receive Window Size is %d", rx_GetMaxReceiveWindow());
1072
1073     dummyLen = sizeof(rx_max_swin_size);
1074     code = RegQueryValueEx(parmKey, "RxMaxSendWinSize", NULL, NULL,
1075                            (BYTE *) &rx_max_swin_size, &dummyLen);
1076     if (code == ERROR_SUCCESS)
1077         rx_SetMaxSendWindow(rx_max_swin_size);
1078     afsi_log("Rx Maximum Send Window Size is %d", rx_GetMaxSendWindow());
1079
1080     dummyLen = sizeof(rx_min_peer_timeout);
1081     code = RegQueryValueEx(parmKey, "RxMinPeerTimeout", NULL, NULL,
1082                            (BYTE *) &rx_min_peer_timeout, &dummyLen);
1083     if (code == ERROR_SUCCESS)
1084         rx_SetMinPeerTimeout(rx_min_peer_timeout);
1085     afsi_log("Rx Minimum Peer Timeout is %d ms", rx_GetMinPeerTimeout());
1086
1087     dummyLen = sizeof(rx_pmtu_discovery);
1088     code = RegQueryValueEx(parmKey, "RxPMTUDiscovery", NULL, NULL,
1089                            (BYTE *) &rx_pmtu_discovery, &dummyLen);
1090     afsi_log("Rx PMTU Discovery is %d ms", rx_pmtu_discovery);
1091
1092     dummyLen = sizeof(rx_nojumbo);
1093     code = RegQueryValueEx(parmKey, "RxNoJumbo", NULL, NULL,
1094                            (BYTE *) &rx_nojumbo, &dummyLen);
1095     if (code != ERROR_SUCCESS) {
1096         DWORD jumbo;
1097         dummyLen = sizeof(jumbo);
1098         code = RegQueryValueEx(parmKey, "RxJumbo", NULL, NULL,
1099                                 (BYTE *) &jumbo, &dummyLen);
1100         if (code != ERROR_SUCCESS) {
1101             rx_nojumbo = 1;
1102         } else {
1103             rx_nojumbo = !jumbo;
1104         }
1105     }
1106     if (rx_nojumbo)
1107         afsi_log("RX Jumbograms are disabled");
1108     else
1109         afsi_log("RX Jumbograms are enabled");
1110
1111     dummyLen = sizeof(rx_extraPackets);
1112     code = RegQueryValueEx(parmKey, "RxExtraPackets", NULL, NULL,
1113                            (BYTE *) &rx_extraPackets, &dummyLen);
1114     if (code != ERROR_SUCCESS) {
1115         rx_extraPackets = (numBkgD + numSvThreads + 5) * 64;
1116     }
1117     if (rx_extraPackets)
1118         afsi_log("RX extraPackets is %d", rx_extraPackets);
1119
1120     dummyLen = sizeof(rx_udpbufsize);
1121     code = RegQueryValueEx(parmKey, "RxUdpBufSize", NULL, NULL,
1122                            (BYTE *) &rx_udpbufsize, &dummyLen);
1123     if (code != ERROR_SUCCESS) {
1124         rx_udpbufsize = 256*1024;
1125     }
1126     if (rx_udpbufsize != -1)
1127         afsi_log("RX udpbufsize is %d", rx_udpbufsize);
1128
1129     dummyLen = sizeof(rx_mtu);
1130     code = RegQueryValueEx(parmKey, "RxMaxMTU", NULL, NULL,
1131                            (BYTE *) &rx_mtu, &dummyLen);
1132     if (code != ERROR_SUCCESS || !rx_mtu) {
1133         rx_mtu = -1;
1134     }
1135     if (rx_mtu != -1)
1136         afsi_log("RX maximum MTU is %d", rx_mtu);
1137
1138     dummyLen = sizeof(rx_enable_peer_stats);
1139     code = RegQueryValueEx(parmKey, "RxEnablePeerStats", NULL, NULL,
1140                            (BYTE *) &rx_enable_peer_stats, &dummyLen);
1141     if (code != ERROR_SUCCESS) {
1142         rx_enable_peer_stats = 1;
1143     }
1144     if (rx_enable_peer_stats)
1145         afsi_log("RX Peer Statistics gathering is enabled");
1146     else
1147         afsi_log("RX Peer Statistics gathering is disabled");
1148
1149     dummyLen = sizeof(rx_enable_process_stats);
1150     code = RegQueryValueEx(parmKey, "RxEnableProcessStats", NULL, NULL,
1151                            (BYTE *) &rx_enable_process_stats, &dummyLen);
1152     if (code != ERROR_SUCCESS) {
1153         rx_enable_process_stats = 1;
1154     }
1155     if (rx_enable_process_stats)
1156         afsi_log("RX Process Statistics gathering is enabled");
1157     else
1158         afsi_log("RX Process Statistics gathering is disabled");
1159
1160     dummyLen = sizeof(dwValue);
1161     dwValue = 0;
1162     code = RegQueryValueEx(parmKey, "RxEnableHotThread", NULL, NULL,
1163                             (BYTE *) &dwValue, &dummyLen);
1164      if (code != ERROR_SUCCESS || dwValue != 0) {
1165          rx_EnableHotThread();
1166          afsi_log("RX Hot Thread is enabled");
1167      }
1168      else
1169          afsi_log("RX Hot Thread is disabled");
1170
1171     dummyLen = sizeof(DWORD);
1172     code = RegQueryValueEx(parmKey, "CallBackPort", NULL, NULL,
1173                            (BYTE *) &dwValue, &dummyLen);
1174     if (code == ERROR_SUCCESS) {
1175         cm_callbackport = (unsigned short) dwValue;
1176     }
1177     afsi_log("CM CallBackPort is %u", cm_callbackport);
1178
1179     dummyLen = sizeof(DWORD);
1180     code = RegQueryValueEx(parmKey, "EnableServerLocks", NULL, NULL,
1181                            (BYTE *) &dwValue, &dummyLen);
1182     if (code == ERROR_SUCCESS) {
1183         cm_enableServerLocks = (unsigned short) dwValue;
1184     }
1185     switch (cm_enableServerLocks) {
1186     case 0:
1187         afsi_log("EnableServerLocks: never");
1188         break;
1189     case 2:
1190         afsi_log("EnableServerLocks: always");
1191         break;
1192     case 1:
1193     default:
1194         afsi_log("EnableServerLocks: server requested");
1195         break;
1196     }
1197
1198     dummyLen = sizeof(DWORD);
1199     code = RegQueryValueEx(parmKey, "DeleteReadOnly", NULL, NULL,
1200                            (BYTE *) &dwValue, &dummyLen);
1201     if (code == ERROR_SUCCESS) {
1202         cm_deleteReadOnly = (unsigned short) dwValue;
1203     }
1204     afsi_log("CM DeleteReadOnly is %u", cm_deleteReadOnly);
1205
1206 #ifdef USE_BPLUS
1207     dummyLen = sizeof(DWORD);
1208     code = RegQueryValueEx(parmKey, "BPlusTrees", NULL, NULL,
1209                            (BYTE *) &dwValue, &dummyLen);
1210     if (code == ERROR_SUCCESS) {
1211         cm_BPlusTrees = (unsigned short) dwValue;
1212     }
1213     afsi_log("CM BPlusTrees is %u", cm_BPlusTrees);
1214
1215     if (cm_BPlusTrees && !cm_InitBPlusDir()) {
1216         cm_BPlusTrees = 0;
1217         afsi_log("CM BPlusTree initialization failure; disabled for this session");
1218     }
1219 #else
1220     afsi_log("CM BPlusTrees is not supported");
1221 #endif
1222
1223     if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0,
1224                            &regType, NULL, &dummyLen) == ERROR_SUCCESS) &&
1225          (regType == REG_MULTI_SZ))
1226     {
1227         clientchar_t * pSz;
1228         dummyLen += 3; /* in case the source string is not nul terminated */
1229         pSz = malloc(dummyLen);
1230         if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0, &regType,
1231                                (LPBYTE) pSz, &dummyLen) == ERROR_SUCCESS) &&
1232              (regType == REG_MULTI_SZ))
1233         {
1234             int cnt;
1235             clientchar_t * p;
1236
1237             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1);
1238
1239             smb_ExecutableExtensions = malloc(sizeof(clientchar_t *) * (cnt+1));
1240
1241             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1) {
1242                 smb_ExecutableExtensions[cnt] = p;
1243                 afsi_log("PrefetchExecutableExtension: \"%S\"", p);
1244             }
1245             smb_ExecutableExtensions[cnt] = NULL;
1246         }
1247
1248         if (!smb_ExecutableExtensions)
1249             free(pSz);
1250     }
1251     if (!smb_ExecutableExtensions)
1252         afsi_log("No PrefetchExecutableExtensions");
1253
1254     dummyLen = sizeof(DWORD);
1255     code = RegQueryValueEx(parmKey, "OfflineReadOnlyIsValid", NULL, NULL,
1256                            (BYTE *) &dwValue, &dummyLen);
1257     if (code == ERROR_SUCCESS) {
1258         cm_OfflineROIsValid = (unsigned short) dwValue;
1259     }
1260     afsi_log("CM OfflineReadOnlyIsValid is %u", cm_OfflineROIsValid);
1261
1262     dummyLen = sizeof(DWORD);
1263     code = RegQueryValueEx(parmKey, "GiveUpAllCallBacks", NULL, NULL,
1264                            (BYTE *) &dwValue, &dummyLen);
1265     if (code == ERROR_SUCCESS) {
1266         cm_giveUpAllCBs = (unsigned short) dwValue;
1267     }
1268     afsi_log("CM GiveUpAllCallBacks is %u", cm_giveUpAllCBs);
1269
1270     dummyLen = sizeof(DWORD);
1271     code = RegQueryValueEx(parmKey, "FollowBackupPath", NULL, NULL,
1272                            (BYTE *) &dwValue, &dummyLen);
1273     if (code == ERROR_SUCCESS) {
1274         cm_followBackupPath = (unsigned short) dwValue;
1275     }
1276     afsi_log("CM FollowBackupPath is %u", cm_followBackupPath);
1277
1278     dummyLen = sizeof(DWORD);
1279     code = RegQueryValueEx(parmKey, "PerFileAccessCheck", NULL, NULL,
1280                            (BYTE *) &dwValue, &dummyLen);
1281     if (code == ERROR_SUCCESS) {
1282         cm_accessPerFileCheck = (int) dwValue;
1283     }
1284     afsi_log("CM PerFileAccessCheck is %d", cm_accessPerFileCheck);
1285
1286     dummyLen = sizeof(DWORD);
1287     code = RegQueryValueEx(parmKey, "ReadOnlyVolumeVersioning", NULL, NULL,
1288                            (BYTE *) &dwValue, &dummyLen);
1289     if (code == ERROR_SUCCESS) {
1290         cm_readonlyVolumeVersioning = (unsigned short) dwValue;
1291     }
1292     afsi_log("CM ReadOnlyVolumeVersioning is %u", cm_readonlyVolumeVersioning);
1293
1294     RegCloseKey (parmKey);
1295
1296     cacheBlocks = ((afs_uint64)cacheSize * 1024) / blockSize;
1297
1298     /* get network related info */
1299     cm_noIPAddr = CM_MAXINTERFACE_ADDR;
1300     code = syscfg_GetIFInfo(&cm_noIPAddr,
1301                              cm_IPAddr, cm_SubnetMask,
1302                              cm_NetMtu, cm_NetFlags);
1303
1304     if ( (cm_noIPAddr <= 0) || (code <= 0 ) )
1305         afsi_log("syscfg_GetIFInfo error code %d", code);
1306     else
1307         afsi_log("First Network address %x SubnetMask %x",
1308                   cm_IPAddr[0], cm_SubnetMask[0]);
1309
1310     /*
1311      * Save client configuration for GetCacheConfig requests
1312      */
1313     cm_initParams.nChunkFiles = 0;
1314     cm_initParams.nStatCaches = stats;
1315     cm_initParams.nDataCaches = (afs_uint32)(cacheBlocks > 0xFFFFFFFF ? 0xFFFFFFFF : cacheBlocks);
1316     cm_initParams.nVolumeCaches = volumes;
1317     cm_initParams.firstChunkSize = cm_chunkSize;
1318     cm_initParams.otherChunkSize = cm_chunkSize;
1319     cm_initParams.cacheSize = cacheSize;
1320     cm_initParams.setTime = 0;
1321     cm_initParams.memCache = 1;
1322
1323     /* init user daemon, and other packages */
1324     cm_InitUser();
1325
1326     cm_InitConn();
1327
1328     cm_InitServer();
1329
1330     cm_InitIoctl();
1331
1332     smb_InitIoctl();
1333
1334     cm_InitCallback();
1335
1336     cm_InitNormalization();
1337
1338     code = cm_InitMappedMemory(cm_virtualCache, cm_CachePath, stats, volumes, cells, cm_chunkSize, cacheBlocks, blockSize);
1339     afsi_log("cm_InitMappedMemory code %x", code);
1340     if (code != 0) {
1341         *reasonP = "error initializing cache file";
1342         return -1;
1343     }
1344
1345 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
1346     if (cm_InitDNS(cm_dnsEnabled) == -1)
1347         cm_dnsEnabled = 0;  /* init failed, so deactivate */
1348     afsi_log("cm_InitDNS %d", cm_dnsEnabled);
1349 #endif
1350
1351     /* Set RX parameters before initializing RX */
1352     if ( rx_nojumbo ) {
1353         rx_SetNoJumbo();
1354         afsi_log("rx_SetNoJumbo successful");
1355     }
1356
1357     if ( rx_mtu != -1 ) {
1358         extern void rx_SetMaxMTU(int);
1359
1360         rx_SetMaxMTU(rx_mtu);
1361         afsi_log("rx_SetMaxMTU %d successful", rx_mtu);
1362     }
1363
1364     if ( rx_udpbufsize != -1 ) {
1365         rx_SetUdpBufSize(rx_udpbufsize);
1366         afsi_log("rx_SetUdpBufSize %d", rx_udpbufsize);
1367     }
1368
1369     rx_SetBusyChannelError(CM_RX_RETRY_BUSY_CALL);
1370
1371     /* initialize RX, and tell it to listen to the callbackport,
1372      * which is used for callback RPC messages.
1373      */
1374     code = rx_Init(htons(cm_callbackport));
1375     if (code != 0) {
1376         afsi_log("rx_Init code %x - retrying with a random port number", code);
1377         code = rx_Init(0);
1378     }
1379     afsi_log("rx_Init code %x", code);
1380     if (code != 0) {
1381         *reasonP = "afsd: failed to init rx client";
1382         return -1;
1383     }
1384
1385     /* create an unauthenticated service #1 for callbacks */
1386     nullServerSecurityClassp = rxnull_NewServerSecurityObject();
1387     serverp = rx_NewService(0, 1, "AFS", &nullServerSecurityClassp, 1,
1388                              RXAFSCB_ExecuteRequest);
1389     afsi_log("rx_NewService addr %x", PtrToUlong(serverp));
1390     if (serverp == NULL) {
1391         *reasonP = "unknown error";
1392         return -1;
1393     }
1394     rx_SetMinProcs(serverp, 2);
1395     rx_SetMaxProcs(serverp, 4);
1396     rx_SetCheckReach(serverp, 1);
1397
1398     nullServerSecurityClassp = rxnull_NewServerSecurityObject();
1399     serverp = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats",
1400                              &nullServerSecurityClassp, 1, RXSTATS_ExecuteRequest);
1401     afsi_log("rx_NewService addr %x", PtrToUlong(serverp));
1402     if (serverp == NULL) {
1403         *reasonP = "unknown error";
1404         return -1;
1405     }
1406     rx_SetMinProcs(serverp, 2);
1407     rx_SetMaxProcs(serverp, 4);
1408
1409     /* start server threads, *not* donating this one to the pool */
1410     rx_StartServer(0);
1411     afsi_log("rx_StartServer");
1412
1413     if (rx_enable_peer_stats)
1414         rx_enablePeerRPCStats();
1415
1416     if (rx_enable_process_stats)
1417         rx_enableProcessRPCStats();
1418
1419     code = cm_GetRootCellName(rootCellName);
1420     afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s",
1421              code, cm_freelanceEnabled, (code ? "<none>" : rootCellName));
1422     if (code != 0 && !cm_freelanceEnabled)
1423     {
1424         *reasonP = "can't find root cell name in " AFS_CELLSERVDB;
1425         return -1;
1426     }
1427     else if (cm_freelanceEnabled)
1428         cm_data.rootCellp = NULL;
1429
1430     if (code == 0 && !cm_freelanceEnabled)
1431     {
1432         cm_data.rootCellp = cm_GetCell(rootCellName, CM_FLAG_CREATE);
1433         afsi_log("cm_GetCell addr %x", PtrToUlong(cm_data.rootCellp));
1434         if (cm_data.rootCellp == NULL)
1435         {
1436             *reasonP = "can't find root cell in " AFS_CELLSERVDB;
1437             return -1;
1438         }
1439     }
1440
1441 #ifdef AFS_FREELANCE_CLIENT
1442     if (cm_freelanceEnabled)
1443         cm_InitFreelance();
1444 #endif
1445
1446     /* Initialize the RPC server for session keys */
1447     RpcInit();
1448
1449     /* Initialize the RPC server for pipe services */
1450     MSRPC_Init();
1451
1452     afsd_InitServerPreferences();
1453
1454     code = afsd_InitRoot(reasonP);
1455
1456     return code;
1457 }
1458
1459 int afsd_ShutdownCM(void)
1460 {
1461     MSRPC_Shutdown();
1462
1463     cm_ReleaseSCache(cm_data.rootSCachep);
1464
1465     cm_utilsCleanup();
1466
1467     cm_shutdown = 1;
1468
1469     return 0;
1470 }
1471
1472 int afsd_InitDaemons(char **reasonP)
1473 {
1474     cm_InitDaemon(numBkgD);
1475     afsi_log("cm_InitDaemon complete");
1476
1477     return 0;
1478 }
1479
1480 int afsd_InitSMB(char **reasonP, void *aMBfunc)
1481 {
1482     HKEY parmKey;
1483     DWORD dummyLen;
1484     DWORD dwValue;
1485     DWORD code;
1486
1487     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
1488                          0, KEY_QUERY_VALUE, &parmKey);
1489     if (code == ERROR_SUCCESS) {
1490         dummyLen = sizeof(DWORD);
1491         code = RegQueryValueEx(parmKey, "StoreAnsiFilenames", NULL, NULL,
1492                                 (BYTE *) &dwValue, &dummyLen);
1493         if (code == ERROR_SUCCESS)
1494             smb_StoreAnsiFilenames = dwValue ? 1 : 0;
1495         afsi_log("StoreAnsiFilenames = %d", smb_StoreAnsiFilenames);
1496
1497         dummyLen = sizeof(DWORD);
1498         code = RegQueryValueEx(parmKey, "EnableSMBAsyncStore", NULL, NULL,
1499                                 (BYTE *) &dwValue, &dummyLen);
1500         if (code == ERROR_SUCCESS)
1501             smb_AsyncStore = dwValue == 2 ? 2 : (dwValue ? 1 : 0);
1502         afsi_log("EnableSMBAsyncStore = %d", smb_AsyncStore);
1503
1504         dummyLen = sizeof(DWORD);
1505         code = RegQueryValueEx(parmKey, "SMBAsyncStoreSize", NULL, NULL,
1506                                 (BYTE *) &dwValue, &dummyLen);
1507         if (code == ERROR_SUCCESS) {
1508             /* Should check for >= blocksize && <= chunksize && round down to multiple of blocksize */
1509             if (dwValue > cm_chunkSize)
1510                 smb_AsyncStoreSize = cm_chunkSize;
1511             else if (dwValue <  cm_data.buf_blockSize)
1512                 smb_AsyncStoreSize = cm_data.buf_blockSize;
1513             else
1514                 smb_AsyncStoreSize = (dwValue & ~(cm_data.buf_blockSize-1));
1515         } else
1516             smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
1517         afsi_log("SMBAsyncStoreSize = %d", smb_AsyncStoreSize);
1518
1519         dummyLen = sizeof(DWORD);
1520         code = RegQueryValueEx(parmKey, "SMBInterfaceEnabled", NULL, NULL,
1521                                 (BYTE *) &dwValue, &dummyLen);
1522         if (code == ERROR_SUCCESS)
1523             smb_Enabled = dwValue ? 1 : 0;
1524         afsi_log("SMBInterfaceEnabled = %d", smb_Enabled);
1525
1526         RegCloseKey (parmKey);
1527     }
1528
1529     if ( smb_Enabled ) {
1530     /* Do this last so that we don't handle requests before init is done.
1531      * Here we initialize the SMB listener.
1532      */
1533     smb_Init(afsd_logp, smb_UseV3, numSvThreads, aMBfunc);
1534     afsi_log("smb_Init complete");
1535     } else {
1536         afsi_log("smb_Init skipped");
1537     }
1538
1539     return 0;
1540 }
1541
1542 #ifdef ReadOnly
1543 #undef ReadOnly
1544 #endif
1545
1546 #ifdef File
1547 #undef File
1548 #endif
1549
1550 #pragma pack( push, before_imagehlp, 8 )
1551 #include <imagehlp.h>
1552 #pragma pack( pop, before_imagehlp )
1553
1554 #define MAXNAMELEN 1024
1555
1556 void afsd_printStack(HANDLE hThread, CONTEXT *c)
1557 {
1558     HANDLE hProcess = GetCurrentProcess();
1559     int frameNum;
1560 #if defined(_AMD64_)
1561     DWORD64 offset;
1562 #elif defined(_X86_)
1563     DWORD offset;
1564 #endif
1565     DWORD symOptions;
1566     char functionName[MAXNAMELEN];
1567
1568     IMAGEHLP_MODULE Module;
1569     IMAGEHLP_LINE Line;
1570
1571     STACKFRAME s;
1572     IMAGEHLP_SYMBOL *pSym;
1573
1574     afsi_log_useTimestamp = 0;
1575
1576     pSym = (IMAGEHLP_SYMBOL *) GlobalAlloc(0, sizeof (IMAGEHLP_SYMBOL) + MAXNAMELEN);
1577
1578     memset( &s, '\0', sizeof s );
1579     if (!SymInitialize(hProcess, NULL, 1) )
1580     {
1581         afsi_log("SymInitialize(): GetLastError() = %lu\n", GetLastError() );
1582
1583         SymCleanup( hProcess );
1584         GlobalFree(pSym);
1585
1586         return;
1587     }
1588
1589     symOptions = SymGetOptions();
1590     symOptions |= SYMOPT_LOAD_LINES;
1591     symOptions &= ~SYMOPT_UNDNAME;
1592     SymSetOptions( symOptions );
1593
1594     /*
1595      * init STACKFRAME for first call
1596      * Notes: AddrModeFlat is just an assumption. I hate VDM debugging.
1597      * Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway,
1598      * and good riddance.
1599      */
1600 #if defined (_ALPHA_) || defined (_MIPS_) || defined (_PPC_)
1601 #error The STACKFRAME initialization in afsd_printStack() for this platform
1602 #error must be properly configured
1603 #elif defined(_AMD64_)
1604     s.AddrPC.Offset = c->Rip;
1605     s.AddrPC.Mode = AddrModeFlat;
1606     s.AddrFrame.Offset = c->Rbp;
1607     s.AddrFrame.Mode = AddrModeFlat;
1608 #else
1609     s.AddrPC.Offset = c->Eip;
1610     s.AddrPC.Mode = AddrModeFlat;
1611     s.AddrFrame.Offset = c->Ebp;
1612     s.AddrFrame.Mode = AddrModeFlat;
1613 #endif
1614
1615     memset( pSym, '\0', sizeof (IMAGEHLP_SYMBOL) + MAXNAMELEN );
1616     pSym->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL);
1617     pSym->MaxNameLength = MAXNAMELEN;
1618
1619     memset( &Line, '\0', sizeof Line );
1620     Line.SizeOfStruct = sizeof Line;
1621
1622     memset( &Module, '\0', sizeof Module );
1623     Module.SizeOfStruct = sizeof Module;
1624
1625     offset = 0;
1626
1627     afsi_log("\n--# FV EIP----- RetAddr- FramePtr StackPtr Symbol" );
1628
1629     for ( frameNum = 0; ; ++ frameNum )
1630     {
1631         /*
1632          * get next stack frame (StackWalk(), SymFunctionTableAccess(),
1633          * SymGetModuleBase()). if this returns ERROR_INVALID_ADDRESS (487) or
1634          * ERROR_NOACCESS (998), you can assume that either you are done, or
1635          * that the stack is so hosed that the next deeper frame could not be
1636          * found.
1637          */
1638         if ( ! StackWalk( IMAGE_FILE_MACHINE_I386, hProcess, hThread, &s, c,
1639                           NULL, SymFunctionTableAccess, SymGetModuleBase,
1640                           NULL ) )
1641             break;
1642
1643         /* display its contents */
1644         afsi_log("\n%3d %c%c %08lx %08lx %08lx %08lx ",
1645                  frameNum, s.Far? 'F': '.', s.Virtual? 'V': '.',
1646                  s.AddrPC.Offset, s.AddrReturn.Offset,
1647                  s.AddrFrame.Offset, s.AddrStack.Offset );
1648
1649         if ( s.AddrPC.Offset == 0 )
1650         {
1651             afsi_log("(-nosymbols- PC == 0)" );
1652         }
1653         else
1654         {
1655             /* show procedure info from a valid PC */
1656             if (!SymGetSymFromAddr(hProcess, s.AddrPC.Offset, &offset, pSym))
1657             {
1658                 if ( GetLastError() != ERROR_INVALID_ADDRESS )
1659                 {
1660                     afsi_log("SymGetSymFromAddr(): errno = %lu",
1661                              GetLastError());
1662                 }
1663             }
1664             else
1665             {
1666                 UnDecorateSymbolName(pSym->Name, functionName, MAXNAMELEN,
1667                                      UNDNAME_NAME_ONLY);
1668                 afsi_log("%s", functionName );
1669
1670                 if ( offset != 0 )
1671                 {
1672                     afsi_log(" %+ld bytes", (long) offset);
1673                 }
1674             }
1675
1676             if (!SymGetLineFromAddr(hProcess, s.AddrPC.Offset, &offset, &Line))
1677             {
1678                 if (GetLastError() != ERROR_INVALID_ADDRESS)
1679                 {
1680                     afsi_log("Error: SymGetLineFromAddr(): errno = %lu",
1681                              GetLastError());
1682                 }
1683             }
1684             else
1685             {
1686                 afsi_log("    Line: %s(%lu) %+ld bytes", Line.FileName,
1687                          Line.LineNumber, offset);
1688             }
1689         }
1690
1691         /* no return address means no deeper stackframe */
1692         if (s.AddrReturn.Offset == 0)
1693         {
1694             SetLastError(0);
1695             break;
1696         }
1697     }
1698
1699     if (GetLastError() != 0)
1700     {
1701         afsi_log("\nStackWalk(): errno = %lu\n", GetLastError());
1702     }
1703
1704     SymCleanup(hProcess);
1705     GlobalFree(pSym);
1706 }
1707
1708 #ifdef _DEBUG
1709 static DWORD *afsd_crtDbgBreakCurrent = NULL;
1710 static DWORD afsd_crtDbgBreaks[256];
1711 #endif
1712
1713 static EFaultRepRetVal (WINAPI *pReportFault)(LPEXCEPTION_POINTERS pep, DWORD dwMode) = NULL;
1714 static BOOL (WINAPI *pMiniDumpWriteDump)(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,
1715                                   MINIDUMP_TYPE DumpType,
1716                                   PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
1717                                   PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
1718                                   PMINIDUMP_CALLBACK_INFORMATION CallbackParam) = NULL;
1719
1720
1721 static HANDLE
1722 OpenDumpFile(void)
1723 {
1724     char tmp[256];
1725     char wd[256];
1726     SYSTEMTIME st;
1727     DWORD code;
1728
1729     code = GetEnvironmentVariable("TEMP", tmp, sizeof(tmp));
1730     if ( code == 0 || code > sizeof(tmp) )
1731     {
1732         if (!GetWindowsDirectory(tmp, sizeof(tmp)))
1733             return NULL;
1734     }
1735     GetLocalTime(&st);
1736     StringCbPrintfA(wd, sizeof(wd),
1737                     "%s\\afsd-%04d-%02d-%02d-%02d_%02d_%02d.dmp", tmp,
1738                     st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
1739     return CreateFile( wd, GENERIC_WRITE, FILE_SHARE_READ, NULL,
1740                             CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
1741 }
1742
1743 void
1744 GenerateMiniDump(PEXCEPTION_POINTERS ep)
1745 {
1746     if (IsDebuggerPresent())
1747         return;
1748
1749     if (ep == NULL)
1750     {
1751         // Generate exception to get proper context in dump
1752         __try
1753         {
1754             RaiseException(DBG_CONTINUE, 0, 0, NULL);
1755         }
1756         __except(GenerateMiniDump(GetExceptionInformation()), EXCEPTION_CONTINUE_EXECUTION)
1757         {
1758         }
1759     }
1760     else
1761     {
1762         MINIDUMP_EXCEPTION_INFORMATION eInfo;
1763         HANDLE hFile = NULL;
1764         HMODULE hDbgHelp = NULL;
1765
1766         hDbgHelp = LoadLibrary("Dbghelp.dll");
1767         if ( hDbgHelp == NULL )
1768             return;
1769
1770         (FARPROC) pMiniDumpWriteDump = GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
1771         if ( pMiniDumpWriteDump == NULL ) {
1772             FreeLibrary(hDbgHelp);
1773             return;
1774         }
1775
1776         hFile = OpenDumpFile();
1777
1778         if ( hFile ) {
1779             HKEY parmKey;
1780             DWORD dummyLen;
1781             DWORD dwValue;
1782             DWORD code;
1783             DWORD dwMiniDumpType = MiniDumpWithDataSegs;
1784
1785             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
1786                                  0, KEY_QUERY_VALUE, &parmKey);
1787             if (code == ERROR_SUCCESS) {
1788                 dummyLen = sizeof(DWORD);
1789                 code = RegQueryValueEx(parmKey, "MiniDumpType", NULL, NULL,
1790                                         (BYTE *) &dwValue, &dummyLen);
1791                 if (code == ERROR_SUCCESS)
1792                     dwMiniDumpType = dwValue;
1793                 RegCloseKey (parmKey);
1794             }
1795
1796             eInfo.ThreadId = GetCurrentThreadId();
1797             eInfo.ExceptionPointers = ep;
1798             eInfo.ClientPointers = FALSE;
1799
1800             pMiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
1801                                 hFile, dwMiniDumpType, ep ? &eInfo : NULL,
1802                                 NULL, NULL);
1803
1804             CloseHandle(hFile);
1805         }
1806         FreeLibrary(hDbgHelp);
1807     }
1808 }
1809
1810 LONG __stdcall afsd_ExceptionFilter(EXCEPTION_POINTERS *ep)
1811 {
1812     CONTEXT context;
1813 #ifdef _DEBUG
1814     BOOL allocRequestBrk = FALSE;
1815 #endif
1816     HMODULE hLib = NULL;
1817
1818     afsi_log("UnhandledException : code : 0x%x, address: 0x%x\n",
1819              ep->ExceptionRecord->ExceptionCode,
1820              ep->ExceptionRecord->ExceptionAddress);
1821
1822 #ifdef _DEBUG
1823     if (afsd_crtDbgBreakCurrent &&
1824         *afsd_crtDbgBreakCurrent == _CrtSetBreakAlloc(*afsd_crtDbgBreakCurrent))
1825     {
1826         allocRequestBrk = TRUE;
1827         afsi_log("Breaking on alloc request # %d\n", *afsd_crtDbgBreakCurrent);
1828     }
1829 #endif
1830
1831     /* save context if we want to print the stack information */
1832     context = *ep->ContextRecord;
1833
1834     afsd_printStack(GetCurrentThread(), &context);
1835
1836     GenerateMiniDump(ep);
1837
1838     hLib = LoadLibrary("Faultrep.dll");
1839     if ( hLib ) {
1840         (FARPROC) pReportFault = GetProcAddress(hLib, "ReportFault");
1841         if ( pReportFault )
1842             pReportFault(ep, 0);
1843         FreeLibrary(hLib);
1844     }
1845
1846     if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
1847     {
1848         afsi_log("\nEXCEPTION_BREAKPOINT - continue execution ...\n");
1849
1850 #ifdef _DEBUG
1851         if (allocRequestBrk)
1852         {
1853             afsd_crtDbgBreakCurrent++;
1854             _CrtSetBreakAlloc(*afsd_crtDbgBreakCurrent);
1855         }
1856 #endif
1857 #if defined(_X86)
1858         ep->ContextRecord->Eip++;
1859 #endif
1860 #if defined(_AMD64_)
1861         ep->ContextRecord->Rip++;
1862 #endif
1863         return EXCEPTION_CONTINUE_EXECUTION;
1864     }
1865     else
1866     {
1867         return EXCEPTION_CONTINUE_SEARCH;
1868     }
1869 }
1870
1871 void afsd_SetUnhandledExceptionFilter()
1872 {
1873 #ifndef NOTRACE
1874     SetUnhandledExceptionFilter(afsd_ExceptionFilter);
1875 #endif
1876 }
1877
1878 #ifdef _DEBUG
1879 void afsd_DbgBreakAllocInit()
1880 {
1881     memset(afsd_crtDbgBreaks, -1, sizeof(afsd_crtDbgBreaks));
1882     afsd_crtDbgBreakCurrent = afsd_crtDbgBreaks;
1883 }
1884
1885 void afsd_DbgBreakAdd(DWORD requestNumber)
1886 {
1887     int i;
1888     for (i = 0; i < sizeof(afsd_crtDbgBreaks) - 1; i++)
1889         {
1890         if (afsd_crtDbgBreaks[i] == -1)
1891             {
1892             break;
1893             }
1894         }
1895     afsd_crtDbgBreaks[i] = requestNumber;
1896
1897     _CrtSetBreakAlloc(afsd_crtDbgBreaks[0]);
1898 }
1899 #endif