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 <afs/param.h>
19 #include <afsconfig.h>
23 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
32 #include <sys/param.h>
35 #include <afs/com_err.h>
37 #include <afs/bubasics.h>
40 extern struct bc_config *bc_globalConfig;
41 extern FILE *bc_open();
42 extern void bc_HandleMisc();
45 static char db_dsvs = 0; /*Assume debugging output turned off*/
46 static char mn[] = "dsvs"; /*Module name*/
48 struct ubik_client *cstructp; /*Ptr to Ubik client structure*/
50 extern struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *cf, char *name);
53 /* Code to maintain dump schedule and volume set abstractions.
54 * A volume set looks like this:
55 * vsname: servername partition-name <volume list>*
56 * A dump schedule looks like this:
57 * dsname: vsname period parent-ds
60 /* get partition id from a name */
61 afs_int32 bc_GetPartitionID(aname, aval)
65 /*bc_GetPartitionID */
70 /* special-case "anything" */
71 if (strcmp(aname, ".*") == 0) {
76 if (tc == 0) 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) {
87 else if (!strncmp(aname, "/vicep", 6)) {
88 strncpy(ascii, aname+6, 2);
90 else if (!strncmp(aname, "vicep", 5)) {
91 strncpy(ascii, aname+5, 2);
93 else return(BC_NOPARTITION); /* bad partition name */
94 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
95 from 0. Do the appropriate conversion */
97 /* one char name, 0..25 */
98 if (ascii[0] < 'a' || ascii[0] > 'z') return -1; /* wrongo */
99 *aval = ascii[0] - 'a';
103 /* two char name, 26 .. <whatever> */
104 if (ascii[0] < 'a' || ascii[0] > 'z') return -1; /* wrongo */
105 if (ascii[1] < 'a' || ascii[1] > 'z') 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 *----------------------------------------------------------------------------
134 int bc_ParseHost(aname, asockaddr)
136 struct sockaddr_in *asockaddr;
140 register struct hostent *th; /*Host entry*/
141 afs_int32 addr; /*Converted address*/
142 afs_int32 b1, b2, b3, b4; /*Byte-sized address chunks*/
143 register afs_int32 code; /*Return code from sscanf()*/
147 * Try to parse the given name as a dot-notation IP address first.
149 code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
152 * Four chunks were read, so we assume success. Construct the socket.
154 asockaddr->sin_family = AF_INET;
155 asockaddr->sin_port = 0;
156 addr = (b1<<24) | (b2<<16) | (b3<<8) | b4;
157 bcopy(&addr,&tmp1,sizeof(afs_int32));
159 bcopy(&tmp2, &asockaddr->sin_addr.s_addr, sizeof(afs_int32));
164 * The given string isn't a dotted IP address. Try to map it as a host
165 * name, or leave it as a wild-card.
168 if (strcmp(aname, ".*") == 0) {
169 bzero(asockaddr, sizeof(struct sockaddr_in));
173 th = gethostbyname(aname);
176 * No such luck, return failure.
181 * We found a mapping; construct the socket.
183 asockaddr->sin_family = AF_INET;
184 asockaddr->sin_port = 0;
185 bcopy(th->h_addr,&tmp1,sizeof(afs_int32));
187 bcopy(&tmp2,&(asockaddr->sin_addr.s_addr),
188 sizeof(asockaddr->sin_addr.s_addr));
194 /* create an empty volume set, new items are added via bc_AddVolumeItem */
195 bc_CreateVolumeSet(aconfig, avolName, aflags)
196 struct bc_config *aconfig;
200 register struct bc_volumeSet **tlast, *tset, *nset;
202 if (bc_FindVolumeSet(aconfig, avolName)) return -1; /* already exists */
203 /* move to end of the list */
205 nset = (struct bc_volumeSet *) malloc(sizeof(struct bc_volumeSet));
206 bzero(nset, sizeof(*nset));
207 nset->flags = aflags;
208 nset->name = (char *) malloc(strlen(avolName)+1);
209 strcpy(nset->name, avolName);
210 if (aflags & VSFLAG_TEMPORARY) {
211 /* Add to beginning of list */
212 nset->next = aconfig->vset;
213 aconfig->vset = nset;
215 /* Add to end of list */
216 for(tlast = &aconfig->vset, tset = *tlast; tset; tlast = &tset->next, tset = *tlast);
224 void FreeVolumeSet(avset)
225 struct bc_volumeSet *avset;
227 FreeVolumeEntryList(avset->ventries);
232 static FreeVolumeEntryList(aentry)
233 register struct bc_volumeEntry *aentry; {
234 register struct bc_volumeEntry *tnext;
237 tnext = aentry->next;
238 FreeVolumeEntry(aentry);
244 static FreeVolumeEntry(aentry)
245 register struct bc_volumeEntry *aentry; {
247 free(aentry->serverName);
248 free(aentry->partname);
253 bc_DeleteVolumeSet(aconfig, avolName, flags)
254 struct bc_config *aconfig;
258 register struct bc_volumeSet **tlast, *tset;
261 tlast = &aconfig->vset;
262 for(tset = *tlast; tset; tlast = &tset->next, tset = *tlast) {
263 if (strcmp(avolName, tset->name) == 0) {
264 *flags = tset->flags; /* Remember flags */
265 *tlast = tset->next; /* Remove from chain */
266 FreeVolumeSet(tset); /* Free the volume set */
271 /* if we get here, we didn't find the item */
275 bc_DeleteVolumeItem(aconfig, avolName, anumber)
276 struct bc_config *aconfig;
280 register afs_int32 i;
281 register struct bc_volumeSet *tset;
282 register struct bc_volumeEntry *tentry, **tlast;
284 tset = bc_FindVolumeSet(aconfig, avolName);
285 if (!tset) return -1;
287 tlast = &tset->ventries;
288 for(i=1, tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast, i++) {
290 /* found entry we want */
291 *tlast = tentry->next;
292 FreeVolumeEntry(tentry);
296 return -2; /* not found */
299 bc_AddVolumeItem(aconfig, avolName, ahost, apart, avol)
300 struct bc_config *aconfig;
302 char *ahost, *apart, *avol;
304 struct bc_volumeSet *tset;
305 register struct bc_volumeEntry **tlast, *tentry;
306 register afs_int32 code;
308 tset = bc_FindVolumeSet(aconfig, avolName);
309 if (!tset) return(BC_NOVOLSET);
311 /* otherwise append this item to the end of the real list */
312 tlast = &tset->ventries;
314 /* move to end of the list */
315 for(tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast);
316 tentry = (struct bc_volumeEntry *) malloc(sizeof(struct bc_volumeEntry));
317 bzero(tentry, sizeof(*tentry));
318 tentry->serverName = (char *) malloc(strlen(ahost)+1);
319 strcpy(tentry->serverName, ahost);
320 tentry->partname = (char *) malloc(strlen(apart)+1);
321 strcpy(tentry->partname, apart);
322 tentry->name = (char *) malloc(strlen(avol)+1);
323 strcpy(tentry->name, avol);
325 code = bc_ParseHost(tentry->serverName, &tentry->server);
329 code = bc_GetPartitionID(tentry->partname, &tentry->partition);
333 *tlast = tentry; /* thread on the list */
337 struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
338 { /*bc_FindVolumeSet*/
340 register struct bc_volumeSet *tvs;
342 for(tvs = aconfig->vset; tvs; tvs=tvs->next) {
343 if (!strcmp(tvs->name, aname))
346 return(struct bc_volumeSet *)0;
348 }/*bc_FindVolumeSet*/
350 /* ------------------------------------
351 * dumpschedule management code
352 * ------------------------------------
355 /* bc_CreateDumpSchedule
356 * Add another node to the dump schedule.
358 * aconfig - in core configuration structures
359 * adumpName - name of new dump node
360 * expDate - expiration date
361 * expType - absolute or relative
364 bc_CreateDumpSchedule(aconfig,adumpName, expDate, expType)
365 struct bc_config *aconfig;
370 register struct bc_dumpSchedule **tlast, *tdump;
371 struct bc_dumpSchedule *parent, *node;
374 if(strcmp(adumpName, "none") == 0)
375 return -2; /* invalid name */
377 code = FindDump(aconfig, adumpName, &parent, &node);
379 return -1; /* node already exists */
380 else if ( code != -1 )
381 return -2; /* name specification error */
383 tdump = (struct bc_dumpSchedule *) malloc(sizeof(struct bc_dumpSchedule));
384 bzero(tdump, sizeof(*tdump));
386 /* prepend this node to the dump schedule list */
387 tdump->next = aconfig->dsched;
388 aconfig->dsched = tdump;
390 /* save the name of this dump node */
391 tdump->name = (char *) malloc(strlen(adumpName)+1);
392 strcpy(tdump->name, adumpName);
394 /* expiration information */
395 tdump->expDate = expDate;
396 tdump->expType = expType;
398 bc_ProcessDumpSchedule(aconfig); /* redo tree */
403 /* Recursively remove this node and all of its children from aconfig's
404 * list of dumps. Note that this leaves the sibling pointers damaged (pointing
405 * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
408 bc_DeleteDumpScheduleAddr(aconfig, adumpAddr)
409 struct bc_config *aconfig;
410 struct bc_dumpSchedule *adumpAddr; {
411 register struct bc_dumpSchedule **tlast, *tdump;
412 register struct bc_dumpSchedule *tnext;
414 /* knock off all children first */
415 for(tdump = adumpAddr->firstChild; tdump; tdump = tnext) {
416 /* extract next ptr now, since will be freed by recursive call below */
417 tnext = tdump->nextSibling;
418 bc_DeleteDumpScheduleAddr(aconfig, tdump);
421 /* finally, remove us from the list of good dudes */
422 for(tlast = &aconfig->dsched, tdump = *tlast; tdump;
423 tlast = &tdump->next, tdump = *tlast) {
424 if (tdump == adumpAddr) {
425 /* found the one we're looking for */
426 *tlast = tdump->next; /* remove us from basic list */
435 /* bc_FindDumpSchedule
436 * Finds dump schedule aname by doing a linear search
438 * aconfig - handle for incore configuration tables
439 * aname - (path)name to match on
441 * 0 for failure, ptr to dumpschedule for success
444 struct bc_dumpSchedule *bc_FindDumpSchedule(aconfig, aname)
446 struct bc_config *aconfig; {
447 register struct bc_dumpSchedule *tds;
448 for(tds=aconfig->dsched; tds; tds=tds->next) {
449 if (!strcmp(tds->name, aname))
452 return (struct bc_dumpSchedule *) 0;
455 /* bc_DeleteDumpSchedule
456 * Delete dump node adumpName from the dump schedule
459 bc_DeleteDumpSchedule(aconfig, adumpName)
460 struct bc_config *aconfig;
462 register struct bc_dumpSchedule *tdump;
464 /* does a linear search of the dump schedules in order to find
467 for(tdump = aconfig->dsched; tdump; tdump=tdump->next) {
468 if (strcmp(tdump->name, adumpName)==0) {
469 /* found it, we can zap recursively */
470 bc_DeleteDumpScheduleAddr(aconfig, tdump);
471 /* tree's been pruned, but we have to recompute the internal pointers
472 from first principles, since we didn't bother to maintain
473 the sibling and children pointers during the call to delete
475 bc_ProcessDumpSchedule(aconfig);
479 /* if we make it here, there's no such dump schedule entry */
484 /* bc_ProcessDumpSchedule
485 * Walk over the dump schedule list, building it into a tree. This
486 * algorithm is simple, but takes O(N*2) operations to run, with N=number
487 * of dump schedule nodes. It probably will never matter
490 bc_ProcessDumpSchedule(aconfig)
491 register struct bc_config *aconfig;
493 register struct bc_dumpSchedule *tds, *uds;
494 struct bc_dumpSchedule *parentptr, *nodeptr;
497 /* first, clear all the links on all entries so that this function
498 * may be called any number of times with no ill effects
500 for(tds = aconfig->dsched; tds; tds=tds->next)
502 tds->parent = (struct bc_dumpSchedule *) 0;
503 tds->nextSibling = (struct bc_dumpSchedule *) 0;
504 tds->firstChild = (struct bc_dumpSchedule *) 0;
507 for(tds = aconfig->dsched; tds; tds=tds->next)
509 retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
512 printf("bc_processdumpschedule: finddump returns %d\n", retval);
516 /* only need to do work if it is not a root node */
517 if ( parentptr != 0 )
519 nodeptr->parent = parentptr;
520 nodeptr->nextSibling = parentptr->firstChild;
521 parentptr->firstChild = nodeptr;
531 * parentptr - set to parent node, if one exists
532 * nodeptr - set to node requested
535 * 0 - success, parentptr and nodeptr set appropriately
536 * -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
537 * -2 - path search error. Some node on the path does not exist.
538 * -3 - name specification error
540 * pathname checking should be done externally. In particular, trailing
541 * / symbols may return confusing error codes. (e.g on missing last
542 * node returns -2 rather than -1)
546 FindDump(aconfig, nodeString, parentptr, nodeptr)
547 struct bc_config *aconfig;
549 struct bc_dumpSchedule **parentptr;
550 struct bc_dumpSchedule **nodeptr;
552 struct bc_dumpSchedule *dsptr;
560 /* ensure first char is correct separator */
561 if ( (nodeString[0] != '/')
562 || (strlen(&nodeString[0]) <= 1)
565 printf("FindDump: %s, error in dump name specification\n", nodeString);
570 curptr = &nodeString[1]; /* past first / */
571 separator = index(curptr, '/');
572 if ( separator == 0 )
573 matchLength = strlen(curptr) + 1; /* +1 for leading / */
575 matchLength = (separator-&nodeString[0]);
577 /* printf("matchLength = %d\n", matchLength); */
580 /* now search all the nodes for this name */
581 for ( dsptr = aconfig->dsched; dsptr != 0; dsptr = dsptr->next)
583 /* printf("compare %s with %s for %d\n",
584 dsptr->name, nodeString, matchLength); */
585 if ( strlen(dsptr->name) != matchLength )
588 if ( strncmp(dsptr->name, nodeString, matchLength) == 0)
595 if ( nodeString[matchLength] == 0 )
597 /* last node in the path */
599 return(0); /* all ok */
601 /* node not found; parent exists for non root nodes */
606 /* failed to find a node in the path */
609 curptr = separator+1;
612 printf("FindDump: trailing / in %s\n", nodeString);
616 separator = index(curptr, '/');
617 if ( separator == 0 )
618 matchLength = strlen(&nodeString[0]);
620 matchLength = separator-&nodeString[0];
622 *parentptr = *nodeptr;