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>
17 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
27 #include <afs/budb_client.h>
29 #include <afs/com_err.h>
30 #include <afs/bubasics.h>
32 #include "error_macros.h"
34 /* code to manage volumesets
35 * specific to the ubik database implementation
38 afs_int32 bc_UpdateVolumeSet();
39 extern struct bc_config *bc_globalConfig;
40 extern struct udbHandleS udbHandle;
42 extern struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *cf, char *name);
43 extern void FreeVolumeSet(struct bc_volumeSet *avset);
46 /* ------------------------------------
47 * command level routines
48 * ------------------------------------
53 * add a volume (or volume expression) to a volume set
55 * parm 0 is vol set name.
56 * parm 1 is server name
57 * parm 2 is partition name
58 * parm 3 is volume regexp
61 bc_AddVolEntryCmd(as, arock)
62 struct cmd_syndesc *as;
65 register afs_int32 code;
66 char *volSetName, *serverName, *partitionName, *volRegExp;
68 struct bc_volumeSet *tset;
70 volSetName = as->parms[0].items->data;
71 serverName = as->parms[1].items->data;
72 partitionName = as->parms[2].items->data;
73 volRegExp = as->parms[3].items->data;
75 code = bc_UpdateVolumeSet();
77 com_err(whoami, code, "; Can't retrieve volume sets");
81 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
83 tset = bc_FindVolumeSet(bc_globalConfig, volSetName);
85 com_err(whoami, code, "; Volume entry not added");
89 if (!(tset->flags & VSFLAG_TEMPORARY)) {
90 code = bc_LockText(ctPtr);
95 code = bc_UpdateVolumeSet();
97 com_err(whoami, code, "; Can't retrieve volume sets");
102 bc_AddVolumeItem(bc_globalConfig, volSetName, serverName,
103 partitionName, volRegExp);
105 com_err(whoami, code, "; Volume entry not added");
109 if (!(tset->flags & VSFLAG_TEMPORARY)) {
110 code = bc_SaveVolumeSet();
112 com_err(whoami, code, "Cannot save volume set file");
114 "Changes are temporary - for this session only");
119 if (ctPtr->lockHandle)
120 bc_UnlockText(ctPtr);
127 * create a new volume set, writing out the new volumeset
128 * file in a safe manner
130 * name of new volume set
134 bc_AddVolSetCmd(as, arock)
135 struct cmd_syndesc *as;
138 /* parm 0 is vol set name */
139 register afs_int32 code;
140 register struct cmd_item *ti;
141 udbClientTextP ctPtr;
144 /* lock schedules and check validity */
145 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
147 flags = (as->parms[1].items ? VSFLAG_TEMPORARY : 0);
149 /* Don't lock if adding a temporary volumeset */
150 if (!(flags & VSFLAG_TEMPORARY)) {
151 code = bc_LockText(ctPtr);
156 code = bc_UpdateVolumeSet();
158 com_err(whoami, code, "; Can't retrieve volume sets");
162 /* validate size of volumeset name */
164 bc_CreateVolumeSet(bc_globalConfig, (ti = as->parms[0].items)->data,
168 com_err(whoami, 0, "Volume set '%s' already exists", ti->data);
170 com_err(whoami, 0, "Unknown problem");
171 } else if (!(flags & VSFLAG_TEMPORARY)) {
172 code = bc_SaveVolumeSet();
174 com_err(whoami, code, "Cannot save new volume set file");
176 "Changes are temporary - for this session only");
181 if (ctPtr->lockHandle != 0)
182 bc_UnlockText(ctPtr);
187 /* bc_DeleteVolEntryCmd
188 * delete a volume specification from a volume set
190 * parm 0 is vol set name
191 * parm 1 is entry # (integer, 1 based)
195 bc_DeleteVolEntryCmd(as, arock)
196 struct cmd_syndesc *as;
199 register afs_int32 code;
202 udbClientTextP ctPtr;
203 struct bc_volumeSet *tset;
205 vsname = as->parms[0].items->data;
207 code = bc_UpdateVolumeSet();
209 com_err(whoami, code, "; Can't retrieve volume sets");
213 /* lock schedules and check validity */
214 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
216 tset = bc_FindVolumeSet(bc_globalConfig, vsname);
218 com_err(whoami, 0, "No such volume set as '%s'", vsname);
222 if (!(tset->flags & VSFLAG_TEMPORARY)) {
223 code = bc_LockText(ctPtr);
228 code = bc_UpdateVolumeSet();
230 com_err(whoami, code, "; Can't retrieve volume sets");
234 entry = bc_SafeATOI(as->parms[1].items->data);
236 com_err(whoami, 0, "Can't parse entry number '%s' as decimal integer",
237 as->parms[1].items->data);
241 code = bc_DeleteVolumeItem(bc_globalConfig, vsname, entry);
244 com_err(whoami, 0, "No such volume set as '%s'", vsname);
245 } else if (code == -2) {
247 "There aren't %d volume items for this volume set",
250 "Use the 'listvolsets' command to examine the volume set");
255 if (!(tset->flags & VSFLAG_TEMPORARY)) {
256 code = bc_SaveVolumeSet();
258 printf("backup: deleted volume entry %d from volume set %s\n",
261 com_err(whoami, code, "Cannot save volume set file");
263 "Deletion is temporary - for this session only");
268 if (ctPtr->lockHandle != 0)
269 bc_UnlockText(ctPtr);
276 /* bc_DeleteVolSetCmd
277 * delete a volume set, writing out a new configuration file when
280 * name of volumeset to delete
284 bc_DeleteVolSetCmd(as, arock)
285 struct cmd_syndesc *as;
288 /* parm 0 is vol set name */
289 register afs_int32 code;
290 register struct cmd_item *ti;
291 udbClientTextP ctPtr;
293 afs_int32 flags, tosave = 0;
295 /* lock schedules and check validity */
296 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
298 code = bc_LockText(ctPtr);
302 code = bc_UpdateVolumeSet();
304 com_err(whoami, code, "; Can't retrieve volume sets");
308 for (ti = as->parms[0].items; ti; ti = ti->next) {
309 code = bc_DeleteVolumeSet(bc_globalConfig, ti->data, &flags);
312 com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
314 com_err(whoami, code,
315 "; Unknown problem deleting volume set '%s'",
318 if (!(flags & VSFLAG_TEMPORARY))
320 printf("backup: deleted volume set '%s'\n", ti->data);
324 /* now write out the file */
326 c = bc_SaveVolumeSet();
330 com_err(whoami, c, "Cannot save updated volume set file");
331 com_err(whoami, 0, "Deletion effective for this session only");
337 if (ctPtr->lockHandle)
338 bc_UnlockText(ctPtr);
344 * list out all the information (?) about a volumeset or about all
347 * optional parameter specifies a volumeset name
351 bc_ListVolSetCmd(as, arock)
352 struct cmd_syndesc *as;
355 /* parm 0 is optional volume set to display */
356 register struct bc_volumeSet *tset;
357 register struct cmd_item *ti;
360 code = bc_UpdateVolumeSet();
362 com_err(whoami, code, "; Can't retrieve volume sets");
366 /* figure out volume set to list */
367 if (ti = as->parms[0].items) {
368 /* for each volume set in the command item list */
369 for (; ti; ti = ti->next) {
370 tset = bc_FindVolumeSet(bc_globalConfig, ti->data);
375 com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
380 /* no command parameters specified, show entire list */
381 for (tset = bc_globalConfig->vset; tset; tset = tset->next) {
392 /* ------------------------------------
394 * ------------------------------------
399 struct udbHandleS *uhptr = &udbHandle;
400 struct bc_volumeSet *vsPtr, *vsNextPtr, **vsPrev;
402 extern struct bc_config *bc_globalConfig;
404 vsPrev = &(bc_globalConfig->vset);
405 for (vsPtr = bc_globalConfig->vset; vsPtr; vsPtr = vsNextPtr) {
406 vsNextPtr = vsPtr->next;
408 if (vsPtr->flags & VSFLAG_TEMPORARY) { /* Skip temporary volumeSet */
409 vsPrev = &(vsPtr->next);
413 *vsPrev = vsPtr->next; /* Remove volumeSet from the chain */
414 FreeVolumeSet(vsPtr);
421 struct bc_volumeSet *aset;
423 struct bc_volumeEntry *tentry;
426 printf("Volume set %s", aset->name);
427 if (aset->flags & VSFLAG_TEMPORARY)
428 printf(" (temporary)");
431 for (tentry = aset->ventries; tentry; tentry = tentry->next, i++) {
432 printf(" Entry %3d: server %s, partition %s, volumes: %s\n", i,
433 tentry->serverName, tentry->partname, tentry->name);
440 * Open up the volume set configuration file as specified in our argument,
441 * then parse the file to set up our internal representation.
443 * 0 on successful processing,
450 static char rn[] = "bc_ParseVolumeSet"; /*Routine name */
451 char tbuffer[1024]; /*Buffer for reading config file */
452 char vsname[256]; /*Volume set name */
453 char serverName[256]; /*Server name */
454 char partName[256]; /*Partition name */
455 register struct bc_volumeEntry *tve; /*Ptr to generated volume spec struct */
456 register struct bc_volumeSet *tvs; /*Ptr to volume set struct */
457 struct bc_volumeEntry **ppve, *pve;
458 struct bc_volumeSet **ppvs, *pvs;
459 register afs_int32 code; /*Generalized return code */
460 char *tp; /*Result of fgets(), malloc() */
461 int readHeader; /*Is next thing to read a volume set hdr? */
463 udbClientTextP ctPtr;
464 register FILE *stream;
465 struct bc_config *configPtr;
467 extern struct bc_config *bc_globalConfig;
469 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
470 stream = ctPtr->textStream;
471 configPtr = bc_globalConfig;
474 * Open up the volume set configuration file, fail if it can't be done.
477 if (ctPtr->textSize == 0) /* empty is ok */
480 /* stream checks and initialization */
482 return (BC_INTERNALERROR);
488 /* Read in and process the next line of the volume set description
491 tp = fgets(tbuffer, sizeof(tbuffer), stream);
494 if (readHeader) { /*r */
496 * Scan a header entry.
499 code = sscanf(tbuffer, "%s %s", serverName, vsname);
501 || (strcmp(serverName, "volumeset") != 0)
503 com_err(whoami, 0, "Bad volume header line: '%s'", tbuffer);
507 /* Create and fill in the volume set descriptor structure from
508 * the info just read placing it at the head of its queue in the
509 * global configuration structure.
511 tvs = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
512 memset(tvs, 0, sizeof(*tvs));
513 tvs->name = (char *)malloc(strlen(vsname) + 1);
514 strcpy(tvs->name, vsname);
516 /* append to the end */
517 for (ppvs = &bc_globalConfig->vset, pvs = *ppvs; pvs;
518 ppvs = &pvs->next, pvs = *ppvs);
520 tvs->next = (struct bc_volumeSet *)0;
523 /* Scan a volume name entry, which contains the server name,
524 * partition pattern, and volume pattern.
526 code = sscanf(tbuffer, "%s %s %s", serverName, partName, vsname);
527 if (code == 1 && strcmp(serverName, "end") == 0) {
528 /* This was really a line delimiting the current volume set.
529 * Next time around, we should try to read a header.
535 /* The line just read in is a volume spec. Create a new volume
536 * spec record, then get the rest of the information regarding
537 * the host, and stuff everything into place.
539 tve = (struct bc_volumeEntry *)
540 malloc(sizeof(struct bc_volumeEntry));
543 "Can't malloc() a new volume spec record!");
546 memset(tve, 0, sizeof(*tve));
547 if (bc_ParseHost(serverName, &(tve->server)))
548 com_err(whoami, 0, "Can't get required info on host '%s'",
551 /* The above code has filled in the server sockaddr, now fill in
552 * the rest of the fields.
554 tve->serverName = (char *)malloc(strlen(serverName) + 1);
555 if (!tve->serverName) {
557 "Can't malloc() a new volume spec server name field!");
560 strcpy(tve->serverName, serverName);
561 tve->partname = (char *)malloc(strlen(partName) + 1);
562 if (!tve->partname) {
564 "Can't malloc() a new volume spec partition pattern field!");
567 strcpy(tve->partname, partName);
568 code = bc_GetPartitionID(partName, &tve->partition);
570 com_err(whoami, 0, "Can't parse partition '%s'", partName);
573 tp = (char *)malloc(strlen(vsname) + 1);
576 "Can't malloc() a new volume spec volume pattern field!");
582 /* Now, thread it onto the list of other volume spec entries for
583 * the current volume set.
586 for (ppve = &tvs->ventries, pve = *ppve; pve;
587 ppve = &pve->next, pve = *ppve);
589 tve->next = (struct bc_volumeEntry *)0;
593 /* If we hit an EOF in the middle of a volume set record, we bitch and
600 * Well, we did it. Return successfully.
604 } /*bc_ParseVolumeSet */
607 * save the current volume set information to disk
612 register afs_int32 code = 0;
613 register struct bc_volumeSet *tset;
614 register struct bc_volumeEntry *tentry;
616 udbClientTextP ctPtr;
617 register FILE *stream;
618 struct bc_config *configPtr;
620 extern struct bc_config *bc_globalConfig;
622 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
623 stream = ctPtr->textStream;
624 configPtr = bc_globalConfig;
627 if (ctPtr->lockHandle == 0)
628 return (BC_INTERNALERROR);
630 /* truncate the file */
631 code = ftruncate(fileno(stream), 0);
637 /* now write the volumeset information */
639 for (tset = bc_globalConfig->vset; tset != 0; tset = tset->next) {
640 if (tset->flags & VSFLAG_TEMPORARY)
641 continue; /* skip temporary entries */
643 fprintf(stream, "volumeset %s\n", tset->name);
644 for (tentry = tset->ventries; tentry; tentry = tentry->next) {
645 fprintf(stream, "%s %s %s\n", tentry->serverName,
646 tentry->partname, tentry->name);
648 fprintf(stream, "end\n");
652 return (BC_INTERNALERROR);
655 code = bcdb_SaveTextFile(ctPtr);
659 /* do this on bcdb_SaveTextFile */
660 /* increment local version number */
661 ctPtr->textVersion++;
663 /* update locally stored file size */
664 ctPtr->textSize = filesize(ctPtr->textStream);
673 struct udbHandleS *uhptr = &udbHandle;
674 udbClientTextP ctPtr;
678 /* lock schedules and check validity */
679 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
681 /* Don't need a lock to check the version */
682 code = bc_CheckTextVersion(ctPtr);
683 if (code != BC_VERSIONMISMATCH) {
684 ERROR(code); /* version matches or some other error */
687 /* Must update the volume sets */
688 /* If no lock alredy taken, then lock it */
689 if (ctPtr->lockHandle == 0) {
690 code = bc_LockText(ctPtr);
696 if (ctPtr->textVersion != -1) {
697 printf("backup: obsolete volumesets - updating\n");
698 bc_ClearVolumeSets();
701 /* open a temp file to store the config text received from buserver *
702 * The open file stream is stored in ctPtr->textStream */
704 bc_openTextFile(ctPtr,
705 &bc_globalConfig->tmpTextFileNames[TB_VOLUMESET][0]);
708 /* now get a fresh set of information from the database */
709 code = bcdb_GetTextFile(ctPtr);
713 /* fetch the version number */
715 ubik_Call(BUDB_GetTextVersion, uhptr->uh_client, 0, ctPtr->textType,
716 &ctPtr->textVersion);
721 code = bc_ParseVolumeSet();
726 if (lock && ctPtr->lockHandle)
727 bc_UnlockText(ctPtr);