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 */
202 bc_CreateVolumeSet(aconfig, avolName, aflags)
203 struct bc_config *aconfig;
207 register struct bc_volumeSet **tlast, *tset, *nset;
209 if (bc_FindVolumeSet(aconfig, avolName))
210 return -1; /* already exists */
211 /* move to end of the list */
213 nset = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
214 memset(nset, 0, sizeof(*nset));
215 nset->flags = aflags;
216 nset->name = (char *)malloc(strlen(avolName) + 1);
217 strcpy(nset->name, avolName);
218 if (aflags & VSFLAG_TEMPORARY) {
219 /* Add to beginning of list */
220 nset->next = aconfig->vset;
221 aconfig->vset = nset;
223 /* Add to end of list */
224 for (tlast = &aconfig->vset, tset = *tlast; tset;
225 tlast = &tset->next, tset = *tlast);
235 struct bc_volumeSet *avset;
237 FreeVolumeEntryList(avset->ventries);
243 FreeVolumeEntryList(aentry)
244 register struct bc_volumeEntry *aentry;
246 register struct bc_volumeEntry *tnext;
249 tnext = aentry->next;
250 FreeVolumeEntry(aentry);
257 FreeVolumeEntry(aentry)
258 register struct bc_volumeEntry *aentry;
261 free(aentry->serverName);
262 free(aentry->partname);
267 bc_DeleteVolumeSet(aconfig, avolName, flags)
268 struct bc_config *aconfig;
272 register struct bc_volumeSet **tlast, *tset;
275 tlast = &aconfig->vset;
276 for (tset = *tlast; tset; tlast = &tset->next, tset = *tlast) {
277 if (strcmp(avolName, tset->name) == 0) {
278 *flags = tset->flags; /* Remember flags */
279 *tlast = tset->next; /* Remove from chain */
280 FreeVolumeSet(tset); /* Free the volume set */
285 /* if we get here, we didn't find the item */
289 bc_DeleteVolumeItem(aconfig, avolName, anumber)
290 struct bc_config *aconfig;
294 register afs_int32 i;
295 register struct bc_volumeSet *tset;
296 register struct bc_volumeEntry *tentry, **tlast;
298 tset = bc_FindVolumeSet(aconfig, avolName);
302 tlast = &tset->ventries;
303 for (i = 1, tentry = *tlast; tentry;
304 tlast = &tentry->next, tentry = *tlast, i++) {
306 /* found entry we want */
307 *tlast = tentry->next;
308 FreeVolumeEntry(tentry);
312 return -2; /* not found */
315 bc_AddVolumeItem(aconfig, avolName, ahost, apart, avol)
316 struct bc_config *aconfig;
318 char *ahost, *apart, *avol;
320 struct bc_volumeSet *tset;
321 register struct bc_volumeEntry **tlast, *tentry;
322 register afs_int32 code;
324 tset = bc_FindVolumeSet(aconfig, avolName);
326 return (BC_NOVOLSET);
328 /* otherwise append this item to the end of the real list */
329 tlast = &tset->ventries;
331 /* move to end of the list */
332 for (tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast);
333 tentry = (struct bc_volumeEntry *)malloc(sizeof(struct bc_volumeEntry));
334 memset(tentry, 0, sizeof(*tentry));
335 tentry->serverName = (char *)malloc(strlen(ahost) + 1);
336 strcpy(tentry->serverName, ahost);
337 tentry->partname = (char *)malloc(strlen(apart) + 1);
338 strcpy(tentry->partname, apart);
339 tentry->name = (char *)malloc(strlen(avol) + 1);
340 strcpy(tentry->name, avol);
342 code = bc_ParseHost(tentry->serverName, &tentry->server);
346 code = bc_GetPartitionID(tentry->partname, &tentry->partition);
350 *tlast = tentry; /* thread on the list */
354 struct bc_volumeSet *
355 bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
356 { /*bc_FindVolumeSet */
358 register struct bc_volumeSet *tvs;
360 for (tvs = aconfig->vset; tvs; tvs = tvs->next) {
361 if (!strcmp(tvs->name, aname))
364 return (struct bc_volumeSet *)0;
366 } /*bc_FindVolumeSet */
368 /* ------------------------------------
369 * dumpschedule management code
370 * ------------------------------------
373 /* bc_CreateDumpSchedule
374 * Add another node to the dump schedule.
376 * aconfig - in core configuration structures
377 * adumpName - name of new dump node
378 * expDate - expiration date
379 * expType - absolute or relative
382 bc_CreateDumpSchedule(aconfig, adumpName, expDate, expType)
383 struct bc_config *aconfig;
388 register struct bc_dumpSchedule *tdump;
389 struct bc_dumpSchedule *parent, *node;
392 if (strcmp(adumpName, "none") == 0)
393 return -2; /* invalid name */
395 code = FindDump(aconfig, adumpName, &parent, &node);
397 return -1; /* node already exists */
399 return -2; /* name specification error */
401 tdump = (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
402 memset(tdump, 0, sizeof(*tdump));
404 /* prepend this node to the dump schedule list */
405 tdump->next = aconfig->dsched;
406 aconfig->dsched = tdump;
408 /* save the name of this dump node */
409 tdump->name = (char *)malloc(strlen(adumpName) + 1);
410 strcpy(tdump->name, adumpName);
412 /* expiration information */
413 tdump->expDate = expDate;
414 tdump->expType = expType;
416 bc_ProcessDumpSchedule(aconfig); /* redo tree */
421 /* Recursively remove this node and all of its children from aconfig's
422 * list of dumps. Note that this leaves the sibling pointers damaged (pointing
423 * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
426 bc_DeleteDumpScheduleAddr(aconfig, adumpAddr)
427 struct bc_config *aconfig;
428 struct bc_dumpSchedule *adumpAddr;
430 register struct bc_dumpSchedule **tlast, *tdump;
431 register struct bc_dumpSchedule *tnext;
433 /* knock off all children first */
434 for (tdump = adumpAddr->firstChild; tdump; tdump = tnext) {
435 /* extract next ptr now, since will be freed by recursive call below */
436 tnext = tdump->nextSibling;
437 bc_DeleteDumpScheduleAddr(aconfig, tdump);
440 /* finally, remove us from the list of good dudes */
441 for (tlast = &aconfig->dsched, tdump = *tlast; tdump;
442 tlast = &tdump->next, tdump = *tlast) {
443 if (tdump == adumpAddr) {
444 /* found the one we're looking for */
445 *tlast = tdump->next; /* remove us from basic list */
454 /* bc_FindDumpSchedule
455 * Finds dump schedule aname by doing a linear search
457 * aconfig - handle for incore configuration tables
458 * aname - (path)name to match on
460 * 0 for failure, ptr to dumpschedule for success
463 struct bc_dumpSchedule *
464 bc_FindDumpSchedule(aconfig, aname)
466 struct bc_config *aconfig;
468 register struct bc_dumpSchedule *tds;
469 for (tds = aconfig->dsched; tds; tds = tds->next) {
470 if (!strcmp(tds->name, aname))
473 return (struct bc_dumpSchedule *)0;
476 /* bc_DeleteDumpSchedule
477 * Delete dump node adumpName from the dump schedule
480 bc_DeleteDumpSchedule(aconfig, adumpName)
481 struct bc_config *aconfig;
484 register struct bc_dumpSchedule *tdump;
486 /* does a linear search of the dump schedules in order to find
489 for (tdump = aconfig->dsched; tdump; tdump = tdump->next) {
490 if (strcmp(tdump->name, adumpName) == 0) {
491 /* found it, we can zap recursively */
492 bc_DeleteDumpScheduleAddr(aconfig, tdump);
493 /* tree's been pruned, but we have to recompute the internal pointers
494 * from first principles, since we didn't bother to maintain
495 * the sibling and children pointers during the call to delete
497 bc_ProcessDumpSchedule(aconfig);
501 /* if we make it here, there's no such dump schedule entry */
506 /* bc_ProcessDumpSchedule
507 * Walk over the dump schedule list, building it into a tree. This
508 * algorithm is simple, but takes O(N*2) operations to run, with N=number
509 * of dump schedule nodes. It probably will never matter
512 bc_ProcessDumpSchedule(aconfig)
513 register struct bc_config *aconfig;
515 register struct bc_dumpSchedule *tds;
516 struct bc_dumpSchedule *parentptr, *nodeptr;
519 /* first, clear all the links on all entries so that this function
520 * may be called any number of times with no ill effects
522 for (tds = aconfig->dsched; tds; tds = tds->next) {
523 tds->parent = (struct bc_dumpSchedule *)0;
524 tds->nextSibling = (struct bc_dumpSchedule *)0;
525 tds->firstChild = (struct bc_dumpSchedule *)0;
528 for (tds = aconfig->dsched; tds; tds = tds->next) {
529 retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
531 printf("bc_processdumpschedule: finddump returns %d\n", retval);
535 /* only need to do work if it is not a root node */
536 if (parentptr != 0) {
537 nodeptr->parent = parentptr;
538 nodeptr->nextSibling = parentptr->firstChild;
539 parentptr->firstChild = nodeptr;
549 * parentptr - set to parent node, if one exists
550 * nodeptr - set to node requested
553 * 0 - success, parentptr and nodeptr set appropriately
554 * -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
555 * -2 - path search error. Some node on the path does not exist.
556 * -3 - name specification error
558 * pathname checking should be done externally. In particular, trailing
559 * / symbols may return confusing error codes. (e.g on missing last
560 * node returns -2 rather than -1)
564 FindDump(aconfig, nodeString, parentptr, nodeptr)
565 struct bc_config *aconfig;
567 struct bc_dumpSchedule **parentptr;
568 struct bc_dumpSchedule **nodeptr;
570 struct bc_dumpSchedule *dsptr;
578 /* ensure first char is correct separator */
579 if ((nodeString[0] != '/')
580 || (strlen(&nodeString[0]) <= 1)
582 printf("FindDump: %s, error in dump name specification\n",
588 curptr = &nodeString[1]; /* past first / */
589 separator = strchr(curptr, '/');
591 matchLength = strlen(curptr) + 1; /* +1 for leading / */
593 matchLength = (separator - &nodeString[0]);
595 /* printf("matchLength = %d\n", matchLength); */
597 /* now search all the nodes for this name */
598 for (dsptr = aconfig->dsched; dsptr != 0; dsptr = dsptr->next) {
599 /* printf("compare %s with %s for %d\n",
600 * dsptr->name, nodeString, matchLength); */
601 if (strlen(dsptr->name) != matchLength)
604 if (strncmp(dsptr->name, nodeString, matchLength) == 0) {
610 if (nodeString[matchLength] == 0) {
611 /* last node in the path */
613 return (0); /* all ok */
615 /* node not found; parent exists for non root nodes */
620 /* failed to find a node in the path */
623 curptr = separator + 1;
625 printf("FindDump: trailing / in %s\n", nodeString);
629 separator = strchr(curptr, '/');
631 matchLength = strlen(&nodeString[0]);
633 matchLength = separator - &nodeString[0];
635 *parentptr = *nodeptr;