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>
22 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
30 #include <sys/param.h>
32 #include <afs/com_err.h>
34 #include <afs/bubasics.h>
36 #include "bucoord_internal.h"
38 struct ubik_client *cstructp; /*Ptr to Ubik client structure */
40 static int FreeVolumeEntryList(struct bc_volumeEntry *aentry);
41 static int FreeVolumeEntry(struct bc_volumeEntry *aentry);
43 /* Code to maintain dump schedule and volume set abstractions.
44 * A volume set looks like this:
45 * vsname: servername partition-name <volume list>*
46 * A dump schedule looks like this:
47 * dsname: vsname period parent-ds
50 /* get partition id from a name */
52 bc_GetPartitionID(char *aname, afs_int32 *aval)
55 /*bc_GetPartitionID */
60 /* special-case "anything" */
61 if (strcmp(aname, ".*") == 0) {
67 return -1; /* unknown */
68 /* numbers go straight through */
69 if (tc >= '0' && tc <= '9') {
70 *aval = bc_SafeATOI(aname);
73 /* otherwise check for vicepa or /vicepa, or just plain "a" */
75 if (strlen(aname) <= 2) {
77 } else if (!strncmp(aname, "/vicep", 6)) {
78 strncpy(ascii, aname + 6, 2);
79 } else if (!strncmp(aname, "vicep", 5)) {
80 strncpy(ascii, aname + 5, 2);
82 return (BC_NOPARTITION); /* bad partition name */
83 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
84 * from 0. Do the appropriate conversion */
86 /* one char name, 0..25 */
87 if (ascii[0] < 'a' || ascii[0] > 'z')
88 return -1; /* wrongo */
89 *aval = ascii[0] - 'a';
92 /* two char name, 26 .. <whatever> */
93 if (ascii[0] < 'a' || ascii[0] > 'z')
94 return -1; /* wrongo */
95 if (ascii[1] < 'a' || ascii[1] > 'z')
96 return -1; /* just as bad */
97 *aval = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
100 } /*bc_GetPartitionID */
102 /*----------------------------------------------------------------------------
106 * Given a string containing a host name or its IP address in dot notation, fill in
107 * the given sockaddr with all the corresponding info.
110 * aname : Host name or dotted IP address.
111 * asockaddr: Ptr to sockaddr to fill in for the above host.
114 * 0 if everything went well,
115 * -1 if it couldn't be translated.
118 * Nothing interesting.
122 *----------------------------------------------------------------------------
126 bc_ParseHost(char *aname, struct sockaddr_in *asockaddr)
130 struct hostent *th; /*Host entry */
131 afs_uint32 addr; /*Converted address */
132 afs_int32 b1, b2, b3, b4; /*Byte-sized address chunks */
133 afs_int32 code; /*Return code from sscanf() */
134 afs_int32 tmp1, tmp2;
137 * Try to parse the given name as a dot-notation IP address first.
139 code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
142 * Four chunks were read, so we assume success. Construct the socket.
144 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
145 asockaddr->sin_len = sizeof(struct sockaddr_in);
147 asockaddr->sin_family = AF_INET;
148 asockaddr->sin_port = 0;
149 addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
150 memcpy(&tmp1, &addr, sizeof(afs_int32));
152 memcpy(&asockaddr->sin_addr.s_addr, &tmp2, sizeof(afs_int32));
157 * The given string isn't a dotted IP address. Try to map it as a host
158 * name, or leave it as a wild-card.
161 if (strcmp(aname, ".*") == 0) {
162 memset(asockaddr, 0, sizeof(struct sockaddr_in));
166 th = gethostbyname(aname);
169 * No such luck, return failure.
174 * We found a mapping; construct the socket.
176 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
177 asockaddr->sin_len = sizeof(struct sockaddr_in);
179 asockaddr->sin_family = AF_INET;
180 asockaddr->sin_port = 0;
181 memcpy(&tmp1, th->h_addr, sizeof(afs_int32));
183 memcpy(&(asockaddr->sin_addr.s_addr), &tmp2,
184 sizeof(asockaddr->sin_addr.s_addr));
190 /* create an empty volume set, new items are added via bc_AddVolumeItem */
192 bc_CreateVolumeSet(struct bc_config *aconfig, char *avolName,
195 struct bc_volumeSet **tlast, *tset, *nset;
197 if (bc_FindVolumeSet(aconfig, avolName))
198 return -1; /* already exists */
199 /* move to end of the list */
201 nset = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
202 memset(nset, 0, sizeof(*nset));
203 nset->flags = aflags;
204 nset->name = (char *)malloc(strlen(avolName) + 1);
205 strcpy(nset->name, avolName);
206 if (aflags & VSFLAG_TEMPORARY) {
207 /* Add to beginning of list */
208 nset->next = aconfig->vset;
209 aconfig->vset = nset;
211 /* Add to end of list */
212 for (tlast = &aconfig->vset, tset = *tlast; tset;
213 tlast = &tset->next, tset = *tlast);
220 FreeVolumeEntry(struct bc_volumeEntry *aentry)
223 free(aentry->serverName);
224 free(aentry->partname);
230 FreeVolumeEntryList(struct bc_volumeEntry *aentry)
232 struct bc_volumeEntry *tnext;
235 tnext = aentry->next;
236 FreeVolumeEntry(aentry);
245 FreeVolumeSet(struct bc_volumeSet *avset)
247 FreeVolumeEntryList(avset->ventries);
253 bc_DeleteVolumeSet(struct bc_config *aconfig, char *avolName,
256 struct bc_volumeSet **tlast, *tset;
259 tlast = &aconfig->vset;
260 for (tset = *tlast; tset; tlast = &tset->next, tset = *tlast) {
261 if (strcmp(avolName, tset->name) == 0) {
262 *flags = tset->flags; /* Remember flags */
263 *tlast = tset->next; /* Remove from chain */
264 FreeVolumeSet(tset); /* Free the volume set */
269 /* if we get here, we didn't find the item */
274 bc_DeleteVolumeItem(struct bc_config *aconfig, char *avolName,
278 struct bc_volumeSet *tset;
279 struct bc_volumeEntry *tentry, **tlast;
281 tset = bc_FindVolumeSet(aconfig, avolName);
285 tlast = &tset->ventries;
286 for (i = 1, tentry = *tlast; tentry;
287 tlast = &tentry->next, tentry = *tlast, i++) {
289 /* found entry we want */
290 *tlast = tentry->next;
291 FreeVolumeEntry(tentry);
295 return -2; /* not found */
299 bc_AddVolumeItem(struct bc_config *aconfig, char *avolName, char *ahost,
300 char *apart, char *avol)
302 struct bc_volumeSet *tset;
303 struct bc_volumeEntry **tlast, *tentry;
306 tset = bc_FindVolumeSet(aconfig, avolName);
308 return (BC_NOVOLSET);
310 /* otherwise append this item to the end of the real list */
311 tlast = &tset->ventries;
313 /* move to end of the list */
314 for (tentry = *tlast; tentry; tlast = &tentry->next, tentry = *tlast);
315 tentry = (struct bc_volumeEntry *)malloc(sizeof(struct bc_volumeEntry));
316 memset(tentry, 0, sizeof(*tentry));
317 tentry->serverName = (char *)malloc(strlen(ahost) + 1);
318 strcpy(tentry->serverName, ahost);
319 tentry->partname = (char *)malloc(strlen(apart) + 1);
320 strcpy(tentry->partname, apart);
321 tentry->name = (char *)malloc(strlen(avol) + 1);
322 strcpy(tentry->name, avol);
324 code = bc_ParseHost(tentry->serverName, &tentry->server);
328 code = bc_GetPartitionID(tentry->partname, &tentry->partition);
332 *tlast = tentry; /* thread on the list */
336 struct bc_volumeSet *
337 bc_FindVolumeSet(struct bc_config *aconfig, char *aname)
338 { /*bc_FindVolumeSet */
340 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
365 bc_CreateDumpSchedule(struct bc_config *aconfig, char *adumpName,
366 afs_int32 expDate, afs_int32 expType)
368 struct bc_dumpSchedule *tdump;
369 struct bc_dumpSchedule *parent, *node;
372 if (strcmp(adumpName, "none") == 0)
373 return -2; /* invalid name */
375 code = FindDump(aconfig, adumpName, &parent, &node);
377 return -1; /* node already exists */
379 return -2; /* name specification error */
381 tdump = (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
382 memset(tdump, 0, sizeof(*tdump));
384 /* prepend this node to the dump schedule list */
385 tdump->next = aconfig->dsched;
386 aconfig->dsched = tdump;
388 /* save the name of this dump node */
389 tdump->name = (char *)malloc(strlen(adumpName) + 1);
390 strcpy(tdump->name, adumpName);
392 /* expiration information */
393 tdump->expDate = expDate;
394 tdump->expType = expType;
396 bc_ProcessDumpSchedule(aconfig); /* redo tree */
401 /* Recursively remove this node and all of its children from aconfig's
402 * list of dumps. Note that this leaves the sibling pointers damaged (pointing
403 * to strange places), so we must call bc_ProcessDumpSchedule when we're done.
406 bc_DeleteDumpScheduleAddr(struct bc_config *aconfig,
407 struct bc_dumpSchedule *adumpAddr)
409 struct bc_dumpSchedule **tlast, *tdump;
410 struct bc_dumpSchedule *tnext;
412 /* knock off all children first */
413 for (tdump = adumpAddr->firstChild; tdump; tdump = tnext) {
414 /* extract next ptr now, since will be freed by recursive call below */
415 tnext = tdump->nextSibling;
416 bc_DeleteDumpScheduleAddr(aconfig, tdump);
419 /* finally, remove us from the list of good dudes */
420 for (tlast = &aconfig->dsched, tdump = *tlast; tdump;
421 tlast = &tdump->next, tdump = *tlast) {
422 if (tdump == adumpAddr) {
423 /* found the one we're looking for */
424 *tlast = tdump->next; /* remove us from basic list */
433 /* bc_FindDumpSchedule
434 * Finds dump schedule aname by doing a linear search
436 * aconfig - handle for incore configuration tables
437 * aname - (path)name to match on
439 * 0 for failure, ptr to dumpschedule for success
442 struct bc_dumpSchedule *
443 bc_FindDumpSchedule(struct bc_config *aconfig, char *aname)
445 struct bc_dumpSchedule *tds;
446 for (tds = aconfig->dsched; tds; tds = tds->next) {
447 if (!strcmp(tds->name, aname))
450 return (struct bc_dumpSchedule *)0;
453 /* bc_DeleteDumpSchedule
454 * Delete dump node adumpName from the dump schedule
458 bc_DeleteDumpSchedule(struct bc_config *aconfig, char *adumpName)
460 struct bc_dumpSchedule *tdump;
462 /* does a linear search of the dump schedules in order to find
465 for (tdump = aconfig->dsched; tdump; tdump = tdump->next) {
466 if (strcmp(tdump->name, adumpName) == 0) {
467 /* found it, we can zap recursively */
468 bc_DeleteDumpScheduleAddr(aconfig, tdump);
469 /* tree's been pruned, but we have to recompute the internal pointers
470 * from first principles, since we didn't bother to maintain
471 * the sibling and children pointers during the call to delete
473 bc_ProcessDumpSchedule(aconfig);
477 /* if we make it here, there's no such dump schedule entry */
482 /* bc_ProcessDumpSchedule
483 * Walk over the dump schedule list, building it into a tree. This
484 * algorithm is simple, but takes O(N*2) operations to run, with N=number
485 * of dump schedule nodes. It probably will never matter
489 bc_ProcessDumpSchedule(struct bc_config *aconfig)
491 struct bc_dumpSchedule *tds;
492 struct bc_dumpSchedule *parentptr, *nodeptr;
495 /* first, clear all the links on all entries so that this function
496 * may be called any number of times with no ill effects
498 for (tds = aconfig->dsched; tds; tds = tds->next) {
499 tds->parent = (struct bc_dumpSchedule *)0;
500 tds->nextSibling = (struct bc_dumpSchedule *)0;
501 tds->firstChild = (struct bc_dumpSchedule *)0;
504 for (tds = aconfig->dsched; tds; tds = tds->next) {
505 retval = FindDump(aconfig, tds->name, &parentptr, &nodeptr);
507 printf("bc_processdumpschedule: finddump returns %d\n", retval);
511 /* only need to do work if it is not a root node */
512 if (parentptr != 0) {
513 nodeptr->parent = parentptr;
514 nodeptr->nextSibling = parentptr->firstChild;
515 parentptr->firstChild = nodeptr;
525 * parentptr - set to parent node, if one exists
526 * nodeptr - set to node requested
529 * 0 - success, parentptr and nodeptr set appropriately
530 * -1 - node not found, parent exists if reqd. Will be 0 for root nodes.
531 * -2 - path search error. Some node on the path does not exist.
532 * -3 - name specification error
534 * pathname checking should be done externally. In particular, trailing
535 * / symbols may return confusing error codes. (e.g on missing last
536 * node returns -2 rather than -1)
540 FindDump(struct bc_config *aconfig, char *nodeString,
541 struct bc_dumpSchedule **parentptr,
542 struct bc_dumpSchedule **nodeptr)
544 struct bc_dumpSchedule *dsptr;
552 /* ensure first char is correct separator */
553 if ((nodeString[0] != '/')
554 || (strlen(&nodeString[0]) <= 1)
556 printf("FindDump: %s, error in dump name specification\n",
562 curptr = &nodeString[1]; /* past first / */
563 separator = strchr(curptr, '/');
565 matchLength = strlen(curptr) + 1; /* +1 for leading / */
567 matchLength = (separator - &nodeString[0]);
569 /* printf("matchLength = %d\n", matchLength); */
571 /* now search all the nodes for this name */
572 for (dsptr = aconfig->dsched; dsptr != 0; dsptr = dsptr->next) {
573 /* printf("compare %s with %s for %d\n",
574 * dsptr->name, nodeString, matchLength); */
575 if (strlen(dsptr->name) != matchLength)
578 if (strncmp(dsptr->name, nodeString, matchLength) == 0) {
584 if (nodeString[matchLength] == 0) {
585 /* last node in the path */
587 return (0); /* all ok */
589 /* node not found; parent exists for non root nodes */
594 /* failed to find a node in the path */
597 curptr = separator + 1;
599 printf("FindDump: trailing / in %s\n", nodeString);
603 separator = strchr(curptr, '/');
605 matchLength = strlen(&nodeString[0]);
607 matchLength = separator - &nodeString[0];
609 *parentptr = *nodeptr;