2 * Copyright 2000, International Business Machines Corporation and others.
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
13 * (C) COPYRIGHT IBM CORPORATION 1987, 1998
14 * LICENSED MATERIALS - PROPERTY OF IBM
18 #include <afsconfig.h>
19 #include <afs/param.h>
24 #include <afs/com_err.h>
25 #include <afs/bubasics.h>
28 #include "bucoord_internal.h"
30 struct ubik_client
*cstructp
; /*Ptr to Ubik client structure */
32 static int FreeVolumeEntryList(struct bc_volumeEntry
*aentry
);
33 static int FreeVolumeEntry(struct bc_volumeEntry
*aentry
);
35 /* Code to maintain dump schedule and volume set abstractions.
36 * A volume set looks like this:
37 * vsname: servername partition-name <volume list>*
38 * A dump schedule looks like this:
39 * dsname: vsname period parent-ds
42 /* get partition id from a name */
44 bc_GetPartitionID(char *aname
, afs_int32
*aval
)
47 /*bc_GetPartitionID */
52 /* special-case "anything" */
53 if (strcmp(aname
, ".*") == 0) {
59 return -1; /* unknown */
60 /* numbers go straight through */
61 if (tc
>= '0' && tc
<= '9') {
62 *aval
= bc_SafeATOI(aname
);
65 /* otherwise check for vicepa or /vicepa, or just plain "a" */
67 if (strlen(aname
) <= 2) {
69 } else if (!strncmp(aname
, "/vicep", 6)) {
70 strncpy(ascii
, aname
+ 6, 2);
71 } else if (!strncmp(aname
, "vicep", 5)) {
72 strncpy(ascii
, aname
+ 5, 2);
74 return (BC_NOPARTITION
); /* bad partition name */
75 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
76 * from 0. Do the appropriate conversion */
78 /* one char name, 0..25 */
79 if (ascii
[0] < 'a' || ascii
[0] > 'z')
80 return -1; /* wrongo */
81 *aval
= ascii
[0] - 'a';
84 /* two char name, 26 .. <whatever> */
85 if (ascii
[0] < 'a' || ascii
[0] > 'z')
86 return -1; /* wrongo */
87 if (ascii
[1] < 'a' || ascii
[1] > 'z')
88 return -1; /* just as bad */
89 *aval
= (ascii
[0] - 'a') * 26 + (ascii
[1] - 'a') + 26;
92 } /*bc_GetPartitionID */
94 /*----------------------------------------------------------------------------
98 * Given a string containing a host name or its IP address in dot notation, fill in
99 * the given sockaddr with all the corresponding info.
102 * aname : Host name or dotted IP address.
103 * asockaddr: Ptr to sockaddr to fill in for the above host.
106 * 0 if everything went well,
107 * -1 if it couldn't be translated.
110 * Nothing interesting.
114 *----------------------------------------------------------------------------
118 bc_ParseHost(char *aname
, struct sockaddr_in
*asockaddr
)
122 struct hostent
*th
; /*Host entry */
123 afs_uint32 addr
; /*Converted address */
124 afs_int32 b1
, b2
, b3
, b4
; /*Byte-sized address chunks */
125 afs_int32 code
; /*Return code from sscanf() */
126 afs_int32 tmp1
, tmp2
;
129 * Try to parse the given name as a dot-notation IP address first.
131 code
= sscanf(aname
, "%d.%d.%d.%d", &b1
, &b2
, &b3
, &b4
);
134 * Four chunks were read, so we assume success. Construct the socket.
136 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
137 asockaddr
->sin_len
= sizeof(struct sockaddr_in
);
139 asockaddr
->sin_family
= AF_INET
;
140 asockaddr
->sin_port
= 0;
141 addr
= (b1
<< 24) | (b2
<< 16) | (b3
<< 8) | b4
;
142 memcpy(&tmp1
, &addr
, sizeof(afs_int32
));
144 memcpy(&asockaddr
->sin_addr
.s_addr
, &tmp2
, sizeof(afs_int32
));
149 * The given string isn't a dotted IP address. Try to map it as a host
150 * name, or leave it as a wild-card.
153 if (strcmp(aname
, ".*") == 0) {
154 memset(asockaddr
, 0, sizeof(struct sockaddr_in
));
158 th
= gethostbyname(aname
);
161 * No such luck, return failure.
166 * We found a mapping; construct the socket.
168 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
169 asockaddr
->sin_len
= sizeof(struct sockaddr_in
);
171 asockaddr
->sin_family
= AF_INET
;
172 asockaddr
->sin_port
= 0;
173 memcpy(&tmp1
, th
->h_addr
, sizeof(afs_int32
));
175 memcpy(&(asockaddr
->sin_addr
.s_addr
), &tmp2
,
176 sizeof(asockaddr
->sin_addr
.s_addr
));
182 /* create an empty volume set, new items are added via bc_AddVolumeItem */
184 bc_CreateVolumeSet(struct bc_config
*aconfig
, char *avolName
,
187 struct bc_volumeSet
**tlast
, *tset
, *nset
;
189 if (bc_FindVolumeSet(aconfig
, avolName
))
190 return -1; /* already exists */
191 /* move to end of the list */
193 nset
= calloc(1, sizeof(struct bc_volumeSet
));
194 nset
->flags
= aflags
;
195 nset
->name
= strdup(avolName
);
196 if (aflags
& VSFLAG_TEMPORARY
) {
197 /* Add to beginning of list */
198 nset
->next
= aconfig
->vset
;
199 aconfig
->vset
= nset
;
201 /* Add to end of list */
202 for (tlast
= &aconfig
->vset
, tset
= *tlast
; tset
;
203 tlast
= &tset
->next
, tset
= *tlast
);
210 FreeVolumeEntry(struct bc_volumeEntry
*aentry
)
213 free(aentry
->serverName
);
214 free(aentry
->partname
);
220 FreeVolumeEntryList(struct bc_volumeEntry
*aentry
)
222 struct bc_volumeEntry
*tnext
;
225 tnext
= aentry
->next
;
226 FreeVolumeEntry(aentry
);
235 FreeVolumeSet(struct bc_volumeSet
*avset
)
237 FreeVolumeEntryList(avset
->ventries
);
243 bc_DeleteVolumeSet(struct bc_config
*aconfig
, char *avolName
,
246 struct bc_volumeSet
**tlast
, *tset
;
249 tlast
= &aconfig
->vset
;
250 for (tset
= *tlast
; tset
; tlast
= &tset
->next
, tset
= *tlast
) {
251 if (strcmp(avolName
, tset
->name
) == 0) {
252 *flags
= tset
->flags
; /* Remember flags */
253 *tlast
= tset
->next
; /* Remove from chain */
254 FreeVolumeSet(tset
); /* Free the volume set */
259 /* if we get here, we didn't find the item */
264 bc_DeleteVolumeItem(struct bc_config
*aconfig
, char *avolName
,
268 struct bc_volumeSet
*tset
;
269 struct bc_volumeEntry
*tentry
, **tlast
;
271 tset
= bc_FindVolumeSet(aconfig
, avolName
);
275 tlast
= &tset
->ventries
;
276 for (i
= 1, tentry
= *tlast
; tentry
;
277 tlast
= &tentry
->next
, tentry
= *tlast
, i
++) {
279 /* found entry we want */
280 *tlast
= tentry
->next
;
281 FreeVolumeEntry(tentry
);
285 return -2; /* not found */
289 bc_AddVolumeItem(struct bc_config
*aconfig
, char *avolName
, char *ahost
,
290 char *apart
, char *avol
)
292 struct bc_volumeSet
*tset
;
293 struct bc_volumeEntry
**tlast
, *tentry
;
296 tset
= bc_FindVolumeSet(aconfig
, avolName
);
298 return (BC_NOVOLSET
);
300 /* otherwise append this item to the end of the real list */
301 tlast
= &tset
->ventries
;
303 /* move to end of the list */
304 for (tentry
= *tlast
; tentry
; tlast
= &tentry
->next
, tentry
= *tlast
);
305 tentry
= calloc(1, sizeof(struct bc_volumeEntry
));
306 tentry
->serverName
= strdup(ahost
);
307 tentry
->partname
= strdup(apart
);
308 tentry
->name
= strdup(avol
);
310 code
= bc_ParseHost(tentry
->serverName
, &tentry
->server
);
314 code
= bc_GetPartitionID(tentry
->partname
, &tentry
->partition
);
318 *tlast
= tentry
; /* thread on the list */
322 struct bc_volumeSet
*
323 bc_FindVolumeSet(struct bc_config
*aconfig
, char *aname
)
324 { /*bc_FindVolumeSet */
326 struct bc_volumeSet
*tvs
;
328 for (tvs
= aconfig
->vset
; tvs
; tvs
= tvs
->next
) {
329 if (!strcmp(tvs
->name
, aname
))
332 return (struct bc_volumeSet
*)0;
334 } /*bc_FindVolumeSet */
336 /* ------------------------------------
337 * dumpschedule management code
338 * ------------------------------------
341 /* bc_CreateDumpSchedule
342 * Add another node to the dump schedule.
344 * aconfig - in core configuration structures
345 * adumpName - name of new dump node
346 * expDate - expiration date
347 * expType - absolute or relative
351 bc_CreateDumpSchedule(struct bc_config
*aconfig
, char *adumpName
,
352 afs_int32 expDate
, afs_int32 expType
)
354 struct bc_dumpSchedule
*tdump
;
355 struct bc_dumpSchedule
*parent
, *node
;
358 if (strcmp(adumpName
, "none") == 0)
359 return -2; /* invalid name */
361 code
= FindDump(aconfig
, adumpName
, &parent
, &node
);
363 return -1; /* node already exists */
365 return -2; /* name specification error */
367 tdump
= calloc(1, sizeof(struct bc_dumpSchedule
));
369 /* prepend this node to the dump schedule list */
370 tdump
->next
= aconfig
->dsched
;
371 aconfig
->dsched
= tdump
;
373 /* save the name of this dump node */
374 tdump
->name
= strdup(adumpName
);
376 /* expiration information */
377 tdump
->expDate
= expDate
;
378 tdump
->expType
= expType
;
380 bc_ProcessDumpSchedule(aconfig
); /* redo tree */
385 /* Recursively remove this node and all of its children from aconfig's
386 * list of dumps. Note that this leaves the sibling pointers damaged (pointing
387 * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
390 bc_DeleteDumpScheduleAddr(struct bc_config
*aconfig
,
391 struct bc_dumpSchedule
*adumpAddr
)
393 struct bc_dumpSchedule
**tlast
, *tdump
;
394 struct bc_dumpSchedule
*tnext
;
396 /* knock off all children first */
397 for (tdump
= adumpAddr
->firstChild
; tdump
; tdump
= tnext
) {
398 /* extract next ptr now, since will be freed by recursive call below */
399 tnext
= tdump
->nextSibling
;
400 bc_DeleteDumpScheduleAddr(aconfig
, tdump
);
403 /* finally, remove us from the list of good dudes */
404 for (tlast
= &aconfig
->dsched
, tdump
= *tlast
; tdump
;
405 tlast
= &tdump
->next
, tdump
= *tlast
) {
406 if (tdump
== adumpAddr
) {
407 /* found the one we're looking for */
408 *tlast
= tdump
->next
; /* remove us from basic list */
417 /* bc_FindDumpSchedule
418 * Finds dump schedule aname by doing a linear search
420 * aconfig - handle for incore configuration tables
421 * aname - (path)name to match on
423 * 0 for failure, ptr to dumpschedule for success
426 struct bc_dumpSchedule
*
427 bc_FindDumpSchedule(struct bc_config
*aconfig
, char *aname
)
429 struct bc_dumpSchedule
*tds
;
430 for (tds
= aconfig
->dsched
; tds
; tds
= tds
->next
) {
431 if (!strcmp(tds
->name
, aname
))
434 return (struct bc_dumpSchedule
*)0;
437 /* bc_DeleteDumpSchedule
438 * Delete dump node adumpName from the dump schedule
442 bc_DeleteDumpSchedule(struct bc_config
*aconfig
, char *adumpName
)
444 struct bc_dumpSchedule
*tdump
;
446 /* does a linear search of the dump schedules in order to find
449 for (tdump
= aconfig
->dsched
; tdump
; tdump
= tdump
->next
) {
450 if (strcmp(tdump
->name
, adumpName
) == 0) {
451 /* found it, we can zap recursively */
452 bc_DeleteDumpScheduleAddr(aconfig
, tdump
);
453 /* tree's been pruned, but we have to recompute the internal pointers
454 * from first principles, since we didn't bother to maintain
455 * the sibling and children pointers during the call to delete
457 bc_ProcessDumpSchedule(aconfig
);
461 /* if we make it here, there's no such dump schedule entry */
466 /* bc_ProcessDumpSchedule
467 * Walk over the dump schedule list, building it into a tree. This
468 * algorithm is simple, but takes O(N*2) operations to run, with N=number
469 * of dump schedule nodes. It probably will never matter
473 bc_ProcessDumpSchedule(struct bc_config
*aconfig
)
475 struct bc_dumpSchedule
*tds
;
476 struct bc_dumpSchedule
*parentptr
, *nodeptr
;
479 /* first, clear all the links on all entries so that this function
480 * may be called any number of times with no ill effects
482 for (tds
= aconfig
->dsched
; tds
; tds
= tds
->next
) {
483 tds
->parent
= (struct bc_dumpSchedule
*)0;
484 tds
->nextSibling
= (struct bc_dumpSchedule
*)0;
485 tds
->firstChild
= (struct bc_dumpSchedule
*)0;
488 for (tds
= aconfig
->dsched
; tds
; tds
= tds
->next
) {
489 retval
= FindDump(aconfig
, tds
->name
, &parentptr
, &nodeptr
);
491 printf("bc_processdumpschedule: finddump returns %d\n", retval
);
495 /* only need to do work if it is not a root node */
496 if (parentptr
!= 0) {
497 nodeptr
->parent
= parentptr
;
498 nodeptr
->nextSibling
= parentptr
->firstChild
;
499 parentptr
->firstChild
= nodeptr
;
509 * parentptr - set to parent node, if one exists
510 * nodeptr - set to node requested
513 * 0 - success, parentptr and nodeptr set appropriately
514 * -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
515 * -2 - path search error. Some node on the path does not exist.
516 * -3 - name specification error
518 * pathname checking should be done externally. In particular, trailing
519 * / symbols may return confusing error codes. (e.g on missing last
520 * node returns -2 rather than -1)
524 FindDump(struct bc_config
*aconfig
, char *nodeString
,
525 struct bc_dumpSchedule
**parentptr
,
526 struct bc_dumpSchedule
**nodeptr
)
528 struct bc_dumpSchedule
*dsptr
;
536 /* ensure first char is correct separator */
537 if ((nodeString
[0] != '/')
538 || (strlen(&nodeString
[0]) <= 1)
540 printf("FindDump: %s, error in dump name specification\n",
545 curptr
= &nodeString
[1]; /* past first / */
546 separator
= strchr(curptr
, '/');
548 matchLength
= strlen(curptr
) + 1; /* +1 for leading / */
550 matchLength
= (separator
- &nodeString
[0]);
552 /* printf("matchLength = %d\n", matchLength); */
554 /* now search all the nodes for this name */
555 for (dsptr
= aconfig
->dsched
; dsptr
!= 0; dsptr
= dsptr
->next
) {
556 /* printf("compare %s with %s for %d\n",
557 * dsptr->name, nodeString, matchLength); */
558 if (strlen(dsptr
->name
) != matchLength
)
561 if (strncmp(dsptr
->name
, nodeString
, matchLength
) == 0) {
567 if (nodeString
[matchLength
] == 0) {
568 /* last node in the path */
570 return (0); /* all ok */
572 /* node not found; parent exists for non root nodes */
577 /* failed to find a node in the path */
580 curptr
= separator
+ 1;
582 printf("FindDump: trailing / in %s\n", nodeString
);
586 separator
= strchr(curptr
, '/');
588 matchLength
= strlen(&nodeString
[0]);
590 matchLength
= separator
- &nodeString
[0];
592 *parentptr
= *nodeptr
;