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 extern struct bc_config *bc_globalConfig;
42 extern FILE *bc_open();
43 extern void bc_HandleMisc();
46 static char db_dsvs = 0; /*Assume debugging output turned off */
47 static char mn[] = "dsvs"; /*Module name */
49 struct ubik_client *cstructp; /*Ptr to Ubik client structure */
51 extern struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *cf,
55 /* Code to maintain dump schedule and volume set abstractions.
56 * A volume set looks like this:
57 * vsname: servername partition-name <volume list>*
58 * A dump schedule looks like this:
59 * dsname: vsname period parent-ds
62 /* get partition id from a name */
64 bc_GetPartitionID(aname, aval)
69 /*bc_GetPartitionID */
74 /* special-case "anything" */
75 if (strcmp(aname, ".*") == 0) {
81 return -1; /* unknown */
82 /* numbers go straight through */
83 if (tc >= '0' && tc <= '9') {
84 *aval = bc_SafeATOI(aname);
87 /* otherwise check for vicepa or /vicepa, or just plain "a" */
89 if (strlen(aname) <= 2) {
91 } else if (!strncmp(aname, "/vicep", 6)) {
92 strncpy(ascii, aname + 6, 2);
93 } else if (!strncmp(aname, "vicep", 5)) {
94 strncpy(ascii, aname + 5, 2);
96 return (BC_NOPARTITION); /* bad partition name */
97 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
98 * from 0. Do the appropriate conversion */
100 /* one char name, 0..25 */
101 if (ascii[0] < 'a' || ascii[0] > 'z')
102 return -1; /* wrongo */
103 *aval = ascii[0] - 'a';
106 /* two char name, 26 .. <whatever> */
107 if (ascii[0] < 'a' || ascii[0] > 'z')
108 return -1; /* wrongo */
109 if (ascii[1] < 'a' || ascii[1] > 'z')
110 return -1; /* just as bad */
111 *aval = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
114 } /*bc_GetPartitionID */
116 /*----------------------------------------------------------------------------
120 * Given a string containing a host name or its IP address in dot notation, fill in
121 * the given sockaddr with all the corresponding info.
124 * aname : Host name or dotted IP address.
125 * asockaddr: Ptr to sockaddr to fill in for the above host.
128 * 0 if everything went well,
129 * -1 if it couldn't be translated.
132 * Nothing interesting.
136 *----------------------------------------------------------------------------
140 bc_ParseHost(aname, asockaddr)
142 struct sockaddr_in *asockaddr;
146 register struct hostent *th; /*Host entry */
147 afs_int32 addr; /*Converted address */
148 afs_int32 b1, b2, b3, b4; /*Byte-sized address chunks */
149 register afs_int32 code; /*Return code from sscanf() */
150 afs_int32 tmp1, tmp2;
153 * Try to parse the given name as a dot-notation IP address first.
155 code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
158 * Four chunks were read, so we assume success. Construct the socket.
160 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
161 asockaddr->sin_len = sizeof(struct sockaddr_in);
163 asockaddr->sin_family = AF_INET;
164 asockaddr->sin_port = 0;
165 addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
166 memcpy(&tmp1, &addr, sizeof(afs_int32));
168 memcpy(&asockaddr->sin_addr.s_addr, &tmp2, sizeof(afs_int32));
173 * The given string isn't a dotted IP address. Try to map it as a host
174 * name, or leave it as a wild-card.
177 if (strcmp(aname, ".*") == 0) {
178 memset(asockaddr, 0, sizeof(struct sockaddr_in));
182 th = gethostbyname(aname);
185 * No such luck, return failure.
190 * We found a mapping; construct the socket.
192 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
193 asockaddr->sin_len = sizeof(struct sockaddr_in);
195 asockaddr->sin_family = AF_INET;
196 asockaddr->sin_port = 0;
197 memcpy(&tmp1, th->h_addr, sizeof(afs_int32));
199 memcpy(&(asockaddr->sin_addr.s_addr), &tmp2,
200 sizeof(asockaddr->sin_addr.s_addr));
206 /* create an empty volume set, new items are added via bc_AddVolumeItem */
207 bc_CreateVolumeSet(aconfig, avolName, aflags)
208 struct bc_config *aconfig;
212 register struct bc_volumeSet **tlast, *tset, *nset;
214 if (bc_FindVolumeSet(aconfig, avolName))
215 return -1; /* already exists */
216 /* move to end of the list */
218 nset = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
219 memset(nset, 0, sizeof(*nset));
220 nset->flags = aflags;
221 nset->name = (char *)malloc(strlen(avolName) + 1);
222 strcpy(nset->name, avolName);
223 if (aflags & VSFLAG_TEMPORARY) {
224 /* Add to beginning of list */
225 nset->next = aconfig->vset;
226 aconfig->vset = nset;
228 /* Add to end of list */
229 for (tlast = &aconfig->vset, tset = *tlast; tset;
230 tlast = &tset->next, tset = *tlast);
240 struct bc_volumeSet *avset;
242 FreeVolumeEntryList(avset->ventries);
248 FreeVolumeEntryList(aentry)
249 register struct bc_volumeEntry *aentry;
251 register struct bc_volumeEntry *tnext;
254 tnext = aentry->next;
255 FreeVolumeEntry(aentry);
262 FreeVolumeEntry(aentry)
263 register struct bc_volumeEntry *aentry;
266 free(aentry->serverName);
267 free(aentry->partname);
272 bc_DeleteVolumeSet(aconfig, avolName, flags)
273 struct bc_config *aconfig;
277 register struct bc_volumeSet **tlast, *tset;
280 tlast = &aconfig->vset;
281 for (tset = *tlast; tset; tlast = &tset->next, tset = *tlast) {
282 if (strcmp(avolName, tset->name) == 0) {
283 *flags = tset->flags; /* Remember flags */
284 *tlast = tset->next; /* Remove from chain */
285 FreeVolumeSet(tset); /* Free the volume set */
290 /* if we get here, we didn't find the item */
294 bc_DeleteVolumeItem(aconfig, avolName, anumber)
295 struct bc_config *aconfig;
299 register afs_int32 i;
300 register struct bc_volumeSet *tset;
301 register struct bc_volumeEntry *tentry, **tlast;
303 tset = bc_FindVolumeSet(aconfig, avolName);
307 tlast = &tset->ventries;
308 for (i = 1, tentry = *tlast; tentry;
309 tlast = &tentry->next, tentry = *tlast, i++) {
311 /* found entry we want */
312 *tlast = tentry->next;
313 FreeVolumeEntry(tentry);
317 return -2; /* not found */
320 bc_AddVolumeItem(aconfig, avolName, ahost, apart, avol)
321 struct bc_config *aconfig;
323 char *ahost, *apart, *avol;
325 struct bc_volumeSet *tset;
326 register struct bc_volumeEntry **tlast, *tentry;
327 register afs_int32 code;
329 tset = bc_FindVolumeSet(aconfig, avolName);
331 return (BC_NOVOLSET);
333 /* otherwise append this item to the end of the real list */
334 tlast = &tset->ventries;
336 /* move to end of the list */
337 for (tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast);
338 tentry = (struct bc_volumeEntry *)malloc(sizeof(struct bc_volumeEntry));
339 memset(tentry, 0, sizeof(*tentry));
340 tentry->serverName = (char *)malloc(strlen(ahost) + 1);
341 strcpy(tentry->serverName, ahost);
342 tentry->partname = (char *)malloc(strlen(apart) + 1);
343 strcpy(tentry->partname, apart);
344 tentry->name = (char *)malloc(strlen(avol) + 1);
345 strcpy(tentry->name, avol);
347 code = bc_ParseHost(tentry->serverName, &tentry->server);
351 code = bc_GetPartitionID(tentry->partname, &tentry->partition);
355 *tlast = tentry; /* thread on the list */
359 struct bc_volumeSet *
360 bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
361 { /*bc_FindVolumeSet */
363 register struct bc_volumeSet *tvs;
365 for (tvs = aconfig->vset; tvs; tvs = tvs->next) {
366 if (!strcmp(tvs->name, aname))
369 return (struct bc_volumeSet *)0;
371 } /*bc_FindVolumeSet */
373 /* ------------------------------------
374 * dumpschedule management code
375 * ------------------------------------
378 /* bc_CreateDumpSchedule
379 * Add another node to the dump schedule.
381 * aconfig - in core configuration structures
382 * adumpName - name of new dump node
383 * expDate - expiration date
384 * expType - absolute or relative
387 bc_CreateDumpSchedule(aconfig, adumpName, expDate, expType)
388 struct bc_config *aconfig;
393 register struct bc_dumpSchedule **tlast, *tdump;
394 struct bc_dumpSchedule *parent, *node;
397 if (strcmp(adumpName, "none") == 0)
398 return -2; /* invalid name */
400 code = FindDump(aconfig, adumpName, &parent, &node);
402 return -1; /* node already exists */
404 return -2; /* name specification error */
406 tdump = (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
407 memset(tdump, 0, sizeof(*tdump));
409 /* prepend this node to the dump schedule list */
410 tdump->next = aconfig->dsched;
411 aconfig->dsched = tdump;
413 /* save the name of this dump node */
414 tdump->name = (char *)malloc(strlen(adumpName) + 1);
415 strcpy(tdump->name, adumpName);
417 /* expiration information */
418 tdump->expDate = expDate;
419 tdump->expType = expType;
421 bc_ProcessDumpSchedule(aconfig); /* redo tree */
426 /* Recursively remove this node and all of its children from aconfig's
427 * list of dumps. Note that this leaves the sibling pointers damaged (pointing
428 * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
431 bc_DeleteDumpScheduleAddr(aconfig, adumpAddr)
432 struct bc_config *aconfig;
433 struct bc_dumpSchedule *adumpAddr;
435 register struct bc_dumpSchedule **tlast, *tdump;
436 register struct bc_dumpSchedule *tnext;
438 /* knock off all children first */
439 for (tdump = adumpAddr->firstChild; tdump; tdump = tnext) {
440 /* extract next ptr now, since will be freed by recursive call below */
441 tnext = tdump->nextSibling;
442 bc_DeleteDumpScheduleAddr(aconfig, tdump);
445 /* finally, remove us from the list of good dudes */
446 for (tlast = &aconfig->dsched, tdump = *tlast; tdump;
447 tlast = &tdump->next, tdump = *tlast) {
448 if (tdump == adumpAddr) {
449 /* found the one we're looking for */
450 *tlast = tdump->next; /* remove us from basic list */
459 /* bc_FindDumpSchedule
460 * Finds dump schedule aname by doing a linear search
462 * aconfig - handle for incore configuration tables
463 * aname - (path)name to match on
465 * 0 for failure, ptr to dumpschedule for success
468 struct bc_dumpSchedule *
469 bc_FindDumpSchedule(aconfig, aname)
471 struct bc_config *aconfig;
473 register struct bc_dumpSchedule *tds;
474 for (tds = aconfig->dsched; tds; tds = tds->next) {
475 if (!strcmp(tds->name, aname))
478 return (struct bc_dumpSchedule *)0;
481 /* bc_DeleteDumpSchedule
482 * Delete dump node adumpName from the dump schedule
485 bc_DeleteDumpSchedule(aconfig, adumpName)
486 struct bc_config *aconfig;
489 register struct bc_dumpSchedule *tdump;
491 /* does a linear search of the dump schedules in order to find
494 for (tdump = aconfig->dsched; tdump; tdump = tdump->next) {
495 if (strcmp(tdump->name, adumpName) == 0) {
496 /* found it, we can zap recursively */
497 bc_DeleteDumpScheduleAddr(aconfig, tdump);
498 /* tree's been pruned, but we have to recompute the internal pointers
499 * from first principles, since we didn't bother to maintain
500 * the sibling and children pointers during the call to delete
502 bc_ProcessDumpSchedule(aconfig);
506 /* if we make it here, there's no such dump schedule entry */
511 /* bc_ProcessDumpSchedule
512 * Walk over the dump schedule list, building it into a tree. This
513 * algorithm is simple, but takes O(N*2) operations to run, with N=number
514 * of dump schedule nodes. It probably will never matter
517 bc_ProcessDumpSchedule(aconfig)
518 register struct bc_config *aconfig;
520 register struct bc_dumpSchedule *tds, *uds;
521 struct bc_dumpSchedule *parentptr, *nodeptr;
524 /* first, clear all the links on all entries so that this function
525 * may be called any number of times with no ill effects
527 for (tds = aconfig->dsched; tds; tds = tds->next) {
528 tds->parent = (struct bc_dumpSchedule *)0;
529 tds->nextSibling = (struct bc_dumpSchedule *)0;
530 tds->firstChild = (struct bc_dumpSchedule *)0;
533 for (tds = aconfig->dsched; tds; tds = tds->next) {
534 retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
536 printf("bc_processdumpschedule: finddump returns %d\n", retval);
540 /* only need to do work if it is not a root node */
541 if (parentptr != 0) {
542 nodeptr->parent = parentptr;
543 nodeptr->nextSibling = parentptr->firstChild;
544 parentptr->firstChild = nodeptr;
554 * parentptr - set to parent node, if one exists
555 * nodeptr - set to node requested
558 * 0 - success, parentptr and nodeptr set appropriately
559 * -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
560 * -2 - path search error. Some node on the path does not exist.
561 * -3 - name specification error
563 * pathname checking should be done externally. In particular, trailing
564 * / symbols may return confusing error codes. (e.g on missing last
565 * node returns -2 rather than -1)
569 FindDump(aconfig, nodeString, parentptr, nodeptr)
570 struct bc_config *aconfig;
572 struct bc_dumpSchedule **parentptr;
573 struct bc_dumpSchedule **nodeptr;
575 struct bc_dumpSchedule *dsptr;
583 /* ensure first char is correct separator */
584 if ((nodeString[0] != '/')
585 || (strlen(&nodeString[0]) <= 1)
587 printf("FindDump: %s, error in dump name specification\n",
593 curptr = &nodeString[1]; /* past first / */
594 separator = strchr(curptr, '/');
596 matchLength = strlen(curptr) + 1; /* +1 for leading / */
598 matchLength = (separator - &nodeString[0]);
600 /* printf("matchLength = %d\n", matchLength); */
602 /* now search all the nodes for this name */
603 for (dsptr = aconfig->dsched; dsptr != 0; dsptr = dsptr->next) {
604 /* printf("compare %s with %s for %d\n",
605 * dsptr->name, nodeString, matchLength); */
606 if (strlen(dsptr->name) != matchLength)
609 if (strncmp(dsptr->name, nodeString, matchLength) == 0) {
615 if (nodeString[matchLength] == 0) {
616 /* last node in the path */
618 return (0); /* all ok */
620 /* node not found; parent exists for non root nodes */
625 /* failed to find a node in the path */
628 curptr = separator + 1;
630 printf("FindDump: trailing / in %s\n", nodeString);
634 separator = strchr(curptr, '/');
636 matchLength = strlen(&nodeString[0]);
638 matchLength = separator - &nodeString[0];
640 *parentptr = *nodeptr;