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 <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
33 #include <sys/param.h>
36 #include <afs/com_err.h>
38 #include <afs/bubasics.h>
41 static char db_dsvs = 0; /*Assume debugging output turned off */
42 static char mn[] = "dsvs"; /*Module name */
44 struct ubik_client *cstructp; /*Ptr to Ubik client structure */
46 extern struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *cf,
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
57 /* get partition id from a name */
59 bc_GetPartitionID(aname, aval)
64 /*bc_GetPartitionID */
69 /* special-case "anything" */
70 if (strcmp(aname, ".*") == 0) {
76 return -1; /* unknown */
77 /* numbers go straight through */
78 if (tc >= '0' && tc <= '9') {
79 *aval = bc_SafeATOI(aname);
82 /* otherwise check for vicepa or /vicepa, or just plain "a" */
84 if (strlen(aname) <= 2) {
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);
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 */
95 /* one char name, 0..25 */
96 if (ascii[0] < 'a' || ascii[0] > 'z')
97 return -1; /* wrongo */
98 *aval = ascii[0] - 'a';
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;
109 } /*bc_GetPartitionID */
111 /*----------------------------------------------------------------------------
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.
119 * aname : Host name or dotted IP address.
120 * asockaddr: Ptr to sockaddr to fill in for the above host.
123 * 0 if everything went well,
124 * -1 if it couldn't be translated.
127 * Nothing interesting.
131 *----------------------------------------------------------------------------
135 bc_ParseHost(aname, asockaddr)
137 struct sockaddr_in *asockaddr;
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;
148 * Try to parse the given name as a dot-notation IP address first.
150 code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
153 * Four chunks were read, so we assume success. Construct the socket.
155 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
156 asockaddr->sin_len = sizeof(struct sockaddr_in);
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));
163 memcpy(&asockaddr->sin_addr.s_addr, &tmp2, sizeof(afs_int32));
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.
172 if (strcmp(aname, ".*") == 0) {
173 memset(asockaddr, 0, sizeof(struct sockaddr_in));
177 th = gethostbyname(aname);
180 * No such luck, return failure.
185 * We found a mapping; construct the socket.
187 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
188 asockaddr->sin_len = sizeof(struct sockaddr_in);
190 asockaddr->sin_family = AF_INET;
191 asockaddr->sin_port = 0;
192 memcpy(&tmp1, th->h_addr, sizeof(afs_int32));
194 memcpy(&(asockaddr->sin_addr.s_addr), &tmp2,
195 sizeof(asockaddr->sin_addr.s_addr));
201 /* create an empty volume set, new items are added via bc_AddVolumeItem */
203 bc_CreateVolumeSet(struct bc_config *aconfig, char *avolName,
206 register struct bc_volumeSet **tlast, *tset, *nset;
208 if (bc_FindVolumeSet(aconfig, avolName))
209 return -1; /* already exists */
210 /* move to end of the list */
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;
222 /* Add to end of list */
223 for (tlast = &aconfig->vset, tset = *tlast; tset;
224 tlast = &tset->next, tset = *tlast);
231 FreeVolumeEntry(register struct bc_volumeEntry *aentry)
234 free(aentry->serverName);
235 free(aentry->partname);
241 FreeVolumeEntryList(register struct bc_volumeEntry *aentry)
243 register struct bc_volumeEntry *tnext;
246 tnext = aentry->next;
247 FreeVolumeEntry(aentry);
256 FreeVolumeSet(struct bc_volumeSet *avset)
258 FreeVolumeEntryList(avset->ventries);
264 bc_DeleteVolumeSet(struct bc_config *aconfig, char *avolName,
267 register struct bc_volumeSet **tlast, *tset;
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 */
280 /* if we get here, we didn't find the item */
285 bc_DeleteVolumeItem(struct bc_config *aconfig, char *avolName,
288 register afs_int32 i;
289 register struct bc_volumeSet *tset;
290 register struct bc_volumeEntry *tentry, **tlast;
292 tset = bc_FindVolumeSet(aconfig, avolName);
296 tlast = &tset->ventries;
297 for (i = 1, tentry = *tlast; tentry;
298 tlast = &tentry->next, tentry = *tlast, i++) {
300 /* found entry we want */
301 *tlast = tentry->next;
302 FreeVolumeEntry(tentry);
306 return -2; /* not found */
309 bc_AddVolumeItem(aconfig, avolName, ahost, apart, avol)
310 struct bc_config *aconfig;
312 char *ahost, *apart, *avol;
314 struct bc_volumeSet *tset;
315 register struct bc_volumeEntry **tlast, *tentry;
316 register afs_int32 code;
318 tset = bc_FindVolumeSet(aconfig, avolName);
320 return (BC_NOVOLSET);
322 /* otherwise append this item to the end of the real list */
323 tlast = &tset->ventries;
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);
336 code = bc_ParseHost(tentry->serverName, &tentry->server);
340 code = bc_GetPartitionID(tentry->partname, &tentry->partition);
344 *tlast = tentry; /* thread on the list */
348 struct bc_volumeSet *
349 bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
350 { /*bc_FindVolumeSet */
352 register struct bc_volumeSet *tvs;
354 for (tvs = aconfig->vset; tvs; tvs = tvs->next) {
355 if (!strcmp(tvs->name, aname))
358 return (struct bc_volumeSet *)0;
360 } /*bc_FindVolumeSet */
362 /* ------------------------------------
363 * dumpschedule management code
364 * ------------------------------------
367 /* bc_CreateDumpSchedule
368 * Add another node to the dump schedule.
370 * aconfig - in core configuration structures
371 * adumpName - name of new dump node
372 * expDate - expiration date
373 * expType - absolute or relative
376 bc_CreateDumpSchedule(aconfig, adumpName, expDate, expType)
377 struct bc_config *aconfig;
382 register struct bc_dumpSchedule *tdump;
383 struct bc_dumpSchedule *parent, *node;
386 if (strcmp(adumpName, "none") == 0)
387 return -2; /* invalid name */
389 code = FindDump(aconfig, adumpName, &parent, &node);
391 return -1; /* node already exists */
393 return -2; /* name specification error */
395 tdump = (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
396 memset(tdump, 0, sizeof(*tdump));
398 /* prepend this node to the dump schedule list */
399 tdump->next = aconfig->dsched;
400 aconfig->dsched = tdump;
402 /* save the name of this dump node */
403 tdump->name = (char *)malloc(strlen(adumpName) + 1);
404 strcpy(tdump->name, adumpName);
406 /* expiration information */
407 tdump->expDate = expDate;
408 tdump->expType = expType;
410 bc_ProcessDumpSchedule(aconfig); /* redo tree */
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.
420 bc_DeleteDumpScheduleAddr(aconfig, adumpAddr)
421 struct bc_config *aconfig;
422 struct bc_dumpSchedule *adumpAddr;
424 register struct bc_dumpSchedule **tlast, *tdump;
425 register struct bc_dumpSchedule *tnext;
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);
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 */
448 /* bc_FindDumpSchedule
449 * Finds dump schedule aname by doing a linear search
451 * aconfig - handle for incore configuration tables
452 * aname - (path)name to match on
454 * 0 for failure, ptr to dumpschedule for success
457 struct bc_dumpSchedule *
458 bc_FindDumpSchedule(aconfig, aname)
460 struct bc_config *aconfig;
462 register struct bc_dumpSchedule *tds;
463 for (tds = aconfig->dsched; tds; tds = tds->next) {
464 if (!strcmp(tds->name, aname))
467 return (struct bc_dumpSchedule *)0;
470 /* bc_DeleteDumpSchedule
471 * Delete dump node adumpName from the dump schedule
474 bc_DeleteDumpSchedule(aconfig, adumpName)
475 struct bc_config *aconfig;
478 register struct bc_dumpSchedule *tdump;
480 /* does a linear search of the dump schedules in order to find
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
491 bc_ProcessDumpSchedule(aconfig);
495 /* if we make it here, there's no such dump schedule entry */
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
506 bc_ProcessDumpSchedule(aconfig)
507 register struct bc_config *aconfig;
509 register struct bc_dumpSchedule *tds;
510 struct bc_dumpSchedule *parentptr, *nodeptr;
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
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;
522 for (tds = aconfig->dsched; tds; tds = tds->next) {
523 retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
525 printf("bc_processdumpschedule: finddump returns %d\n", retval);
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;
543 * parentptr - set to parent node, if one exists
544 * nodeptr - set to node requested
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
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)
558 FindDump(aconfig, nodeString, parentptr, nodeptr)
559 struct bc_config *aconfig;
561 struct bc_dumpSchedule **parentptr;
562 struct bc_dumpSchedule **nodeptr;
564 struct bc_dumpSchedule *dsptr;
572 /* ensure first char is correct separator */
573 if ((nodeString[0] != '/')
574 || (strlen(&nodeString[0]) <= 1)
576 printf("FindDump: %s, error in dump name specification\n",
582 curptr = &nodeString[1]; /* past first / */
583 separator = strchr(curptr, '/');
585 matchLength = strlen(curptr) + 1; /* +1 for leading / */
587 matchLength = (separator - &nodeString[0]);
589 /* printf("matchLength = %d\n", matchLength); */
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)
598 if (strncmp(dsptr->name, nodeString, matchLength) == 0) {
604 if (nodeString[matchLength] == 0) {
605 /* last node in the path */
607 return (0); /* all ok */
609 /* node not found; parent exists for non root nodes */
614 /* failed to find a node in the path */
617 curptr = separator + 1;
619 printf("FindDump: trailing / in %s\n", nodeString);
623 separator = strchr(curptr, '/');
625 matchLength = strlen(&nodeString[0]);
627 matchLength = separator - &nodeString[0];
629 *parentptr = *nodeptr;