25672c5a748c7b5dc14bcdd22fae94c9817f3027
[openafs.git] / src / WINNT / afsd / cm_config.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 #include <afs/cellconfig.h>
13
14 #ifndef DJGPP
15 #include <windows.h>
16 #include <winsock2.h>
17 #else
18 #include <sys/socket.h>
19 #include <netdb.h>
20 #endif /* !DJGPP */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "afsd.h"
26 #include <WINNT\afssw.h>
27 #include <WINNT\afsreg.h>
28 #ifdef AFS_AFSDB_ENV
29 #include "cm_dns.h"
30 #include <afs/afsint.h>
31 #endif
32
33 /* TODO: these should be pulled in from dirpath.h */
34 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
35 #define AFS_THISCELL "ThisCell"
36 #endif
37 #define AFS_CELLSERVDB_UNIX "CellServDB"
38 #define AFS_CELLSERVDB_NT "afsdcell.ini"
39 #ifndef AFSDIR_CLIENT_ETC_DIRPATH
40 #define AFSDIR_CLIENT_ETC_DIRPATH "c:/afs"
41 #endif
42 #if defined(DJGPP) || defined(AFS_WIN95_ENV)
43 #define AFS_CELLSERVDB AFS_CELLSERVDB_UNIX
44 #ifdef DJGPP
45 extern char cm_confDir[];
46 extern int errno;
47 #endif /* DJGPP */
48 #else
49 #define AFS_CELLSERVDB AFS_CELLSERVDB_UNIX
50 #endif /* DJGPP || WIN95 */
51
52 static DWORD TraceOption = 0;
53
54 /* This really needs to be initialized at DLL Init */
55 #define TRACE_OPTION_EVENT 4
56
57 #define ISCONFIGTRACE(v) ( ((v) & TRACE_OPTION_EVENT)==TRACE_OPTION_EVENT)
58
59 void DebugEvent0_local(char *a) 
60 {
61         HANDLE h; char *ptbuf[1];
62         if (!ISCONFIGTRACE(TraceOption))
63                 return;
64         h = RegisterEventSource(NULL, a);
65         ptbuf[0] = a;
66         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
67         DeregisterEventSource(h);
68 }
69
70 #define MAXBUF_ 512
71
72 void DebugEvent_local(char *a,char *b,...) 
73 {
74         HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
75         va_list marker;
76         if (!ISCONFIGTRACE(TraceOption))
77                 return;
78         h = RegisterEventSource(NULL, a);
79         va_start(marker,b);
80         _vsnprintf(buf,MAXBUF_,b,marker);
81         ptbuf[0] = buf;
82         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
83         DeregisterEventSource(h);
84         va_end(marker);
85 }
86
87 #define REG_CLIENT_PARMS_KEY            TEXT("SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters")
88 #define REG_CLIENT_TRACE_OPTION_PARM    TEXT("TraceOption")
89
90 #ifdef COMMENT
91 BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
92 {
93     switch (fdwReason)
94     {
95     case DLL_PROCESS_ATTACH: {
96         DWORD LSPtype, LSPsize;
97         HKEY NPKey;
98
99         (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
100                              0, KEY_QUERY_VALUE, &NPKey);
101         LSPsize=sizeof(TraceOption);
102         RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
103                         &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
104
105         RegCloseKey (NPKey);
106         break;
107     }
108
109     case DLL_THREAD_ATTACH:
110         break;
111
112     case DLL_THREAD_DETACH:
113         break;
114
115     case DLL_PROCESS_DETACH:
116         break;
117
118     default:
119         return FALSE;
120     }
121
122     return TRUE;   // successful DLL_PROCESS_ATTACH
123 }
124 #endif /* COMMENT */
125
126 static long cm_ParsePair(char *lineBufferp, char *leftp, char *rightp)
127 {
128         char *tp;
129     char tc;
130     int sawEquals;
131         int sawBracket;
132         
133     sawEquals = 0;
134         sawBracket = 0;
135     for(tp = lineBufferp; *tp; tp++) {
136         tc = *tp;
137
138                 if (sawBracket) {
139                         if (tc == ']')
140                                 sawBracket = 0;
141                         continue;
142                 }
143
144                 /* comment or line end */
145         if (tc == '#' || tc == '\r' || tc == '\n') 
146             break;
147
148                 /* square bracket comment -- look for closing delim */
149                 if (tc == '[') {
150             sawBracket = 1; 
151             continue;
152         }
153
154                 /* space or tab */
155         if (tc == ' ' || tc == '\t') 
156             continue;
157
158         if (tc == '=') {
159             sawEquals = 1;
160             continue;
161                 }
162                 
163         /* now we have a real character, put it in the appropriate bucket */
164         if (sawEquals == 0) {
165                         *leftp++ = tc;
166         }
167         else {
168                         *rightp++ = tc;
169         }
170     }
171
172         /* null terminate the strings */
173         *leftp = 0;
174     *rightp = 0;
175
176     return 0;   /* and return success */
177 }
178
179 /* search for a cell, and either return an error code if we don't find it,
180  * or return 0 if we do, in which case we also fill in the addresses in
181  * the cellp field.
182  *
183  * new feature:  we can handle abbreviations and are insensitive to case.
184  * If the caller wants the "real" cell name, it puts a non-null pointer in
185  * newCellNamep.  Anomaly:  if cellNamep is ambiguous, we may modify
186  * newCellNamep but return an error code.
187  */
188 long cm_SearchCellFile(char *cellNamep, char *newCellNamep,
189                        cm_configProc_t *procp, void *rockp)
190 {
191     char wdir[257];
192     FILE *tfilep = NULL, *bestp, *tempp;
193     char *tp;
194     char lineBuffer[257];
195     struct hostent *thp;
196     char *valuep;
197     struct sockaddr_in vlSockAddr;
198     int inRightCell;
199     int foundCell = 0;
200     long code;
201         int tracking = 1, partial = 0;
202 #if defined(DJGPP) || defined(AFS_WIN95_ENV)
203     char *afsconf_path;
204 #endif
205
206     cm_GetCellServDB(wdir);
207     tfilep = fopen(wdir, "r");
208
209 #if defined(DJGPP) || defined(AFS_WIN95_ENV)
210     if (!tfilep) {
211         /* If we are using DJGPP client, cellservdb will be in afsconf dir. */
212         /* If we are in Win95 here, we are linking with klog etc. and are
213         using DJGPP client even though DJGPP is not defined.  So we still
214         need to check AFSCONF for location. */
215         afsconf_path = getenv("AFSCONF");
216         if (!afsconf_path)
217             strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
218         else
219             strcpy(wdir, afsconf_path);
220         strcat(wdir, "/");
221         strcat(wdir, AFS_CELLSERVDB);
222         /*fprintf(stderr, "opening cellservdb file %s\n", wdir);*/
223         tfilep = fopen(wdir, "r");
224         if (!tfilep) return -2;
225     }
226 #else
227     /* If we are NT or higher, we don't do DJGPP, So just fail */
228     if ( !tfilep )
229         return -2;
230 #endif
231
232         bestp = fopen(wdir, "r");
233     
234 #ifdef DEBUG
235     DebugEvent_local("AFS- cm_searchfile fopen", "Handle[%x], wdir[%s]", bestp, wdir);
236 #endif
237
238         /* have we seen the cell line for the guy we're looking for? */
239         inRightCell = 0;
240         while (1) {
241         tp = fgets(lineBuffer, sizeof(lineBuffer), tfilep);
242         if (tracking)
243                         (void) fgets(lineBuffer, sizeof(lineBuffer), bestp);
244         if (tp == NULL) {
245                         if (feof(tfilep)) {
246                                 /* hit EOF */
247                                 if (partial) {
248                                         /*
249                                          * found partial match earlier;
250                                          * now go back to it
251                                          */
252                                         tempp = bestp;
253                                         bestp = tfilep;
254                                         tfilep = tempp;
255                                         inRightCell = 1;
256                                         partial = 0;
257                                         continue;
258                                 }
259                                 else {
260                                         fclose(tfilep);
261                                         fclose(bestp);
262                                         return (foundCell? 0 : -3);
263                                 }
264                         }
265         }
266
267         /* turn trailing cr or lf into null */
268         tp = strchr(lineBuffer, '\r');
269         if (tp) *tp = 0;
270         tp = strchr(lineBuffer, '\n');
271         if (tp) *tp = 0;
272
273                 /* skip blank lines */
274         if (lineBuffer[0] == 0) continue;
275
276         if (lineBuffer[0] == '>') {
277                         /* trim off at white space or '#' chars */
278             tp = strchr(lineBuffer, ' ');
279             if (tp) *tp = 0;
280             tp = strchr(lineBuffer, '\t');
281             if (tp) *tp = 0;
282             tp = strchr(lineBuffer, '#');
283             if (tp) *tp = 0;
284
285                         /* now see if this is the right cell */
286             if (stricmp(lineBuffer+1, cellNamep) == 0) {
287                                 /* found the cell we're looking for */
288                                 if (newCellNamep)
289                                         strcpy(newCellNamep, lineBuffer+1);
290                 inRightCell = 1;
291                                 tracking = 0;
292 #ifdef DEBUG
293                 DebugEvent_local("AFS- cm_searchfile is cell", "inRightCell[%x], linebuffer[%s]", 
294                                  inRightCell, lineBuffer);
295 #endif
296                         }
297                         else if (strnicmp(lineBuffer+1, cellNamep,
298                                strlen(cellNamep)) == 0) {
299                                 /* partial match */
300                                 if (partial) {  /* ambiguous */
301                                         fclose(tfilep);
302                                         fclose(bestp);
303                                         return -5;
304                                 }
305                                 if (newCellNamep)
306                                         strcpy(newCellNamep, lineBuffer+1);
307                                 inRightCell = 0;
308                                 tracking = 0;
309                                 partial = 1;
310                         }
311             else inRightCell = 0;
312         }
313         else {
314 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
315             valuep = strchr(lineBuffer, '#');
316                         if (valuep == NULL) {
317                                 fclose(tfilep);
318                                 fclose(bestp);
319                                 return -4;
320                         }
321             valuep++;   /* skip the "#" */
322
323             valuep += strspn(valuep, " \t"); /* skip SP & TAB */
324             /* strip spaces and tabs in the end. They should not be there according to CellServDB format
325             so do this just in case                        */
326             while (valuep[strlen(valuep) - 1] == ' ' || valuep[strlen(valuep) - 1] == '\t') 
327                 valuep[strlen(valuep) - 1] = '\0';
328
329 #endif /* !DJGPP */
330                         if (inRightCell) {
331 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
332                                 /* add the server to the VLDB list */
333                 WSASetLastError(0);
334                 thp = gethostbyname(valuep);
335 #ifdef DEBUG
336                 {
337                     int iErr = WSAGetLastError();
338                     DebugEvent_local("AFS- cm_searchfile inRightCell", 
339                                      "thp[%x], valuep[%s], WSAGetLastError[%d]", 
340                                      thp, valuep, iErr);
341                 }
342 #endif
343                 if (thp) {
344                                         memcpy(&vlSockAddr.sin_addr.s_addr, thp->h_addr,
345                             sizeof(long));
346                     vlSockAddr.sin_family = AF_INET;
347                     /* sin_port supplied by connection code */
348                                         if (procp)
349                                                 (*procp)(rockp, &vlSockAddr, valuep);
350                     foundCell = 1;
351                                 }
352 #else
353                 thp = 0;
354 #endif /* !DJGPP */
355                 if (!thp) {
356                     long ip_addr;
357                                         int c1, c2, c3, c4;
358                                         char aname[241] = "";                    
359                     
360                     /* Since there is no gethostbyname() data 
361                      * available we will read the IP address
362                      * stored in the CellServDB file
363                      */
364                     code = sscanf(lineBuffer, "%d.%d.%d.%d #%s",
365                                    &c1, &c2, &c3, &c4, aname);
366                     tp = (char *) &ip_addr;
367                     *tp++ = c1;
368                     *tp++ = c2;
369                     *tp++ = c3;
370                     *tp++ = c4;
371                     memcpy(&vlSockAddr.sin_addr.s_addr, &ip_addr,
372                             sizeof(long));
373                     vlSockAddr.sin_family = AF_INET;
374                     /* sin_port supplied by connection code */
375                     if (procp)
376                         (*procp)(rockp, &vlSockAddr, valuep);
377                     foundCell = 1;
378                 }
379             }
380         }       /* a vldb line */
381     }           /* while loop processing all lines */
382
383     /* if for some unknown reason cell is not found, return negative code (-11) ??? */
384     return (foundCell) ? 0 : -11;
385 }
386
387 long cm_SearchCellByDNS(char *cellNamep, char *newCellNamep, int *ttl,
388                cm_configProc_t *procp, void *rockp)
389 {
390 #ifdef AFS_AFSDB_ENV
391     int rc;
392     int  cellHostAddrs[AFSMAXCELLHOSTS];
393     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
394     int numServers;
395     int i;
396     struct sockaddr_in vlSockAddr;
397
398 #ifdef DEBUG
399     DebugEvent_local("AFS SearchCellDNS-","Doing search for [%s]", cellNamep);
400 #endif
401     rc = getAFSServer(cellNamep, cellHostAddrs, cellHostNames, &numServers, ttl);
402     if (rc == 0 && numServers > 0) {     /* found the cell */
403         for (i = 0; i < numServers; i++) {
404             memcpy(&vlSockAddr.sin_addr.s_addr, &cellHostAddrs[i],
405                    sizeof(long));
406            vlSockAddr.sin_family = AF_INET;
407            /* sin_port supplied by connection code */
408            if (procp)
409           (*procp)(rockp, &vlSockAddr, cellHostNames[i]);
410            if(newCellNamep)
411           strcpy(newCellNamep,cellNamep);
412         }
413         return 0;   /* found cell */
414     }
415     else
416        return -1;  /* not found */
417 #else
418         return -1;  /* not found */
419 #endif /* AFS_AFSDB_ENV */
420 }
421
422 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
423 /* look up the CellServDBDir's name in the Registry 
424  * or use the Client Dirpath value to produce a CellServDB 
425  * filename
426  */
427 long cm_GetCellServDB(char *cellNamep)
428 {
429 #if !defined(DJGPP)
430         DWORD code, dummyLen;
431         HKEY parmKey;
432     int tlen;
433
434         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
435                                 0, KEY_QUERY_VALUE, &parmKey);
436         if (code != ERROR_SUCCESS)
437         goto dirpath;
438
439         dummyLen = 256;
440         code = RegQueryValueEx(parmKey, "CellServDBDir", NULL, NULL,
441                                 cellNamep, &dummyLen);
442         RegCloseKey (parmKey);
443
444   dirpath:
445         if (code != ERROR_SUCCESS || cellNamep[0] == 0)
446         strcpy(cellNamep, AFSDIR_CLIENT_ETC_DIRPATH);
447
448     /* add trailing backslash, if required */
449     tlen = strlen(cellNamep);
450     if (cellNamep[tlen-1] != '\\') 
451         strcat(cellNamep, "\\");
452 #else
453     strcpy(cellNamep, cm_confDir);
454     strcat(cellNamep,"/");
455 #endif /* !DJGPP */
456         
457     strcat(cellNamep, AFS_CELLSERVDB);
458         return 0;
459 }
460
461 /* look up the root cell's name in the Registry */
462 long cm_GetRootCellName(char *cellNamep)
463 {
464         DWORD code, dummyLen;
465         HKEY parmKey;
466
467         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
468                                 0, KEY_QUERY_VALUE, &parmKey);
469         if (code != ERROR_SUCCESS)
470                 return -1;
471
472         dummyLen = 256;
473         code = RegQueryValueEx(parmKey, "Cell", NULL, NULL,
474                                 cellNamep, &dummyLen);
475         RegCloseKey (parmKey);
476         if (code != ERROR_SUCCESS || cellNamep[0] == 0)
477                 return -1;
478
479         return 0;
480 }
481 #else
482 /* look up the root cell's name in the THISCELL file */
483 long cm_GetRootCellName(char *cellNamep)
484 {
485         FILE *thisCell;
486         char thisCellPath[256];
487         char *newline;
488
489 #ifdef DJGPP
490         strcpy(thisCellPath, cm_confDir);
491 #else
492         /* Win 95 */
493         char *afsconf_path;
494         afsconf_path = getenv("AFSCONF");
495         if (!afsconf_path)
496           strcpy(thisCellPath, AFSDIR_CLIENT_ETC_DIRPATH);
497         else
498           strcpy(thisCellPath, afsconf_path);
499 #endif
500         strcat(thisCellPath,"/");
501
502         strcat(thisCellPath, AFS_THISCELL);
503         thisCell = fopen(thisCellPath, "r");
504         if (thisCell == NULL)
505           return -1;
506
507         fgets(cellNamep, 256, thisCell);
508         fclose(thisCell);
509
510         newline = strrchr(cellNamep,'\n');
511         if (newline) *newline = '\0';
512         newline = strrchr(cellNamep,'\r');
513         if (newline) *newline = '\0';
514
515         return 0;
516 }
517 #endif /* !DJGPP */
518
519 cm_configFile_t *cm_CommonOpen(char *namep, char *rwp)
520 {
521         char wdir[256];
522     long tlen;
523     FILE *tfilep;
524
525 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
526     strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
527         
528         /* add trailing backslash, if required */
529         tlen = strlen(wdir);
530         if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
531 #else
532 #ifdef DJGPP
533         strcpy(wdir,cm_confDir);
534 #else
535         char *afsconf_path = getenv("AFSCONF");
536         if (!afsconf_path)
537           strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
538         else
539           strcpy(wdir, afsconf_path);
540 #endif /* !DJGPP */
541         strcat(wdir,"/");
542 #endif /* DJGPP || WIN95 */
543
544         strcat(wdir, namep);
545         
546         tfilep = fopen(wdir, rwp);
547
548         return ((cm_configFile_t *) tfilep);        
549 }
550
551 #ifndef DJGPP
552 long cm_WriteConfigString(char *labelp, char *valuep)
553 {
554         DWORD code, dummyDisp;
555         HKEY parmKey;
556
557         code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
558                                 0, "container", 0, KEY_SET_VALUE, NULL,
559                                 &parmKey, &dummyDisp);
560         if (code != ERROR_SUCCESS)
561                 return -1;
562
563         code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
564                              valuep, strlen(valuep) + 1);
565         RegCloseKey (parmKey);
566         if (code != ERROR_SUCCESS)
567                 return -1;
568
569         return 0;
570 }
571 #endif /* !DJGPP */
572
573 #ifndef DJGPP
574 long cm_WriteConfigInt(char *labelp, long value)
575 {
576         DWORD code, dummyDisp;
577         HKEY parmKey;
578
579         code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
580                                 0, "container", 0, KEY_SET_VALUE, NULL,
581                                 &parmKey, &dummyDisp);
582         if (code != ERROR_SUCCESS)
583                 return -1;
584
585         code = RegSetValueEx(parmKey, labelp, 0, REG_DWORD,
586                              (LPBYTE)&value, sizeof(value));
587         RegCloseKey (parmKey);
588         if (code != ERROR_SUCCESS)
589                 return -1;
590
591         return 0;
592 }
593 #endif /* !DJGPP */
594
595 cm_configFile_t *cm_OpenCellFile(void)
596 {
597         cm_configFile_t *cfp;
598
599         cfp = cm_CommonOpen("afsdcel2.ini", "w");
600         return cfp;
601 }
602
603 long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
604 {
605         cm_configFile_t *tfilep;        /* input file */
606         char *tp;
607         char lineBuffer[256];
608         char *valuep;
609         int inRightCell;
610         int foundCell;
611
612         tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
613         if (!tfilep) return -1;
614
615         foundCell = 0;
616
617         /* have we seen the cell line for the guy we're looking for? */
618         inRightCell = 0;
619         while (1) {
620                 tp = fgets(lineBuffer, sizeof(lineBuffer), (FILE *)tfilep);
621                 if (tp == NULL) {
622                         if (feof((FILE *)tfilep)) {
623                                 /* hit EOF */
624                                 fclose((FILE *)tfilep);
625                                 return 0;
626                         }
627                 }
628                 
629                 /* turn trailing cr or lf into null */
630                 tp = strchr(lineBuffer, '\r');
631                 if (tp) *tp = 0;
632                 tp = strchr(lineBuffer, '\n');
633                 if (tp) *tp = 0;
634                 
635                 /* skip blank lines */
636                 if (lineBuffer[0] == 0) {
637                         fprintf((FILE *)ofp, "%s\n", lineBuffer);
638                         continue;
639                 }
640
641                 if (lineBuffer[0] == '>') {
642                         /* trim off at white space or '#' chars */
643                         tp = strchr(lineBuffer, ' ');
644                         if (tp) *tp = 0;
645                         tp = strchr(lineBuffer, '\t');
646                         if (tp) *tp = 0;
647                         tp = strchr(lineBuffer, '#');
648                         if (tp) *tp = 0;
649
650                         /* now see if this is the right cell */
651                         if (strcmp(lineBuffer+1, cellNamep) == 0) {
652                                 /* found the cell we're looking for */
653                                 inRightCell = 1;
654                         }
655                         else {
656                                 inRightCell = 0;
657                                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
658                         }
659                 }
660                 else {
661                         valuep = strchr(lineBuffer, '#');
662                         if (valuep == NULL) return -2;
663                         valuep++;       /* skip the "#" */
664                         if (!inRightCell) {
665                                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
666                         }
667                 }       /* a vldb line */
668         }               /* while loop processing all lines */
669 }
670
671 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
672 {
673         fprintf((FILE *)filep, ">%s\n", cellNamep);
674         return 0;
675 }
676
677 long cm_AppendNewCellLine(cm_configFile_t *filep, char *linep)
678 {
679         fprintf((FILE *)filep, "%s\n", linep);
680         return 0;
681 }
682
683 long cm_CloseCellFile(cm_configFile_t *filep)
684 {
685         char wdir[256];
686     char sdir[256];
687     long code;
688     long closeCode;
689     int tlen;
690 #ifdef AFS_WIN95_ENV
691     char *afsconf_path;
692 #endif
693         closeCode = fclose((FILE *)filep);
694
695 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
696     strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
697         
698         /* add trailing backslash, if required */
699     tlen = strlen(wdir);
700     if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
701 #else
702 #ifdef DJGPP
703     strcpy(wdir,cm_confDir);
704 #else
705     afsconf_path = getenv("AFSCONF");
706     if (!afsconf_path)
707         strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
708     else
709         strcpy(wdir, afsconf_path);
710 #endif /* !DJGPP */
711     strcat(wdir,"/");
712 #endif /* DJGPP || WIN95 */
713
714     strcpy(sdir, wdir);
715
716         if (closeCode != 0) {
717                 /* something went wrong, preserve original database */
718         strcat(wdir, "afsdcel2.ini");
719         unlink(wdir);
720         return closeCode;
721     }
722
723     strcat(wdir, AFS_CELLSERVDB);
724     strcat(sdir, "afsdcel2.ini");       /* new file */
725
726     unlink(wdir);                       /* delete old file */
727
728     code = rename(sdir, wdir);  /* do the rename */
729
730     if (code) 
731         code = errno;
732
733     return code;
734 }   
735
736 void cm_GetConfigDir(char *dir)
737 {
738         char wdir[256];
739     int tlen;
740 #ifdef AFS_WIN95_ENV
741     char *afsconf_path;
742 #endif
743
744 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
745     strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
746         
747         /* add trailing backslash, if required */
748     tlen = strlen(wdir);
749     if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
750 #else
751 #ifdef DJGPP
752     strcpy(wdir,cm_confDir);
753 #else
754     afsconf_path = getenv("AFSCONF");
755     if (!afsconf_path)
756         strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
757     else
758         strcpy(wdir, afsconf_path);
759 #endif /* !DJGPP */
760     strcat(wdir,"\\");
761 #endif /* DJGPP || WIN95 */
762     strcpy(dir, wdir);
763 }