empty-cell-name-fix-20040313
[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         /* query the AFSDB records of cell */
395         if(DnsQuery_A(cellNamep, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
396
397                 memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
398                 
399                 nvlServers = 0; wttl = 0;
400
401                 /* go through the returned records */
402                 for(pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
403                         /* if we find an AFSDB record with Preference set to 1, we found a volserver */
404                         if(pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
405                                 vlServers[nvlServers++] = pDnsIter->Data.Afsdb.pNameExchange;
406                                 if(!wttl) wttl = pDnsIter->dwTtl;
407                                 if(nvlServers == AFSMAXCELLHOSTS) break;
408                         }
409                 }
410
411                 for(i=0;i<nvlServers;i++) vlAddrs[i] = 0;
412
413                 /* now check if there are any A records in the results */
414                 for(pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
415                         if(pDnsIter->wType == DNS_TYPE_A)
416                                 /* check if its for one of the volservers */
417                                 for(i=0;i<nvlServers;i++)
418                                         if(stricmp(pDnsIter->pName, vlServers[i]) == 0)
419                                                 vlAddrs[i] = pDnsIter->Data.A.IpAddress;
420                 }
421
422                 for(i=0;i<nvlServers;i++) {
423                         /* if we don't have an IP yet, then we should try resolving the volserver hostname
424                            in a separate query. */
425                         if(!vlAddrs[i]) {
426                                 if(DnsQuery_A(vlServers[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &pDnsVol, NULL) == ERROR_SUCCESS) {
427                                         for(pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
428                                                 /* if we get an A record, keep it */
429                                                 if(pDnsVolIter->wType == DNS_TYPE_A && stricmp(vlServers[i], pDnsVolIter->pName)==0) {
430                                                         vlAddrs[i] = pDnsVolIter->Data.A.IpAddress;
431                                                         break;
432                                                 }
433                                                 /* if we get a CNAME, look for a corresponding A record */
434                                                 if(pDnsVolIter->wType == DNS_TYPE_CNAME && stricmp(vlServers[i], pDnsVolIter->pName)==0) {
435                                                         for(pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
436                                                                 if(pDnsCIter->wType == DNS_TYPE_A && stricmp(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
437                                                                         vlAddrs[i] = pDnsCIter->Data.A.IpAddress;
438                                                                         break;
439                                                                 }
440                                                         }
441                                                         if(vlAddrs[i]) break;
442                                                         /* TODO: if the additional section is missing, then do another lookup for the CNAME */
443                                                 }
444                                         }
445                                         /* we are done with the volserver lookup */
446                                         DnsRecordListFree(pDnsVol, DnsFreeRecordListDeep);
447                                 }
448                         }
449
450                         /* if we found a volserver, then add it */
451                         if(vlAddrs[i]) {
452                                 vlSockAddr.sin_family = AF_INET;
453                                 vlSockAddr.sin_addr.s_addr = vlAddrs[i];
454                                 if(procp)
455                                         (*procp)(rockp, &vlSockAddr, vlServers[i]);
456                                 success = TRUE;
457                         }
458                 }
459
460                 DnsRecordListFree(pDnsCell, DnsFreeRecordListDeep);
461         }
462
463         if(!success) return -1;
464         else {
465                 strcpy(newCellNamep, cellNamep);
466                 if(ttl) *ttl = (int) wttl;
467                 return 0;
468         }
469
470 #endif /* DNSAPI_ENV */
471 #else
472         return -1;  /* not found */
473 #endif /* AFS_AFSDB_ENV */
474 }
475
476 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
477 /* look up the root cell's name in the Registry */
478 long cm_GetRootCellName(char *cellNamep)
479 {
480         DWORD code, dummyLen;
481         HKEY parmKey;
482
483         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
484                                 0, KEY_QUERY_VALUE, &parmKey);
485         if (code != ERROR_SUCCESS)
486                 return -1;
487
488         dummyLen = 256;
489         code = RegQueryValueEx(parmKey, "Cell", NULL, NULL,
490                                 cellNamep, &dummyLen);
491         RegCloseKey (parmKey);
492         if (code != ERROR_SUCCESS || cellNamep[0] == 0)
493                 return -1;
494
495         return 0;
496 }
497 #else
498 /* look up the root cell's name in the THISCELL file */
499 long cm_GetRootCellName(char *cellNamep)
500 {
501         FILE *thisCell;
502         char thisCellPath[256];
503         char *newline;
504
505 #ifdef DJGPP
506         strcpy(thisCellPath, cm_confDir);
507 #else
508         /* Win 95 */
509         char *afsconf_path;
510         afsconf_path = getenv("AFSCONF");
511         if (!afsconf_path)
512           strcpy(thisCellPath, AFSDIR_CLIENT_ETC_DIRPATH);
513         else
514           strcpy(thisCellPath, afsconf_path);
515 #endif
516         strcat(thisCellPath,"/");
517
518         strcat(thisCellPath, AFS_THISCELL);
519         thisCell = fopen(thisCellPath, "r");
520         if (thisCell == NULL)
521           return -1;
522
523         fgets(cellNamep, 256, thisCell);
524         fclose(thisCell);
525
526         newline = strrchr(cellNamep,'\n');
527         if (newline) *newline = '\0';
528         newline = strrchr(cellNamep,'\r');
529         if (newline) *newline = '\0';
530
531         return 0;
532 }
533 #endif /* !DJGPP */
534
535 cm_configFile_t *cm_CommonOpen(char *namep, char *rwp)
536 {
537         char wdir[256];
538     long code;
539     long tlen;
540     FILE *tfilep;
541
542 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
543         code = GetWindowsDirectory(wdir, sizeof(wdir));
544         if (code == 0 || code > sizeof(wdir)) 
545             return 0;
546         
547         /* add trailing backslash, if required */
548         tlen = strlen(wdir);
549         if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
550 #else
551 #ifdef DJGPP
552         strcpy(wdir,cm_confDir);
553 #else
554         char *afsconf_path = getenv("AFSCONF");
555         if (!afsconf_path)
556           strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
557         else
558           strcpy(wdir, afsconf_path);
559 #endif /* !DJGPP */
560         strcat(wdir,"/");
561 #endif /* DJGPP || WIN95 */
562
563         strcat(wdir, namep);
564         
565         tfilep = fopen(wdir, rwp);
566
567         return ((cm_configFile_t *) tfilep);        
568 }
569
570 #ifndef DJGPP
571 long cm_WriteConfigString(char *labelp, char *valuep)
572 {
573         DWORD code, dummyDisp;
574         HKEY parmKey;
575
576         code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
577                                 0, "container", 0, KEY_SET_VALUE, NULL,
578                                 &parmKey, &dummyDisp);
579         if (code != ERROR_SUCCESS)
580                 return -1;
581
582         code = RegSetValueEx(parmKey, labelp, 0, REG_SZ,
583                              valuep, strlen(valuep) + 1);
584         RegCloseKey (parmKey);
585         if (code != ERROR_SUCCESS)
586                 return -1;
587
588         return 0;
589 }
590 #endif /* !DJGPP */
591
592 #ifndef DJGPP
593 long cm_WriteConfigInt(char *labelp, long value)
594 {
595         DWORD code, dummyDisp;
596         HKEY parmKey;
597
598         code = RegCreateKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
599                                 0, "container", 0, KEY_SET_VALUE, NULL,
600                                 &parmKey, &dummyDisp);
601         if (code != ERROR_SUCCESS)
602                 return -1;
603
604         code = RegSetValueEx(parmKey, labelp, 0, REG_DWORD,
605                              (LPBYTE)&value, sizeof(value));
606         RegCloseKey (parmKey);
607         if (code != ERROR_SUCCESS)
608                 return -1;
609
610         return 0;
611 }
612 #endif /* !DJGPP */
613
614 cm_configFile_t *cm_OpenCellFile(void)
615 {
616         cm_configFile_t *cfp;
617
618         cfp = cm_CommonOpen("afsdcel2.ini", "w");
619         return cfp;
620 }
621
622 long cm_AppendPrunedCellList(cm_configFile_t *ofp, char *cellNamep)
623 {
624         cm_configFile_t *tfilep;        /* input file */
625         char *tp;
626         char lineBuffer[256];
627         char *valuep;
628         int inRightCell;
629         int foundCell;
630
631         tfilep = cm_CommonOpen(AFS_CELLSERVDB, "r");
632         if (!tfilep) return -1;
633
634         foundCell = 0;
635
636         /* have we seen the cell line for the guy we're looking for? */
637         inRightCell = 0;
638         while (1) {
639                 tp = fgets(lineBuffer, sizeof(lineBuffer), (FILE *)tfilep);
640                 if (tp == NULL) {
641                         if (feof((FILE *)tfilep)) {
642                                 /* hit EOF */
643                                 fclose((FILE *)tfilep);
644                                 return 0;
645                         }
646                 }
647                 
648                 /* turn trailing cr or lf into null */
649                 tp = strchr(lineBuffer, '\r');
650                 if (tp) *tp = 0;
651                 tp = strchr(lineBuffer, '\n');
652                 if (tp) *tp = 0;
653                 
654                 /* skip blank lines */
655                 if (lineBuffer[0] == 0) {
656                         fprintf((FILE *)ofp, "%s\n", lineBuffer);
657                         continue;
658                 }
659
660                 if (lineBuffer[0] == '>') {
661                         /* trim off at white space or '#' chars */
662                         tp = strchr(lineBuffer, ' ');
663                         if (tp) *tp = 0;
664                         tp = strchr(lineBuffer, '\t');
665                         if (tp) *tp = 0;
666                         tp = strchr(lineBuffer, '#');
667                         if (tp) *tp = 0;
668
669                         /* now see if this is the right cell */
670                         if (strcmp(lineBuffer+1, cellNamep) == 0) {
671                                 /* found the cell we're looking for */
672                                 inRightCell = 1;
673                         }
674                         else {
675                                 inRightCell = 0;
676                                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
677                         }
678                 }
679                 else {
680                         valuep = strchr(lineBuffer, '#');
681                         if (valuep == NULL) return -2;
682                         valuep++;       /* skip the "#" */
683                         if (!inRightCell) {
684                                 fprintf((FILE *)ofp, "%s\n", lineBuffer);
685                         }
686                 }       /* a vldb line */
687         }               /* while loop processing all lines */
688 }
689
690 long cm_AppendNewCell(cm_configFile_t *filep, char *cellNamep)
691 {
692         fprintf((FILE *)filep, ">%s\n", cellNamep);
693         return 0;
694 }
695
696 long cm_AppendNewCellLine(cm_configFile_t *filep, char *linep)
697 {
698         fprintf((FILE *)filep, "%s\n", linep);
699         return 0;
700 }
701
702 long cm_CloseCellFile(cm_configFile_t *filep)
703 {
704         char wdir[256];
705     char sdir[256];
706     long code;
707     long closeCode;
708     int tlen;
709 #ifdef AFS_WIN95_ENV
710     char *afsconf_path;
711 #endif
712         closeCode = fclose((FILE *)filep);
713
714 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
715         code = GetWindowsDirectory(wdir, sizeof(wdir));
716         if (code == 0 || code > sizeof(wdir)) 
717             return closeCode;
718         
719         /* add trailing backslash, if required */
720         tlen = strlen(wdir);
721         if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
722 #else
723 #ifdef DJGPP
724         strcpy(wdir,cm_confDir);
725 #else
726         afsconf_path = getenv("AFSCONF");
727         if (!afsconf_path)
728           strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
729         else
730           strcpy(wdir, afsconf_path);
731 #endif /* !DJGPP */
732         strcat(wdir,"/");
733 #endif /* DJGPP || WIN95 */
734
735         strcpy(sdir, wdir);
736
737         if (closeCode != 0) {
738                 /* something went wrong, preserve original database */
739                 strcat(wdir, "afsdcel2.ini");
740                 unlink(wdir);
741                 return closeCode;
742         }
743
744         strcat(wdir, AFS_CELLSERVDB);
745         strcat(sdir, "afsdcel2.ini");   /* new file */
746         
747         unlink(wdir);                   /* delete old file */
748         
749         code = rename(sdir, wdir);      /* do the rename */
750         
751         if (code) 
752           code = errno;
753         
754         return code;
755 }
756
757 void cm_GetConfigDir(char *dir)
758 {
759         char wdir[256];
760     int code;
761     int tlen;
762 #ifdef AFS_WIN95_ENV
763     char *afsconf_path;
764 #endif
765
766 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
767         code = GetWindowsDirectory(wdir, sizeof(wdir));
768       if (code == 0 || code > sizeof(wdir)) wdir[0] = 0;
769         
770         /* add trailing backslash, if required */
771         tlen = strlen(wdir);
772         if (wdir[tlen-1] != '\\') strcat(wdir, "\\");
773 #else
774 #ifdef DJGPP
775         strcpy(wdir,cm_confDir);
776 #else
777         afsconf_path = getenv("AFSCONF");
778         if (!afsconf_path)
779           strcpy(wdir, AFSDIR_CLIENT_ETC_DIRPATH);
780         else
781           strcpy(wdir, afsconf_path);
782 #endif /* !DJGPP */
783         strcat(wdir,"\\");
784 #endif /* DJGPP || WIN95 */
785         strcpy(dir, wdir);
786 }