linux-and-64bit-cleanup-20050710
[openafs.git] / src / bucoord / dsvs.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 /*
11  * ALL RIGHTS RESERVED
12  *
13  * (C) COPYRIGHT IBM CORPORATION 1987, 1998
14  * LICENSED MATERIALS - PROPERTY OF IBM
15  */
16
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 RCSID
22     ("$Header$");
23
24 #include <sys/types.h>
25 #include <afs/cmd.h>
26 #ifdef AFS_NT40_ENV
27 #include <winsock2.h>
28 #else
29 #include <strings.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <netdb.h>
33 #include <sys/param.h>
34 #endif
35 #include <stdio.h>
36 #include <afs/com_err.h>
37
38 #include <afs/bubasics.h>
39 #include "bc.h"
40
41 static char db_dsvs = 0;        /*Assume debugging output turned off */
42 static char mn[] = "dsvs";      /*Module name */
43
44 struct ubik_client *cstructp;   /*Ptr to Ubik client structure */
45
46 extern struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *cf,
47                                              char *name);
48
49
50 /* Code to maintain dump schedule and volume set abstractions.
51  * A volume set looks like this:
52  *      vsname: servername partition-name <volume list>*
53  * A dump schedule looks like this:
54  *      dsname: vsname period parent-ds
55  */
56
57 /* get partition id from a name */
58 afs_int32
59 bc_GetPartitionID(aname, aval)
60      afs_int32 *aval;
61      char *aname;
62 {
63
64     /*bc_GetPartitionID */
65
66     register char tc;
67     char ascii[3];
68
69     /* special-case "anything" */
70     if (strcmp(aname, ".*") == 0) {
71         *aval = -1;
72         return 0;
73     }
74     tc = *aname;
75     if (tc == 0)
76         return -1;              /* unknown */
77     /* numbers go straight through */
78     if (tc >= '0' && tc <= '9') {
79         *aval = bc_SafeATOI(aname);
80         return 0;
81     }
82     /* otherwise check for vicepa or /vicepa, or just plain "a" */
83     ascii[2] = 0;
84     if (strlen(aname) <= 2) {
85         strcpy(ascii, aname);
86     } else if (!strncmp(aname, "/vicep", 6)) {
87         strncpy(ascii, aname + 6, 2);
88     } else if (!strncmp(aname, "vicep", 5)) {
89         strncpy(ascii, aname + 5, 2);
90     } else
91         return (BC_NOPARTITION);        /* bad partition name */
92     /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
93      * from 0.  Do the appropriate conversion */
94     if (ascii[1] == 0) {
95         /* one char name, 0..25 */
96         if (ascii[0] < 'a' || ascii[0] > 'z')
97             return -1;          /* wrongo */
98         *aval = ascii[0] - 'a';
99         return 0;
100     } else {
101         /* two char name, 26 .. <whatever> */
102         if (ascii[0] < 'a' || ascii[0] > 'z')
103             return -1;          /* wrongo */
104         if (ascii[1] < 'a' || ascii[1] > 'z')
105             return -1;          /* just as bad */
106         *aval = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
107         return 0;
108     }
109 }                               /*bc_GetPartitionID */
110
111 /*----------------------------------------------------------------------------
112  * bc_ParseHost
113  *
114  * Description:
115  *      Given a string containing a host name or its IP address in dot notation, fill in
116  *      the given sockaddr with all the corresponding info.
117  *
118  * Arguments:
119  *      aname : Host name or dotted IP address.
120   *     asockaddr: Ptr to sockaddr to fill in for the above host.
121  *
122  * Returns:
123  *      0 if everything went well,
124  *      -1 if it couldn't be translated.
125  *
126  * Environment:
127  *      Nothing interesting.
128  *
129  * Side Effects:
130  *      None.
131  *----------------------------------------------------------------------------
132  */
133
134 int
135 bc_ParseHost(aname, asockaddr)
136      char *aname;
137      struct sockaddr_in *asockaddr;
138
139 {                               /*bc_ParseHost */
140
141     register struct hostent *th;        /*Host entry */
142     afs_int32 addr;             /*Converted address */
143     afs_int32 b1, b2, b3, b4;   /*Byte-sized address chunks */
144     register afs_int32 code;    /*Return code from sscanf() */
145     afs_int32 tmp1, tmp2;
146
147     /*
148      * Try to parse the given name as a dot-notation IP address first.
149      */
150     code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
151     if (code == 4) {
152         /*
153          * Four chunks were read, so we assume success.  Construct the socket.
154          */
155 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
156         asockaddr->sin_len = sizeof(struct sockaddr_in);
157 #endif
158         asockaddr->sin_family = AF_INET;
159         asockaddr->sin_port = 0;
160         addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
161         memcpy(&tmp1, &addr, sizeof(afs_int32));
162         tmp2 = htonl(tmp1);
163         memcpy(&asockaddr->sin_addr.s_addr, &tmp2, sizeof(afs_int32));
164         return (0);
165     }
166
167     /*
168      * The given string isn't a dotted IP address.  Try to map it as a host
169      * name, or leave it as a wild-card.
170      */
171
172     if (strcmp(aname, ".*") == 0) {
173         memset(asockaddr, 0, sizeof(struct sockaddr_in));
174         return 0;
175     }
176
177     th = gethostbyname(aname);
178     if (!th)
179         /*
180          * No such luck, return failure.
181          */
182         return (BC_NOHOST);
183
184     /*
185      * We found a mapping; construct the socket.
186      */
187 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
188     asockaddr->sin_len = sizeof(struct sockaddr_in);
189 #endif
190     asockaddr->sin_family = AF_INET;
191     asockaddr->sin_port = 0;
192     memcpy(&tmp1, th->h_addr, sizeof(afs_int32));
193     tmp2 = htonl(tmp1);
194     memcpy(&(asockaddr->sin_addr.s_addr), &tmp2,
195            sizeof(asockaddr->sin_addr.s_addr));
196     return (0);
197
198 }                               /*bc_ParseHost */
199
200
201 /* create an empty volume set, new items are added via bc_AddVolumeItem */
202 int
203 bc_CreateVolumeSet(struct bc_config *aconfig, char *avolName,
204                    afs_int32 aflags)
205 {
206     register struct bc_volumeSet **tlast, *tset, *nset;
207
208     if (bc_FindVolumeSet(aconfig, avolName))
209         return -1;              /* already exists */
210     /* move to end of the list */
211
212     nset = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
213     memset(nset, 0, sizeof(*nset));
214     nset->flags = aflags;
215     nset->name = (char *)malloc(strlen(avolName) + 1);
216     strcpy(nset->name, avolName);
217     if (aflags & VSFLAG_TEMPORARY) {
218         /* Add to beginning of list */
219         nset->next = aconfig->vset;
220         aconfig->vset = nset;
221     } else {
222         /* Add to end of list */
223         for (tlast = &aconfig->vset, tset = *tlast; tset;
224              tlast = &tset->next, tset = *tlast);
225         *tlast = nset;
226     }
227     return 0;
228 }
229
230 static int
231 FreeVolumeEntry(register struct bc_volumeEntry *aentry)
232 {
233     free(aentry->name);
234     free(aentry->serverName);
235     free(aentry->partname);
236     free(aentry);
237     return 0;
238 }
239
240 static int
241 FreeVolumeEntryList(register struct bc_volumeEntry *aentry)
242 {
243     register struct bc_volumeEntry *tnext;
244
245     while (aentry) {
246         tnext = aentry->next;
247         FreeVolumeEntry(aentry);
248         aentry = tnext;
249     }
250     return 0;
251 }
252
253
254
255 void
256 FreeVolumeSet(struct bc_volumeSet *avset)
257 {
258     FreeVolumeEntryList(avset->ventries);
259     free(avset->name);
260     free(avset);
261 }
262
263 int
264 bc_DeleteVolumeSet(struct bc_config *aconfig, char *avolName,
265                    afs_int32 *flags)
266 {
267     register struct bc_volumeSet **tlast, *tset;
268
269     *flags = 0;
270     tlast = &aconfig->vset;
271     for (tset = *tlast; tset; tlast = &tset->next, tset = *tlast) {
272         if (strcmp(avolName, tset->name) == 0) {
273             *flags = tset->flags;       /* Remember flags */
274             *tlast = tset->next;        /* Remove from chain */
275             FreeVolumeSet(tset);        /* Free the volume set */
276             return 0;
277         }
278     }
279
280     /* if we get here, we didn't find the item */
281     return -1;
282 }
283
284 int
285 bc_DeleteVolumeItem(struct bc_config *aconfig, char *avolName,
286                     afs_int32 anumber)
287 {
288     register afs_int32 i;
289     register struct bc_volumeSet *tset;
290     register struct bc_volumeEntry *tentry, **tlast;
291
292     tset = bc_FindVolumeSet(aconfig, avolName);
293     if (!tset)
294         return -1;
295
296     tlast = &tset->ventries;
297     for (i = 1, tentry = *tlast; tentry;
298          tlast = &tentry->next, tentry = *tlast, i++) {
299         if (anumber == i) {
300             /* found entry we want */
301             *tlast = tentry->next;
302             FreeVolumeEntry(tentry);
303             return 0;
304         }
305     }
306     return -2;                  /* not found */
307 }
308
309 bc_AddVolumeItem(aconfig, avolName, ahost, apart, avol)
310      struct bc_config *aconfig;
311      char *avolName;
312      char *ahost, *apart, *avol;
313 {
314     struct bc_volumeSet *tset;
315     register struct bc_volumeEntry **tlast, *tentry;
316     register afs_int32 code;
317
318     tset = bc_FindVolumeSet(aconfig, avolName);
319     if (!tset)
320         return (BC_NOVOLSET);
321
322     /* otherwise append this item to the end of the real list */
323     tlast = &tset->ventries;
324
325     /* move to end of the list */
326     for (tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast);
327     tentry = (struct bc_volumeEntry *)malloc(sizeof(struct bc_volumeEntry));
328     memset(tentry, 0, sizeof(*tentry));
329     tentry->serverName = (char *)malloc(strlen(ahost) + 1);
330     strcpy(tentry->serverName, ahost);
331     tentry->partname = (char *)malloc(strlen(apart) + 1);
332     strcpy(tentry->partname, apart);
333     tentry->name = (char *)malloc(strlen(avol) + 1);
334     strcpy(tentry->name, avol);
335
336     code = bc_ParseHost(tentry->serverName, &tentry->server);
337     if (code)
338         return (code);
339
340     code = bc_GetPartitionID(tentry->partname, &tentry->partition);
341     if (code)
342         return (code);
343
344     *tlast = tentry;            /* thread on the list */
345     return 0;
346 }
347
348 struct bc_volumeSet *
349 bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
350 {                               /*bc_FindVolumeSet */
351
352     register struct bc_volumeSet *tvs;
353
354     for (tvs = aconfig->vset; tvs; tvs = tvs->next) {
355         if (!strcmp(tvs->name, aname))
356             return (tvs);
357     }
358     return (struct bc_volumeSet *)0;
359
360 }                               /*bc_FindVolumeSet */
361
362 /* ------------------------------------
363  * dumpschedule management code
364  * ------------------------------------
365  */
366
367 /* bc_CreateDumpSchedule
368  *      Add another node to the dump schedule.
369  * entry:
370  *      aconfig - in core configuration structures
371  *      adumpName - name of new dump node
372  *      expDate - expiration date
373  *      expType - absolute or relative
374  */
375
376 bc_CreateDumpSchedule(aconfig, adumpName, expDate, expType)
377      struct bc_config *aconfig;
378      char *adumpName;
379      afs_int32 expDate;
380      afs_int32 expType;
381 {
382     register struct bc_dumpSchedule *tdump;
383     struct bc_dumpSchedule *parent, *node;
384     afs_int32 code;
385
386     if (strcmp(adumpName, "none") == 0)
387         return -2;              /* invalid name */
388
389     code = FindDump(aconfig, adumpName, &parent, &node);
390     if (code == 0)
391         return -1;              /* node already exists */
392     else if (code != -1)
393         return -2;              /* name specification error */
394
395     tdump = (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
396     memset(tdump, 0, sizeof(*tdump));
397
398     /* prepend this node to the dump schedule list */
399     tdump->next = aconfig->dsched;
400     aconfig->dsched = tdump;
401
402     /* save the name of this dump node */
403     tdump->name = (char *)malloc(strlen(adumpName) + 1);
404     strcpy(tdump->name, adumpName);
405
406     /* expiration information */
407     tdump->expDate = expDate;
408     tdump->expType = expType;
409
410     bc_ProcessDumpSchedule(aconfig);    /* redo tree */
411     return 0;
412 }
413
414
415 /* Recursively remove this node and all of its children from aconfig's
416  * list of dumps.  Note that this leaves the sibling pointers damaged (pointing
417  * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
418  */
419
420 bc_DeleteDumpScheduleAddr(aconfig, adumpAddr)
421      struct bc_config *aconfig;
422      struct bc_dumpSchedule *adumpAddr;
423 {
424     register struct bc_dumpSchedule **tlast, *tdump;
425     register struct bc_dumpSchedule *tnext;
426
427     /* knock off all children first */
428     for (tdump = adumpAddr->firstChild; tdump; tdump = tnext) {
429         /* extract next ptr now, since will be freed by recursive call below */
430         tnext = tdump->nextSibling;
431         bc_DeleteDumpScheduleAddr(aconfig, tdump);
432     }
433
434     /* finally, remove us from the list of good dudes */
435     for (tlast = &aconfig->dsched, tdump = *tlast; tdump;
436          tlast = &tdump->next, tdump = *tlast) {
437         if (tdump == adumpAddr) {
438             /* found the one we're looking for */
439             *tlast = tdump->next;       /* remove us from basic list */
440             free(tdump->name);
441             free(tdump);
442             return 0;
443         }
444     }
445     return 0;
446 }
447
448 /* bc_FindDumpSchedule
449  *      Finds dump schedule aname by doing a linear search
450  * entry:
451  *      aconfig - handle for incore configuration tables
452  *      aname - (path)name to match on
453  * exit:
454  *      0 for failure, ptr to dumpschedule for success
455  */
456
457 struct bc_dumpSchedule *
458 bc_FindDumpSchedule(aconfig, aname)
459      char *aname;
460      struct bc_config *aconfig;
461 {
462     register struct bc_dumpSchedule *tds;
463     for (tds = aconfig->dsched; tds; tds = tds->next) {
464         if (!strcmp(tds->name, aname))
465             return tds;
466     }
467     return (struct bc_dumpSchedule *)0;
468 }
469
470 /* bc_DeleteDumpSchedule
471  *      Delete dump node adumpName from the dump schedule
472  */
473
474 bc_DeleteDumpSchedule(aconfig, adumpName)
475      struct bc_config *aconfig;
476      char *adumpName;
477 {
478     register struct bc_dumpSchedule *tdump;
479
480     /* does a linear search of the dump schedules in order to find
481      * the one to delete
482      */
483     for (tdump = aconfig->dsched; tdump; tdump = tdump->next) {
484         if (strcmp(tdump->name, adumpName) == 0) {
485             /* found it, we can zap recursively */
486             bc_DeleteDumpScheduleAddr(aconfig, tdump);
487             /* tree's been pruned, but we have to recompute the internal pointers
488              * from first principles, since we didn't bother to maintain
489              * the sibling and children pointers during the call to delete
490              * the nodes */
491             bc_ProcessDumpSchedule(aconfig);
492             return 0;
493         }
494     }
495     /* if we make it here, there's no such dump schedule entry */
496     return -1;
497 }
498
499
500 /* bc_ProcessDumpSchedule
501  *      Walk over the dump schedule list, building it into a tree.  This
502  * algorithm is simple, but takes O(N*2) operations to run, with N=number
503  * of dump schedule nodes. It probably will never matter
504  */
505
506 bc_ProcessDumpSchedule(aconfig)
507      register struct bc_config *aconfig;
508 {
509     register struct bc_dumpSchedule *tds;
510     struct bc_dumpSchedule *parentptr, *nodeptr;
511     int retval;
512
513     /* first, clear all the links on all entries so that this function
514      * may be called any number of times with no ill effects
515      */
516     for (tds = aconfig->dsched; tds; tds = tds->next) {
517         tds->parent = (struct bc_dumpSchedule *)0;
518         tds->nextSibling = (struct bc_dumpSchedule *)0;
519         tds->firstChild = (struct bc_dumpSchedule *)0;
520     }
521
522     for (tds = aconfig->dsched; tds; tds = tds->next) {
523         retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
524         if (retval != 0) {
525             printf("bc_processdumpschedule: finddump returns %d\n", retval);
526             exit(1);
527         }
528
529         /* only need to do work if it is not a root node */
530         if (parentptr != 0) {
531             nodeptr->parent = parentptr;
532             nodeptr->nextSibling = parentptr->firstChild;
533             parentptr->firstChild = nodeptr;
534         }
535     }
536     return 0;
537 }
538
539
540 /* FindDump
541  * entry:
542  * exit:
543  *      parentptr - set to parent node, if one exists
544  *      nodeptr - set to node requested
545  *
546  *      return values are:
547  *      0 - success, parentptr and nodeptr set appropriately
548  *      -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
549  *      -2 - path search error. Some node on the path does not exist.
550  *      -3 - name specification error
551  * notes:
552  *      pathname checking should be done externally. In particular, trailing
553  *      / symbols may return confusing error codes. (e.g on missing last
554  *      node returns -2 rather than -1)
555  */
556
557 int
558 FindDump(aconfig, nodeString, parentptr, nodeptr)
559      struct bc_config *aconfig;
560      char *nodeString;
561      struct bc_dumpSchedule **parentptr;
562      struct bc_dumpSchedule **nodeptr;
563 {
564     struct bc_dumpSchedule *dsptr;
565     char *separator;
566     int matchLength;
567     char *curptr;
568
569     *parentptr = 0;
570     *nodeptr = 0;
571
572     /* ensure first char is correct separator */
573     if ((nodeString[0] != '/')
574         || (strlen(&nodeString[0]) <= 1)
575         ) {
576         printf("FindDump: %s, error in dump name specification\n",
577                nodeString);
578         return (-3);
579     }
580
581     matchLength = 0;
582     curptr = &nodeString[1];    /* past first / */
583     separator = strchr(curptr, '/');
584     if (separator == 0)
585         matchLength = strlen(curptr) + 1;       /* +1 for leading / */
586     else
587         matchLength = (separator - &nodeString[0]);
588
589     /* printf("matchLength = %d\n", matchLength); */
590     while (1) {
591         /* now search all the nodes for this name */
592         for (dsptr = aconfig->dsched; dsptr != 0; dsptr = dsptr->next) {
593             /* printf("compare %s with %s for %d\n",
594              * dsptr->name, nodeString, matchLength); */
595             if (strlen(dsptr->name) != matchLength)
596                 continue;
597
598             if (strncmp(dsptr->name, nodeString, matchLength) == 0) {
599                 *nodeptr = dsptr;
600                 break;
601             }
602         }
603
604         if (nodeString[matchLength] == 0) {
605             /* last node in the path */
606             if (*nodeptr)
607                 return (0);     /* all ok */
608             else
609                 /* node not found; parent exists for non root nodes */
610                 return (-1);
611         }
612
613         if (*nodeptr == 0)
614             /* failed to find a node in the path */
615             return (-2);
616
617         curptr = separator + 1;
618         if (*curptr == 0) {
619             printf("FindDump: trailing / in %s\n", nodeString);
620             return (-3);
621         }
622
623         separator = strchr(curptr, '/');
624         if (separator == 0)
625             matchLength = strlen(&nodeString[0]);
626         else
627             matchLength = separator - &nodeString[0];
628
629         *parentptr = *nodeptr;
630         *nodeptr = 0;
631     }
632 }