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