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>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
26 #include <afs/budb_client.h>
28 #include <afs/com_err.h>
29 #include <afs/bubasics.h>
31 #include "error_macros.h"
33 /* code to manage volumesets
34 * specific to the ubik database implementation
37 afs_int32 bc_UpdateVolumeSet();
38 extern struct bc_config *bc_globalConfig;
39 extern struct udbHandleS udbHandle;
41 extern struct bc_volumeSet *bc_FindVolumeSet(struct bc_config *cf, char *name);
42 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
62 bc_AddVolEntryCmd(struct cmd_syndesc *as, void *arock)
65 char *volSetName, *serverName, *partitionName, *volRegExp;
67 struct bc_volumeSet *tset;
69 volSetName = as->parms[0].items->data;
70 serverName = as->parms[1].items->data;
71 partitionName = as->parms[2].items->data;
72 volRegExp = as->parms[3].items->data;
74 code = bc_UpdateVolumeSet();
76 afs_com_err(whoami, code, "; Can't retrieve volume sets");
80 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
82 tset = bc_FindVolumeSet(bc_globalConfig, volSetName);
84 afs_com_err(whoami, code, "; Volume entry not added");
88 if (!(tset->flags & VSFLAG_TEMPORARY)) {
89 code = bc_LockText(ctPtr);
94 code = bc_UpdateVolumeSet();
96 afs_com_err(whoami, code, "; Can't retrieve volume sets");
101 bc_AddVolumeItem(bc_globalConfig, volSetName, serverName,
102 partitionName, volRegExp);
104 afs_com_err(whoami, code, "; Volume entry not added");
108 if (!(tset->flags & VSFLAG_TEMPORARY)) {
109 code = bc_SaveVolumeSet();
111 afs_com_err(whoami, code, "Cannot save volume set file");
112 afs_com_err(whoami, 0,
113 "Changes are temporary - for this session only");
118 if (ctPtr->lockHandle)
119 bc_UnlockText(ctPtr);
126 * create a new volume set, writing out the new volumeset
127 * file in a safe manner
129 * name of new volume set
133 bc_AddVolSetCmd(struct cmd_syndesc *as, void *arock)
135 /* parm 0 is vol set name */
137 register struct cmd_item *ti;
138 udbClientTextP ctPtr;
141 /* lock schedules and check validity */
142 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
144 flags = (as->parms[1].items ? VSFLAG_TEMPORARY : 0);
146 /* Don't lock if adding a temporary volumeset */
147 if (!(flags & VSFLAG_TEMPORARY)) {
148 code = bc_LockText(ctPtr);
153 code = bc_UpdateVolumeSet();
155 afs_com_err(whoami, code, "; Can't retrieve volume sets");
159 /* validate size of volumeset name */
161 bc_CreateVolumeSet(bc_globalConfig, (ti = as->parms[0].items)->data,
165 afs_com_err(whoami, 0, "Volume set '%s' already exists", ti->data);
167 afs_com_err(whoami, 0, "Unknown problem");
168 } else if (!(flags & VSFLAG_TEMPORARY)) {
169 code = bc_SaveVolumeSet();
171 afs_com_err(whoami, code, "Cannot save new volume set file");
172 afs_com_err(whoami, 0,
173 "Changes are temporary - for this session only");
178 if (ctPtr->lockHandle != 0)
179 bc_UnlockText(ctPtr);
184 /* bc_DeleteVolEntryCmd
185 * delete a volume specification from a volume set
187 * parm 0 is vol set name
188 * parm 1 is entry # (integer, 1 based)
192 bc_DeleteVolEntryCmd(struct cmd_syndesc *as, void *arock)
197 udbClientTextP ctPtr;
198 struct bc_volumeSet *tset;
200 vsname = as->parms[0].items->data;
202 code = bc_UpdateVolumeSet();
204 afs_com_err(whoami, code, "; Can't retrieve volume sets");
208 /* lock schedules and check validity */
209 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
211 tset = bc_FindVolumeSet(bc_globalConfig, vsname);
213 afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
217 if (!(tset->flags & VSFLAG_TEMPORARY)) {
218 code = bc_LockText(ctPtr);
223 code = bc_UpdateVolumeSet();
225 afs_com_err(whoami, code, "; Can't retrieve volume sets");
229 entry = bc_SafeATOI(as->parms[1].items->data);
231 afs_com_err(whoami, 0, "Can't parse entry number '%s' as decimal integer",
232 as->parms[1].items->data);
236 code = bc_DeleteVolumeItem(bc_globalConfig, vsname, entry);
239 afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
240 } else if (code == -2) {
241 afs_com_err(whoami, 0,
242 "There aren't %d volume items for this volume set",
244 afs_com_err(whoami, 0,
245 "Use the 'listvolsets' command to examine the volume set");
250 if (!(tset->flags & VSFLAG_TEMPORARY)) {
251 code = bc_SaveVolumeSet();
253 printf("backup: deleted volume entry %d from volume set %s\n",
256 afs_com_err(whoami, code, "Cannot save volume set file");
257 afs_com_err(whoami, 0,
258 "Deletion is temporary - for this session only");
263 if (ctPtr->lockHandle != 0)
264 bc_UnlockText(ctPtr);
271 /* bc_DeleteVolSetCmd
272 * delete a volume set, writing out a new configuration file when
275 * name of volumeset to delete
279 bc_DeleteVolSetCmd(struct cmd_syndesc *as, void *arock)
281 /* parm 0 is vol set name */
283 register struct cmd_item *ti;
284 udbClientTextP ctPtr;
286 afs_int32 flags, tosave = 0;
288 /* lock schedules and check validity */
289 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
291 code = bc_LockText(ctPtr);
295 code = bc_UpdateVolumeSet();
297 afs_com_err(whoami, code, "; Can't retrieve volume sets");
301 for (ti = as->parms[0].items; ti; ti = ti->next) {
302 code = bc_DeleteVolumeSet(bc_globalConfig, ti->data, &flags);
305 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
307 afs_com_err(whoami, code,
308 "; Unknown problem deleting volume set '%s'",
311 if (!(flags & VSFLAG_TEMPORARY))
313 printf("backup: deleted volume set '%s'\n", ti->data);
317 /* now write out the file */
319 c = bc_SaveVolumeSet();
323 afs_com_err(whoami, c, "Cannot save updated volume set file");
324 afs_com_err(whoami, 0, "Deletion effective for this session only");
330 if (ctPtr->lockHandle)
331 bc_UnlockText(ctPtr);
337 ListVolSet(struct bc_volumeSet *aset)
339 struct bc_volumeEntry *tentry;
342 printf("Volume set %s", aset->name);
343 if (aset->flags & VSFLAG_TEMPORARY)
344 printf(" (temporary)");
347 for (tentry = aset->ventries; tentry; tentry = tentry->next, i++) {
348 printf(" Entry %3d: server %s, partition %s, volumes: %s\n", i,
349 tentry->serverName, tentry->partname, tentry->name);
355 * list out all the information (?) about a volumeset or about all
358 * optional parameter specifies a volumeset name
362 bc_ListVolSetCmd(struct cmd_syndesc *as, void *arock)
364 /* parm 0 is optional volume set to display */
365 register struct bc_volumeSet *tset;
366 register struct cmd_item *ti;
369 code = bc_UpdateVolumeSet();
371 afs_com_err(whoami, code, "; Can't retrieve volume sets");
375 /* figure out volume set to list */
376 if (ti = as->parms[0].items) {
377 /* for each volume set in the command item list */
378 for (; ti; ti = ti->next) {
379 tset = bc_FindVolumeSet(bc_globalConfig, ti->data);
384 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
389 /* no command parameters specified, show entire list */
390 for (tset = bc_globalConfig->vset; tset; tset = tset->next) {
401 /* ------------------------------------
403 * ------------------------------------
408 struct udbHandleS *uhptr = &udbHandle;
409 struct bc_volumeSet *vsPtr, *vsNextPtr, **vsPrev;
411 extern struct bc_config *bc_globalConfig;
413 vsPrev = &(bc_globalConfig->vset);
414 for (vsPtr = bc_globalConfig->vset; vsPtr; vsPtr = vsNextPtr) {
415 vsNextPtr = vsPtr->next;
417 if (vsPtr->flags & VSFLAG_TEMPORARY) { /* Skip temporary volumeSet */
418 vsPrev = &(vsPtr->next);
422 *vsPrev = vsPtr->next; /* Remove volumeSet from the chain */
423 FreeVolumeSet(vsPtr);
429 * Open up the volume set configuration file as specified in our argument,
430 * then parse the file to set up our internal representation.
432 * 0 on successful processing,
439 static char rn[] = "bc_ParseVolumeSet"; /*Routine name */
440 char tbuffer[1024]; /*Buffer for reading config file */
441 char vsname[256]; /*Volume set name */
442 char serverName[256]; /*Server name */
443 char partName[256]; /*Partition name */
444 register struct bc_volumeEntry *tve; /*Ptr to generated volume spec struct */
445 register struct bc_volumeSet *tvs; /*Ptr to volume set struct */
446 struct bc_volumeEntry **ppve, *pve;
447 struct bc_volumeSet **ppvs, *pvs;
448 register afs_int32 code; /*Generalized return code */
449 char *tp; /*Result of fgets(), malloc() */
450 int readHeader; /*Is next thing to read a volume set hdr? */
452 udbClientTextP ctPtr;
453 register FILE *stream;
454 struct bc_config *configPtr;
456 extern struct bc_config *bc_globalConfig;
458 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
459 stream = ctPtr->textStream;
460 configPtr = bc_globalConfig;
463 * Open up the volume set configuration file, fail if it can't be done.
466 if (ctPtr->textSize == 0) /* empty is ok */
469 /* stream checks and initialization */
471 return (BC_INTERNALERROR);
477 /* Read in and process the next line of the volume set description
480 tp = fgets(tbuffer, sizeof(tbuffer), stream);
483 if (readHeader) { /*r */
485 * Scan a header entry.
488 code = sscanf(tbuffer, "%s %s", serverName, vsname);
490 || (strcmp(serverName, "volumeset") != 0)
492 afs_com_err(whoami, 0, "Bad volume header line: '%s'", tbuffer);
496 /* Create and fill in the volume set descriptor structure from
497 * the info just read placing it at the head of its queue in the
498 * global configuration structure.
500 tvs = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
501 memset(tvs, 0, sizeof(*tvs));
502 tvs->name = (char *)malloc(strlen(vsname) + 1);
503 strcpy(tvs->name, vsname);
505 /* append to the end */
506 for (ppvs = &bc_globalConfig->vset, pvs = *ppvs; pvs;
507 ppvs = &pvs->next, pvs = *ppvs);
509 tvs->next = (struct bc_volumeSet *)0;
512 /* Scan a volume name entry, which contains the server name,
513 * partition pattern, and volume pattern.
515 code = sscanf(tbuffer, "%s %s %s", serverName, partName, vsname);
516 if (code == 1 && strcmp(serverName, "end") == 0) {
517 /* This was really a line delimiting the current volume set.
518 * Next time around, we should try to read a header.
524 /* The line just read in is a volume spec. Create a new volume
525 * spec record, then get the rest of the information regarding
526 * the host, and stuff everything into place.
528 tve = (struct bc_volumeEntry *)
529 malloc(sizeof(struct bc_volumeEntry));
531 afs_com_err(whoami, 0,
532 "Can't malloc() a new volume spec record!");
535 memset(tve, 0, sizeof(*tve));
536 if (bc_ParseHost(serverName, &(tve->server)))
537 afs_com_err(whoami, 0, "Can't get required info on host '%s'",
540 /* The above code has filled in the server sockaddr, now fill in
541 * the rest of the fields.
543 tve->serverName = (char *)malloc(strlen(serverName) + 1);
544 if (!tve->serverName) {
545 afs_com_err(whoami, 0,
546 "Can't malloc() a new volume spec server name field!");
549 strcpy(tve->serverName, serverName);
550 tve->partname = (char *)malloc(strlen(partName) + 1);
551 if (!tve->partname) {
552 afs_com_err(whoami, 0,
553 "Can't malloc() a new volume spec partition pattern field!");
556 strcpy(tve->partname, partName);
557 code = bc_GetPartitionID(partName, &tve->partition);
559 afs_com_err(whoami, 0, "Can't parse partition '%s'", partName);
562 tp = (char *)malloc(strlen(vsname) + 1);
564 afs_com_err(whoami, 0,
565 "Can't malloc() a new volume spec volume pattern field!");
571 /* Now, thread it onto the list of other volume spec entries for
572 * the current volume set.
575 for (ppve = &tvs->ventries, pve = *ppve; pve;
576 ppve = &pve->next, pve = *ppve);
578 tve->next = (struct bc_volumeEntry *)0;
582 /* If we hit an EOF in the middle of a volume set record, we bitch and
589 * Well, we did it. Return successfully.
593 } /*bc_ParseVolumeSet */
596 * save the current volume set information to disk
601 register afs_int32 code = 0;
602 register struct bc_volumeSet *tset;
603 register struct bc_volumeEntry *tentry;
605 udbClientTextP ctPtr;
606 register FILE *stream;
607 struct bc_config *configPtr;
609 extern struct bc_config *bc_globalConfig;
611 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
612 stream = ctPtr->textStream;
613 configPtr = bc_globalConfig;
616 if (ctPtr->lockHandle == 0)
617 return (BC_INTERNALERROR);
619 /* truncate the file */
620 code = ftruncate(fileno(stream), 0);
626 /* now write the volumeset information */
628 for (tset = bc_globalConfig->vset; tset != 0; tset = tset->next) {
629 if (tset->flags & VSFLAG_TEMPORARY)
630 continue; /* skip temporary entries */
632 fprintf(stream, "volumeset %s\n", tset->name);
633 for (tentry = tset->ventries; tentry; tentry = tentry->next) {
634 fprintf(stream, "%s %s %s\n", tentry->serverName,
635 tentry->partname, tentry->name);
637 fprintf(stream, "end\n");
641 return (BC_INTERNALERROR);
644 code = bcdb_SaveTextFile(ctPtr);
648 /* do this on bcdb_SaveTextFile */
649 /* increment local version number */
650 ctPtr->textVersion++;
652 /* update locally stored file size */
653 ctPtr->textSize = filesize(ctPtr->textStream);
662 struct udbHandleS *uhptr = &udbHandle;
663 udbClientTextP ctPtr;
667 /* lock schedules and check validity */
668 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
670 /* Don't need a lock to check the version */
671 code = bc_CheckTextVersion(ctPtr);
672 if (code != BC_VERSIONMISMATCH) {
673 ERROR(code); /* version matches or some other error */
676 /* Must update the volume sets */
677 /* If no lock alredy taken, then lock it */
678 if (ctPtr->lockHandle == 0) {
679 code = bc_LockText(ctPtr);
685 if (ctPtr->textVersion != -1) {
686 printf("backup: obsolete volumesets - updating\n");
687 bc_ClearVolumeSets();
690 /* open a temp file to store the config text received from buserver *
691 * The open file stream is stored in ctPtr->textStream */
693 bc_openTextFile(ctPtr,
694 &bc_globalConfig->tmpTextFileNames[TB_VOLUMESET][0]);
697 /* now get a fresh set of information from the database */
698 code = bcdb_GetTextFile(ctPtr);
702 /* fetch the version number */
704 ubik_BUDB_GetTextVersion(uhptr->uh_client, 0, ctPtr->textType,
705 &ctPtr->textVersion);
710 code = bc_ParseVolumeSet();
715 if (lock && ctPtr->lockHandle)
716 bc_UnlockText(ctPtr);