cellservdb-20040714
[openafs.git] / src / WINNT / client_config / cellservdb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <memory.h>
16 #include <malloc.h>
17 #include "cellservdb.h"
18
19 #ifdef AFS_NT40_ENV
20 #include <windows.h>
21 #include <winsock2.h>
22 #else
23 #include <sys/socket.h>
24 #endif
25
26
27 /*
28  * PROTOTYPES _________________________________________________________________
29  *
30  */
31
32 #define new(_t)     (_t*)malloc(sizeof(_t))
33 #define delete(_p)  free((void*)(_p))
34
35 #ifndef iswhite
36 #define iswhite(_ch) (((_ch)==' ') || ((_ch)=='\t'))
37 #endif
38 #ifndef iseol
39 #define iseol(_ch) (((_ch)=='\r') || ((_ch)=='\n'))
40 #endif
41 #ifndef iswhiteeol
42 #define iswhiteeol(_ch) (iswhite(_ch) || iseol(_ch))
43 #endif
44 #ifndef min
45 #define min(_a,_b) ((_a) < (_b) ? (_a) : (_b))
46 #endif
47
48
49 /*
50  * STATICS ____________________________________________________________________
51  *
52  */
53
54 static void strzcpy (char *pszTarget, const char *pszSource, size_t cch)
55 {
56    cch = min(cch, (size_t)(1+strlen(pszSource)));
57    strncpy (pszTarget, pszSource, cch-1);
58    pszTarget[ cch-1 ] = '\0';
59 }
60
61
62 /*
63  * ROUTINES ___________________________________________________________________
64  *
65  */
66
67 void CSDB_GetFileName (char *pszFilename)
68 {
69 #ifdef AFS_NT40_ENV
70    /* Find the appropriate CellServDB */
71     char * clientdir = 0;
72         afssw_GetClientInstallDir(&clientdir);
73         if (clientdir) {
74                 strncpy(pszFilename, clientdir, MAX_CSDB_PATH);
75                 pszFilename[MAX_CSDB_PATH - 1] = '\0';
76         }
77     if (pszFilename[ strlen(pszFilename)-1 ] != '\\')
78       strcat (pszFilename, "\\");
79
80    strcat (pszFilename, "CellServDB");
81 #else
82    strcpy (pszFilename, "/usr/vice/etc/CellServDB");
83 #endif
84 }
85
86
87 BOOL CSDB_ReadFile (PCELLSERVDB pCellServDB, const char *pszFilename)
88 {
89    BOOL rc = FALSE;
90    FILE *pFile;
91    size_t cbLength;
92    size_t cbRead;
93    char *pszBuffer;
94    char *pszStart;
95    char *pszEnd;
96    PCELLDBLINE pLine;
97
98    memset (pCellServDB, 0x00, sizeof(CELLSERVDB));
99
100    /* Open AFSDCELL.INI and read it into memory. */
101
102    if (pszFilename)
103       strcpy (pCellServDB->szFilename, pszFilename);
104    else
105       CSDB_GetFileName (pCellServDB->szFilename);
106
107    if ((pFile = fopen (pCellServDB->szFilename, "r")) != NULL)
108       {
109       fseek (pFile, 0, 2);
110       cbLength = ftell (pFile);
111       fseek (pFile, 0, 0);
112
113       pszBuffer = (char*)malloc (sizeof(char) * (cbLength +2));
114
115       if ((cbRead = fread (pszBuffer, 1, cbLength, pFile)) != 0)
116          {
117          pszBuffer[ cbRead ] = '\0';
118          pszBuffer[ cbRead+1 ] = '\0';
119
120          /* Scan the file line-by-line... */
121
122          for (pszStart = pszBuffer; pszStart && *pszStart; )
123             {
124             while (iswhiteeol(*pszStart))
125                ++pszStart;
126             if (!*pszStart)
127                break;
128
129             for (pszEnd = pszStart; *pszEnd && !iseol(*pszEnd); ++pszEnd)
130                ;
131             *pszEnd++ = '\0';
132
133             /* Add this line to our chain */
134
135             pLine = new(CELLDBLINE);
136             memset (pLine, 0x00, sizeof(CELLDBLINE));
137             strzcpy (pLine->szLine, pszStart, cchCELLDBLINE-1);
138             pLine->szLine[ cchCELLDBLINE-1 ] = '\0';
139             if ((pLine->pPrev = pCellServDB->pLast) != NULL)
140                pLine->pPrev->pNext = pLine;
141             if ((pCellServDB->pLast = pLine)->pPrev == NULL)
142                pCellServDB->pFirst = pLine;
143
144             /* Process the next line in the file */
145
146             pszStart = pszEnd;
147             }
148
149          rc = TRUE;
150          }
151
152       free (pszBuffer);
153       fclose (pFile);
154       }
155
156    return rc;
157 }
158
159
160 BOOL CSDB_WriteFile (PCELLSERVDB pCellServDB)
161 {
162    BOOL rc = TRUE;
163    FILE *pFile;
164    char szLine[ cchCELLDBLINE ];
165    PCELLDBLINE pLine;
166
167    if (pCellServDB->fChanged)
168       {
169       if ((pFile = fopen (pCellServDB->szFilename, "w")) == NULL)
170          {
171          rc = FALSE;
172          }
173       else
174          {
175          for (pLine = pCellServDB->pFirst; pLine; pLine = pLine->pNext)
176             {
177 #ifdef AFS_NT40_ENV
178             sprintf (szLine, "%s\r\n", pLine->szLine);
179 #else
180             sprintf (szLine, "%s\n", pLine->szLine);
181 #endif
182             fwrite (szLine, 1, strlen(szLine), pFile);
183             }
184
185          fclose (pFile);
186          }
187
188       pCellServDB->fChanged = FALSE;
189       }
190
191    return rc;
192 }
193
194
195 void CSDB_FreeFile (PCELLSERVDB pCellServDB)
196 {
197    PCELLDBLINE pNext;
198    PCELLDBLINE pLine;
199    for (pLine = pCellServDB->pFirst; pLine; pLine = pNext)
200       {
201       pNext = pLine->pNext;
202       delete(pLine);
203       }
204    memset (pCellServDB, 0x00, sizeof(CELLSERVDB));
205 }
206
207
208 BOOL CSDB_CrackLine (PCELLDBLINEINFO pInfo, const char *pszLine)
209 {
210    char *pszOut;
211    BOOL fIsCell = TRUE;
212    BOOL fSawHash = FALSE;
213
214    memset (pInfo, 0x00, sizeof(CELLDBLINEINFO));
215
216    if (!pszLine || !*pszLine)
217       return FALSE;
218
219    while (iswhite(*pszLine))
220       ++pszLine;
221
222    if (*pszLine == '>')
223       ++pszLine;
224    else if (!isdigit (*pszLine))
225       return FALSE;
226    else /* (isdigit (*pszLine)) */
227       fIsCell = FALSE;
228
229    for (pszOut = pInfo->szCell; *pszLine && (!iswhite(*pszLine)) && (*pszLine != '#'); )
230       *pszOut++ = *pszLine++;
231    *pszOut = '\0';
232
233    while (iswhite(*pszLine) || (*pszLine == '#'))
234       {
235       fSawHash = fSawHash || (*pszLine == '#');
236       ++pszLine;
237       }
238
239    if (fIsCell && *pszLine && !fSawHash)
240       {
241       for (pszOut = pInfo->szLinkedCell; *pszLine && (!iswhite(*pszLine)) && (*pszLine != '#'); )
242          *pszOut++ = *pszLine++;
243       *pszOut = '\0';
244
245       while (iswhite(*pszLine) || (*pszLine == '#'))
246          ++pszLine;
247       }
248
249    for (pszOut = pInfo->szComment; *pszLine; )
250       *pszOut++ = *pszLine++;
251    *pszOut = '\0';
252
253    if (!pInfo->szCell[0])
254       return FALSE;
255
256    if (!fIsCell)
257       {
258       if ((pInfo->ipServer = inet_addr (pInfo->szCell)) == 0xffffffff)
259          return FALSE;
260       pInfo->szCell[0] = '\0';
261       }
262
263    return TRUE;
264 }
265
266
267 BOOL CSDB_FormatLine (char *pszLine, const char *pszCell, const char *pszLinkedCell, const char *pszComment, BOOL fIsCell)
268 {
269    if (fIsCell)
270       sprintf (pszLine, ">%s", pszCell);
271    else
272       strcpy (pszLine, pszCell);
273
274    if (fIsCell && pszLinkedCell && *pszLinkedCell)
275       sprintf (&pszLine[ strlen(pszLine) ], " %s", pszLinkedCell);
276
277    if (pszComment)
278       {
279       size_t cchSpacing = (fIsCell) ? 28 : 33;
280       strcat (pszLine, " ");
281       if ((size_t)strlen(pszLine) < cchSpacing)
282          {
283          strcat (pszLine, "                                 ");
284          pszLine[cchSpacing] = '\0';
285          }
286
287       sprintf (&pszLine[ strlen(pszLine) ], ((fIsCell) ? "# %s" : "#%s"), pszComment);
288       }
289
290    return TRUE;
291 }
292
293
294 PCELLDBLINE CSDB_FindCell (PCELLSERVDB pCellServDB, const char *pszCell)
295 {
296    PCELLDBLINE pLine;
297    for (pLine = pCellServDB->pFirst; pLine; pLine = pLine->pNext)
298       {
299       CELLDBLINEINFO Info;
300       if (!CSDB_CrackLine (&Info, pLine->szLine))
301          continue;
302       if (!strcmpi (Info.szCell, pszCell))
303          return pLine;
304       }
305    return NULL;
306 }
307
308
309 BOOL CSDB_OnRemove (PCELLSERVDB pCellServDB, PCELLDBLINE pCellLine, BOOL fRemoveCellLineToo)
310 {
311    CELLDBLINEINFO Info;
312    PCELLDBLINE pNext;
313    PCELLDBLINE pLine;
314
315    /* Quick validation: make sure the caller specified a Cell line */
316
317    if (!pCellLine)
318       return FALSE;
319    if (!CSDB_CrackLine (&Info, pCellLine->szLine))
320       return FALSE;
321    if (!Info.szCell[0])
322       return FALSE;
323
324    /* Remove everything about this cell (except maybe the cell line) */
325
326    pLine = (fRemoveCellLineToo) ? pCellLine : pCellLine->pNext;
327    for ( ; pLine; pLine = pNext)
328       {
329       if ((pNext = CSDB_RemoveLine (pCellServDB, pLine)) != NULL)
330          {
331          if (!CSDB_CrackLine (&Info, pNext->szLine))
332             break;
333          if (Info.szCell[0]) /* Hit the next cell? We're done! */
334             break;
335          }
336       }
337
338    pCellServDB->fChanged = TRUE;
339    return TRUE;
340 }
341
342 BOOL CSDB_RemoveCell (PCELLSERVDB pCellServDB, PCELLDBLINE pCellLine)
343 {
344    return CSDB_OnRemove (pCellServDB, pCellLine, TRUE);
345 }
346    
347 BOOL CSDB_RemoveCellServers (PCELLSERVDB pCellServDB, PCELLDBLINE pCellLine)
348 {
349    return CSDB_OnRemove (pCellServDB, pCellLine, FALSE);
350 }
351
352
353 PCELLDBLINE CSDB_AddCell (PCELLSERVDB pCellServDB, const char *pszCell, const char *pszLinkedCell, const char *pszComment)
354 {
355    PCELLDBLINE pCellLine;
356
357    /* Find out if there's already an entry in CellServDB for this cell; */
358    /* add one if necessary. */
359
360    if ((pCellLine = CSDB_FindCell (pCellServDB, pszCell)) == NULL)
361       {
362       pCellLine = new(CELLDBLINE);
363       memset (pCellLine, 0x00, sizeof(CELLDBLINE));
364       if ((pCellLine->pPrev = pCellServDB->pLast) != NULL)
365          pCellLine->pPrev->pNext = pCellLine;
366       if ((pCellServDB->pLast = pCellLine)->pPrev == NULL)
367          pCellServDB->pFirst = pCellLine;
368       }
369
370    CSDB_FormatLine (pCellLine->szLine, pszCell, pszLinkedCell, pszComment, TRUE);
371    pCellServDB->fChanged = TRUE;
372    return pCellLine;
373 }
374
375
376 PCELLDBLINE CSDB_AddCellServer (PCELLSERVDB pCellServDB, PCELLDBLINE pAddAfter, const char *pszAddress, const char *pszComment)
377 {
378    char szLine[ cchCELLDBLINE ];
379    CSDB_FormatLine (szLine, pszAddress, NULL, pszComment, FALSE);
380    return CSDB_AddLine (pCellServDB, pAddAfter, szLine);
381 }
382
383
384 PCELLDBLINE CSDB_AddLine (PCELLSERVDB pCellServDB, PCELLDBLINE pAddAfter, const char *pszLine)
385 {
386    PCELLDBLINE pNew = new(CELLDBLINE);
387    memset (pNew, 0x00, sizeof(CELLDBLINE));
388    strcpy (pNew->szLine, pszLine);
389
390    if (pAddAfter == NULL)
391       {
392       if ((pNew->pNext = pCellServDB->pFirst) != NULL)
393          pNew->pNext->pPrev = pNew;
394       pNew->pPrev = NULL;
395       pCellServDB->pFirst = pNew;
396       if (pCellServDB->pLast == NULL)
397          pCellServDB->pLast = pNew;
398       }
399    else /* (pAddAfter != NULL) */
400       {
401       if ((pNew->pNext = pAddAfter->pNext) != NULL)
402          pNew->pNext->pPrev = pNew->pPrev;
403       pNew->pPrev = pAddAfter;
404       pAddAfter->pNext = pNew;
405       if (pCellServDB->pLast == pAddAfter)
406          pCellServDB->pLast = pNew;
407       }
408
409    pCellServDB->fChanged = TRUE;
410    return pNew;
411 }
412
413
414 PCELLDBLINE CSDB_RemoveLine (PCELLSERVDB pCellServDB, PCELLDBLINE pRemove)
415 {
416    PCELLDBLINE pNext;
417
418    if (!pRemove)
419       return NULL;
420
421    pNext = pRemove->pNext;
422
423    if (pRemove->pPrev)
424       pRemove->pPrev->pNext = pRemove->pNext;
425    if (pRemove->pNext)
426       pRemove->pNext->pPrev = pRemove->pPrev;
427    if (pCellServDB->pFirst == pRemove)
428       pCellServDB->pFirst = pRemove->pNext;
429    if (pCellServDB->pLast == pRemove)
430       pCellServDB->pLast = pRemove->pPrev;
431
432    delete(pRemove);
433
434    pCellServDB->fChanged = TRUE;
435    return pNext;
436 }
437