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
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <afs/budb_client.h>
18 #include <afs/com_err.h>
19 #include <afs/bubasics.h>
22 #include "error_macros.h"
23 #include "bucoord_internal.h"
24 #include "bucoord_prototypes.h"
26 /* code to manage volumesets
27 * specific to the ubik database implementation
30 extern struct bc_config *bc_globalConfig;
31 extern struct udbHandleS udbHandle;
34 static int ListVolSet(struct bc_volumeSet *aset);
36 /* ------------------------------------
37 * command level routines
38 * ------------------------------------
43 * add a volume (or volume expression) to a volume set
45 * parm 0 is vol set name.
46 * parm 1 is server name
47 * parm 2 is partition name
48 * parm 3 is volume regexp
52 bc_AddVolEntryCmd(struct cmd_syndesc *as, void *arock)
55 char *volSetName, *serverName, *partitionName, *volRegExp;
57 struct bc_volumeSet *tset;
59 volSetName = as->parms[0].items->data;
60 serverName = as->parms[1].items->data;
61 partitionName = as->parms[2].items->data;
62 volRegExp = as->parms[3].items->data;
64 code = bc_UpdateVolumeSet();
66 afs_com_err(whoami, code, "; Can't retrieve volume sets");
70 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
72 tset = bc_FindVolumeSet(bc_globalConfig, volSetName);
74 afs_com_err(whoami, code, "; Volume entry not added");
78 if (!(tset->flags & VSFLAG_TEMPORARY)) {
79 code = bc_LockText(ctPtr);
84 code = bc_UpdateVolumeSet();
86 afs_com_err(whoami, code, "; Can't retrieve volume sets");
91 bc_AddVolumeItem(bc_globalConfig, volSetName, serverName,
92 partitionName, volRegExp);
94 afs_com_err(whoami, code, "; Volume entry not added");
98 if (!(tset->flags & VSFLAG_TEMPORARY)) {
99 code = bc_SaveVolumeSet();
101 afs_com_err(whoami, code, "Cannot save volume set file");
102 afs_com_err(whoami, 0,
103 "Changes are temporary - for this session only");
108 if (ctPtr->lockHandle)
109 bc_UnlockText(ctPtr);
116 * create a new volume set, writing out the new volumeset
117 * file in a safe manner
119 * name of new volume set
123 bc_AddVolSetCmd(struct cmd_syndesc *as, void *arock)
125 /* parm 0 is vol set name */
128 udbClientTextP ctPtr;
131 /* lock schedules and check validity */
132 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
134 flags = (as->parms[1].items ? VSFLAG_TEMPORARY : 0);
136 /* Don't lock if adding a temporary volumeset */
137 if (!(flags & VSFLAG_TEMPORARY)) {
138 code = bc_LockText(ctPtr);
143 code = bc_UpdateVolumeSet();
145 afs_com_err(whoami, code, "; Can't retrieve volume sets");
149 /* validate size of volumeset name */
151 bc_CreateVolumeSet(bc_globalConfig, (ti = as->parms[0].items)->data,
155 afs_com_err(whoami, 0, "Volume set '%s' already exists", ti->data);
157 afs_com_err(whoami, 0, "Unknown problem");
158 } else if (!(flags & VSFLAG_TEMPORARY)) {
159 code = bc_SaveVolumeSet();
161 afs_com_err(whoami, code, "Cannot save new volume set file");
162 afs_com_err(whoami, 0,
163 "Changes are temporary - for this session only");
168 if (ctPtr->lockHandle != 0)
169 bc_UnlockText(ctPtr);
174 /* bc_DeleteVolEntryCmd
175 * delete a volume specification from a volume set
177 * parm 0 is vol set name
178 * parm 1 is entry # (integer, 1 based)
182 bc_DeleteVolEntryCmd(struct cmd_syndesc *as, void *arock)
187 udbClientTextP ctPtr;
188 struct bc_volumeSet *tset;
190 vsname = as->parms[0].items->data;
192 code = bc_UpdateVolumeSet();
194 afs_com_err(whoami, code, "; Can't retrieve volume sets");
198 /* lock schedules and check validity */
199 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
201 tset = bc_FindVolumeSet(bc_globalConfig, vsname);
203 afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
207 if (!(tset->flags & VSFLAG_TEMPORARY)) {
208 code = bc_LockText(ctPtr);
213 code = bc_UpdateVolumeSet();
215 afs_com_err(whoami, code, "; Can't retrieve volume sets");
219 entry = bc_SafeATOI(as->parms[1].items->data);
221 afs_com_err(whoami, 0, "Can't parse entry number '%s' as decimal integer",
222 as->parms[1].items->data);
226 code = bc_DeleteVolumeItem(bc_globalConfig, vsname, entry);
229 afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
230 } else if (code == -2) {
231 afs_com_err(whoami, 0,
232 "There aren't %d volume items for this volume set",
234 afs_com_err(whoami, 0,
235 "Use the 'listvolsets' command to examine the volume set");
240 if (!(tset->flags & VSFLAG_TEMPORARY)) {
241 code = bc_SaveVolumeSet();
243 printf("backup: deleted volume entry %d from volume set %s\n",
246 afs_com_err(whoami, code, "Cannot save volume set file");
247 afs_com_err(whoami, 0,
248 "Deletion is temporary - for this session only");
253 if (ctPtr->lockHandle != 0)
254 bc_UnlockText(ctPtr);
261 /* bc_DeleteVolSetCmd
262 * delete a volume set, writing out a new configuration file when
265 * name of volumeset to delete
269 bc_DeleteVolSetCmd(struct cmd_syndesc *as, void *arock)
271 /* parm 0 is vol set name */
274 udbClientTextP ctPtr;
276 afs_int32 flags, tosave = 0;
278 /* lock schedules and check validity */
279 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
281 code = bc_LockText(ctPtr);
285 code = bc_UpdateVolumeSet();
287 afs_com_err(whoami, code, "; Can't retrieve volume sets");
291 for (ti = as->parms[0].items; ti; ti = ti->next) {
292 code = bc_DeleteVolumeSet(bc_globalConfig, ti->data, &flags);
295 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
297 afs_com_err(whoami, code,
298 "; Unknown problem deleting volume set '%s'",
301 if (!(flags & VSFLAG_TEMPORARY))
303 printf("backup: deleted volume set '%s'\n", ti->data);
307 /* now write out the file */
309 c = bc_SaveVolumeSet();
313 afs_com_err(whoami, c, "Cannot save updated volume set file");
314 afs_com_err(whoami, 0, "Deletion effective for this session only");
320 if (ctPtr->lockHandle)
321 bc_UnlockText(ctPtr);
327 ListVolSet(struct bc_volumeSet *aset)
329 struct bc_volumeEntry *tentry;
332 printf("Volume set %s", aset->name);
333 if (aset->flags & VSFLAG_TEMPORARY)
334 printf(" (temporary)");
337 for (tentry = aset->ventries; tentry; tentry = tentry->next, i++) {
338 printf(" Entry %3d: server %s, partition %s, volumes: %s\n", i,
339 tentry->serverName, tentry->partname, tentry->name);
345 * list out all the information (?) about a volumeset or about all
348 * optional parameter specifies a volumeset name
352 bc_ListVolSetCmd(struct cmd_syndesc *as, void *arock)
354 /* parm 0 is optional volume set to display */
355 struct bc_volumeSet *tset;
359 code = bc_UpdateVolumeSet();
361 afs_com_err(whoami, code, "; Can't retrieve volume sets");
365 /* figure out volume set to list */
366 if ((ti = as->parms[0].items)) {
367 /* for each volume set in the command item list */
368 for (; ti; ti = ti->next) {
369 tset = bc_FindVolumeSet(bc_globalConfig, ti->data);
374 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
379 /* no command parameters specified, show entire list */
380 for (tset = bc_globalConfig->vset; tset; tset = tset->next) {
391 /* ------------------------------------
393 * ------------------------------------
397 bc_ClearVolumeSets(void)
399 struct bc_volumeSet *vsPtr, *vsNextPtr, **vsPrev;
401 extern struct bc_config *bc_globalConfig;
403 vsPrev = &(bc_globalConfig->vset);
404 for (vsPtr = bc_globalConfig->vset; vsPtr; vsPtr = vsNextPtr) {
405 vsNextPtr = vsPtr->next;
407 if (vsPtr->flags & VSFLAG_TEMPORARY) { /* Skip temporary volumeSet */
408 vsPrev = &(vsPtr->next);
412 *vsPrev = vsPtr->next; /* Remove volumeSet from the chain */
413 FreeVolumeSet(vsPtr);
419 * Open up the volume set configuration file as specified in our argument,
420 * then parse the file to set up our internal representation.
422 * 0 on successful processing,
427 bc_ParseVolumeSet(void)
429 char tbuffer[1024]; /*Buffer for reading config file */
430 char vsname[256]; /*Volume set name */
431 char serverName[256]; /*Server name */
432 char partName[256]; /*Partition name */
433 struct bc_volumeEntry *tve; /*Ptr to generated volume spec struct */
434 struct bc_volumeSet *tvs = NULL; /*Ptr to volume set struct */
435 struct bc_volumeEntry **ppve, *pve;
436 struct bc_volumeSet **ppvs, *pvs;
437 afs_int32 code; /*Generalized return code */
438 char *tp; /*Result of fgets(), malloc() */
439 int readHeader; /*Is next thing to read a volume set hdr? */
441 udbClientTextP ctPtr;
444 extern struct bc_config *bc_globalConfig;
446 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
447 stream = ctPtr->textStream;
450 * Open up the volume set configuration file, fail if it can't be done.
453 if (ctPtr->textSize == 0) /* empty is ok */
456 /* stream checks and initialization */
458 return (BC_INTERNALERROR);
464 /* Read in and process the next line of the volume set description
467 tp = fgets(tbuffer, sizeof(tbuffer), stream);
470 if (readHeader) { /*r */
472 * Scan a header entry.
475 code = sscanf(tbuffer, "%s %s", serverName, vsname);
477 || (strcmp(serverName, "volumeset") != 0)
479 afs_com_err(whoami, 0, "Bad volume header line: '%s'", tbuffer);
483 /* Create and fill in the volume set descriptor structure from
484 * the info just read placing it at the head of its queue in the
485 * global configuration structure.
487 tvs = calloc(1, sizeof(struct bc_volumeSet));
488 tvs->name = strdup(vsname);
490 /* append to the end */
491 for (ppvs = &bc_globalConfig->vset, pvs = *ppvs; pvs;
492 ppvs = &pvs->next, pvs = *ppvs);
494 tvs->next = (struct bc_volumeSet *)0;
497 /* Scan a volume name entry, which contains the server name,
498 * partition pattern, and volume pattern.
500 code = sscanf(tbuffer, "%s %s %s", serverName, partName, vsname);
501 if (code == 1 && strcmp(serverName, "end") == 0) {
502 /* This was really a line delimiting the current volume set.
503 * Next time around, we should try to read a header.
509 /* The line just read in is a volume spec. Create a new volume
510 * spec record, then get the rest of the information regarding
511 * the host, and stuff everything into place.
513 tve = calloc(1, sizeof(struct bc_volumeEntry));
515 afs_com_err(whoami, 0,
516 "Can't malloc() a new volume spec record!");
519 if (bc_ParseHost(serverName, &(tve->server)))
520 afs_com_err(whoami, 0, "Can't get required info on host '%s'",
523 /* The above code has filled in the server sockaddr, now fill in
524 * the rest of the fields.
526 tve->serverName = strdup(serverName);
527 if (!tve->serverName) {
528 afs_com_err(whoami, 0,
529 "Can't malloc() a new volume spec server name field!");
532 tve->partname = strdup(partName);
533 if (!tve->partname) {
534 afs_com_err(whoami, 0,
535 "Can't malloc() a new volume spec partition pattern field!");
538 code = bc_GetPartitionID(partName, &tve->partition);
540 afs_com_err(whoami, 0, "Can't parse partition '%s'", partName);
545 afs_com_err(whoami, 0,
546 "Can't malloc() a new volume spec volume pattern field!");
551 /* Now, thread it onto the list of other volume spec entries for
552 * the current volume set.
555 for (ppve = &tvs->ventries, pve = *ppve; pve;
556 ppve = &pve->next, pve = *ppve);
558 tve->next = (struct bc_volumeEntry *)0;
562 /* If we hit an EOF in the middle of a volume set record, we bitch and
569 * Well, we did it. Return successfully.
573 } /*bc_ParseVolumeSet */
576 * save the current volume set information to disk
580 bc_SaveVolumeSet(void)
583 struct bc_volumeSet *tset;
584 struct bc_volumeEntry *tentry;
586 udbClientTextP ctPtr;
589 extern struct bc_config *bc_globalConfig;
591 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
592 stream = ctPtr->textStream;
595 if (ctPtr->lockHandle == 0)
596 return (BC_INTERNALERROR);
598 /* truncate the file */
599 code = ftruncate(fileno(stream), 0);
605 /* now write the volumeset information */
607 for (tset = bc_globalConfig->vset; tset != 0; tset = tset->next) {
608 if (tset->flags & VSFLAG_TEMPORARY)
609 continue; /* skip temporary entries */
611 fprintf(stream, "volumeset %s\n", tset->name);
612 for (tentry = tset->ventries; tentry; tentry = tentry->next) {
613 fprintf(stream, "%s %s %s\n", tentry->serverName,
614 tentry->partname, tentry->name);
616 fprintf(stream, "end\n");
620 return (BC_INTERNALERROR);
623 code = bcdb_SaveTextFile(ctPtr);
627 /* do this on bcdb_SaveTextFile */
628 /* increment local version number */
629 ctPtr->textVersion++;
631 /* update locally stored file size */
632 ctPtr->textSize = filesize(ctPtr->textStream);
639 bc_UpdateVolumeSet(void)
641 struct udbHandleS *uhptr = &udbHandle;
642 udbClientTextP ctPtr;
646 /* lock schedules and check validity */
647 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
649 /* Don't need a lock to check the version */
650 code = bc_CheckTextVersion(ctPtr);
651 if (code != BC_VERSIONMISMATCH) {
652 ERROR(code); /* version matches or some other error */
655 /* Must update the volume sets */
656 /* If no lock alredy taken, then lock it */
657 if (ctPtr->lockHandle == 0) {
658 code = bc_LockText(ctPtr);
664 if (ctPtr->textVersion != -1) {
665 printf("backup: obsolete volumesets - updating\n");
666 bc_ClearVolumeSets();
669 /* open a temp file to store the config text received from buserver *
670 * The open file stream is stored in ctPtr->textStream */
672 bc_openTextFile(ctPtr,
673 &bc_globalConfig->tmpTextFileNames[TB_VOLUMESET][0]);
676 /* now get a fresh set of information from the database */
677 code = bcdb_GetTextFile(ctPtr);
681 /* fetch the version number */
683 ubik_BUDB_GetTextVersion(uhptr->uh_client, 0, ctPtr->textType,
684 &ctPtr->textVersion);
689 code = bc_ParseVolumeSet();
694 if (lock && ctPtr->lockHandle)
695 bc_UnlockText(ctPtr);