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);
45 /* ------------------------------------
46 * command level routines
47 * ------------------------------------
52 * add a volume (or volume expression) to a volume set
54 * parm 0 is vol set name.
55 * parm 1 is server name
56 * parm 2 is partition name
57 * parm 3 is volume regexp
60 bc_AddVolEntryCmd(as, arock)
61 struct cmd_syndesc *as;
64 register afs_int32 code;
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(as, arock)
134 struct cmd_syndesc *as;
137 /* parm 0 is vol set name */
138 register afs_int32 code;
139 register struct cmd_item *ti;
140 udbClientTextP ctPtr;
143 /* lock schedules and check validity */
144 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
146 flags = (as->parms[1].items ? VSFLAG_TEMPORARY : 0);
148 /* Don't lock if adding a temporary volumeset */
149 if (!(flags & VSFLAG_TEMPORARY)) {
150 code = bc_LockText(ctPtr);
155 code = bc_UpdateVolumeSet();
157 afs_com_err(whoami, code, "; Can't retrieve volume sets");
161 /* validate size of volumeset name */
163 bc_CreateVolumeSet(bc_globalConfig, (ti = as->parms[0].items)->data,
167 afs_com_err(whoami, 0, "Volume set '%s' already exists", ti->data);
169 afs_com_err(whoami, 0, "Unknown problem");
170 } else if (!(flags & VSFLAG_TEMPORARY)) {
171 code = bc_SaveVolumeSet();
173 afs_com_err(whoami, code, "Cannot save new volume set file");
174 afs_com_err(whoami, 0,
175 "Changes are temporary - for this session only");
180 if (ctPtr->lockHandle != 0)
181 bc_UnlockText(ctPtr);
186 /* bc_DeleteVolEntryCmd
187 * delete a volume specification from a volume set
189 * parm 0 is vol set name
190 * parm 1 is entry # (integer, 1 based)
194 bc_DeleteVolEntryCmd(as, arock)
195 struct cmd_syndesc *as;
198 register afs_int32 code;
201 udbClientTextP ctPtr;
202 struct bc_volumeSet *tset;
204 vsname = as->parms[0].items->data;
206 code = bc_UpdateVolumeSet();
208 afs_com_err(whoami, code, "; Can't retrieve volume sets");
212 /* lock schedules and check validity */
213 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
215 tset = bc_FindVolumeSet(bc_globalConfig, vsname);
217 afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
221 if (!(tset->flags & VSFLAG_TEMPORARY)) {
222 code = bc_LockText(ctPtr);
227 code = bc_UpdateVolumeSet();
229 afs_com_err(whoami, code, "; Can't retrieve volume sets");
233 entry = bc_SafeATOI(as->parms[1].items->data);
235 afs_com_err(whoami, 0, "Can't parse entry number '%s' as decimal integer",
236 as->parms[1].items->data);
240 code = bc_DeleteVolumeItem(bc_globalConfig, vsname, entry);
243 afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
244 } else if (code == -2) {
245 afs_com_err(whoami, 0,
246 "There aren't %d volume items for this volume set",
248 afs_com_err(whoami, 0,
249 "Use the 'listvolsets' command to examine the volume set");
254 if (!(tset->flags & VSFLAG_TEMPORARY)) {
255 code = bc_SaveVolumeSet();
257 printf("backup: deleted volume entry %d from volume set %s\n",
260 afs_com_err(whoami, code, "Cannot save volume set file");
261 afs_com_err(whoami, 0,
262 "Deletion is temporary - for this session only");
267 if (ctPtr->lockHandle != 0)
268 bc_UnlockText(ctPtr);
275 /* bc_DeleteVolSetCmd
276 * delete a volume set, writing out a new configuration file when
279 * name of volumeset to delete
283 bc_DeleteVolSetCmd(as, arock)
284 struct cmd_syndesc *as;
287 /* parm 0 is vol set name */
288 register afs_int32 code;
289 register struct cmd_item *ti;
290 udbClientTextP ctPtr;
292 afs_int32 flags, tosave = 0;
294 /* lock schedules and check validity */
295 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
297 code = bc_LockText(ctPtr);
301 code = bc_UpdateVolumeSet();
303 afs_com_err(whoami, code, "; Can't retrieve volume sets");
307 for (ti = as->parms[0].items; ti; ti = ti->next) {
308 code = bc_DeleteVolumeSet(bc_globalConfig, ti->data, &flags);
311 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
313 afs_com_err(whoami, code,
314 "; Unknown problem deleting volume set '%s'",
317 if (!(flags & VSFLAG_TEMPORARY))
319 printf("backup: deleted volume set '%s'\n", ti->data);
323 /* now write out the file */
325 c = bc_SaveVolumeSet();
329 afs_com_err(whoami, c, "Cannot save updated volume set file");
330 afs_com_err(whoami, 0, "Deletion effective for this session only");
336 if (ctPtr->lockHandle)
337 bc_UnlockText(ctPtr);
343 ListVolSet(struct bc_volumeSet *aset)
345 struct bc_volumeEntry *tentry;
348 printf("Volume set %s", aset->name);
349 if (aset->flags & VSFLAG_TEMPORARY)
350 printf(" (temporary)");
353 for (tentry = aset->ventries; tentry; tentry = tentry->next, i++) {
354 printf(" Entry %3d: server %s, partition %s, volumes: %s\n", i,
355 tentry->serverName, tentry->partname, tentry->name);
361 * list out all the information (?) about a volumeset or about all
364 * optional parameter specifies a volumeset name
368 bc_ListVolSetCmd(struct cmd_syndesc *as, char *arock)
370 /* parm 0 is optional volume set to display */
371 register struct bc_volumeSet *tset;
372 register struct cmd_item *ti;
375 code = bc_UpdateVolumeSet();
377 afs_com_err(whoami, code, "; Can't retrieve volume sets");
381 /* figure out volume set to list */
382 if (ti = as->parms[0].items) {
383 /* for each volume set in the command item list */
384 for (; ti; ti = ti->next) {
385 tset = bc_FindVolumeSet(bc_globalConfig, ti->data);
390 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
395 /* no command parameters specified, show entire list */
396 for (tset = bc_globalConfig->vset; tset; tset = tset->next) {
407 /* ------------------------------------
409 * ------------------------------------
414 struct udbHandleS *uhptr = &udbHandle;
415 struct bc_volumeSet *vsPtr, *vsNextPtr, **vsPrev;
417 extern struct bc_config *bc_globalConfig;
419 vsPrev = &(bc_globalConfig->vset);
420 for (vsPtr = bc_globalConfig->vset; vsPtr; vsPtr = vsNextPtr) {
421 vsNextPtr = vsPtr->next;
423 if (vsPtr->flags & VSFLAG_TEMPORARY) { /* Skip temporary volumeSet */
424 vsPrev = &(vsPtr->next);
428 *vsPrev = vsPtr->next; /* Remove volumeSet from the chain */
429 FreeVolumeSet(vsPtr);
435 * Open up the volume set configuration file as specified in our argument,
436 * then parse the file to set up our internal representation.
438 * 0 on successful processing,
445 static char rn[] = "bc_ParseVolumeSet"; /*Routine name */
446 char tbuffer[1024]; /*Buffer for reading config file */
447 char vsname[256]; /*Volume set name */
448 char serverName[256]; /*Server name */
449 char partName[256]; /*Partition name */
450 register struct bc_volumeEntry *tve; /*Ptr to generated volume spec struct */
451 register struct bc_volumeSet *tvs; /*Ptr to volume set struct */
452 struct bc_volumeEntry **ppve, *pve;
453 struct bc_volumeSet **ppvs, *pvs;
454 register afs_int32 code; /*Generalized return code */
455 char *tp; /*Result of fgets(), malloc() */
456 int readHeader; /*Is next thing to read a volume set hdr? */
458 udbClientTextP ctPtr;
459 register FILE *stream;
460 struct bc_config *configPtr;
462 extern struct bc_config *bc_globalConfig;
464 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
465 stream = ctPtr->textStream;
466 configPtr = bc_globalConfig;
469 * Open up the volume set configuration file, fail if it can't be done.
472 if (ctPtr->textSize == 0) /* empty is ok */
475 /* stream checks and initialization */
477 return (BC_INTERNALERROR);
483 /* Read in and process the next line of the volume set description
486 tp = fgets(tbuffer, sizeof(tbuffer), stream);
489 if (readHeader) { /*r */
491 * Scan a header entry.
494 code = sscanf(tbuffer, "%s %s", serverName, vsname);
496 || (strcmp(serverName, "volumeset") != 0)
498 afs_com_err(whoami, 0, "Bad volume header line: '%s'", tbuffer);
502 /* Create and fill in the volume set descriptor structure from
503 * the info just read placing it at the head of its queue in the
504 * global configuration structure.
506 tvs = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
507 memset(tvs, 0, sizeof(*tvs));
508 tvs->name = (char *)malloc(strlen(vsname) + 1);
509 strcpy(tvs->name, vsname);
511 /* append to the end */
512 for (ppvs = &bc_globalConfig->vset, pvs = *ppvs; pvs;
513 ppvs = &pvs->next, pvs = *ppvs);
515 tvs->next = (struct bc_volumeSet *)0;
518 /* Scan a volume name entry, which contains the server name,
519 * partition pattern, and volume pattern.
521 code = sscanf(tbuffer, "%s %s %s", serverName, partName, vsname);
522 if (code == 1 && strcmp(serverName, "end") == 0) {
523 /* This was really a line delimiting the current volume set.
524 * Next time around, we should try to read a header.
530 /* The line just read in is a volume spec. Create a new volume
531 * spec record, then get the rest of the information regarding
532 * the host, and stuff everything into place.
534 tve = (struct bc_volumeEntry *)
535 malloc(sizeof(struct bc_volumeEntry));
537 afs_com_err(whoami, 0,
538 "Can't malloc() a new volume spec record!");
541 memset(tve, 0, sizeof(*tve));
542 if (bc_ParseHost(serverName, &(tve->server)))
543 afs_com_err(whoami, 0, "Can't get required info on host '%s'",
546 /* The above code has filled in the server sockaddr, now fill in
547 * the rest of the fields.
549 tve->serverName = (char *)malloc(strlen(serverName) + 1);
550 if (!tve->serverName) {
551 afs_com_err(whoami, 0,
552 "Can't malloc() a new volume spec server name field!");
555 strcpy(tve->serverName, serverName);
556 tve->partname = (char *)malloc(strlen(partName) + 1);
557 if (!tve->partname) {
558 afs_com_err(whoami, 0,
559 "Can't malloc() a new volume spec partition pattern field!");
562 strcpy(tve->partname, partName);
563 code = bc_GetPartitionID(partName, &tve->partition);
565 afs_com_err(whoami, 0, "Can't parse partition '%s'", partName);
568 tp = (char *)malloc(strlen(vsname) + 1);
570 afs_com_err(whoami, 0,
571 "Can't malloc() a new volume spec volume pattern field!");
577 /* Now, thread it onto the list of other volume spec entries for
578 * the current volume set.
581 for (ppve = &tvs->ventries, pve = *ppve; pve;
582 ppve = &pve->next, pve = *ppve);
584 tve->next = (struct bc_volumeEntry *)0;
588 /* If we hit an EOF in the middle of a volume set record, we bitch and
595 * Well, we did it. Return successfully.
599 } /*bc_ParseVolumeSet */
602 * save the current volume set information to disk
607 register afs_int32 code = 0;
608 register struct bc_volumeSet *tset;
609 register struct bc_volumeEntry *tentry;
611 udbClientTextP ctPtr;
612 register FILE *stream;
613 struct bc_config *configPtr;
615 extern struct bc_config *bc_globalConfig;
617 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
618 stream = ctPtr->textStream;
619 configPtr = bc_globalConfig;
622 if (ctPtr->lockHandle == 0)
623 return (BC_INTERNALERROR);
625 /* truncate the file */
626 code = ftruncate(fileno(stream), 0);
632 /* now write the volumeset information */
634 for (tset = bc_globalConfig->vset; tset != 0; tset = tset->next) {
635 if (tset->flags & VSFLAG_TEMPORARY)
636 continue; /* skip temporary entries */
638 fprintf(stream, "volumeset %s\n", tset->name);
639 for (tentry = tset->ventries; tentry; tentry = tentry->next) {
640 fprintf(stream, "%s %s %s\n", tentry->serverName,
641 tentry->partname, tentry->name);
643 fprintf(stream, "end\n");
647 return (BC_INTERNALERROR);
650 code = bcdb_SaveTextFile(ctPtr);
654 /* do this on bcdb_SaveTextFile */
655 /* increment local version number */
656 ctPtr->textVersion++;
658 /* update locally stored file size */
659 ctPtr->textSize = filesize(ctPtr->textStream);
668 struct udbHandleS *uhptr = &udbHandle;
669 udbClientTextP ctPtr;
673 /* lock schedules and check validity */
674 ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
676 /* Don't need a lock to check the version */
677 code = bc_CheckTextVersion(ctPtr);
678 if (code != BC_VERSIONMISMATCH) {
679 ERROR(code); /* version matches or some other error */
682 /* Must update the volume sets */
683 /* If no lock alredy taken, then lock it */
684 if (ctPtr->lockHandle == 0) {
685 code = bc_LockText(ctPtr);
691 if (ctPtr->textVersion != -1) {
692 printf("backup: obsolete volumesets - updating\n");
693 bc_ClearVolumeSets();
696 /* open a temp file to store the config text received from buserver *
697 * The open file stream is stored in ctPtr->textStream */
699 bc_openTextFile(ctPtr,
700 &bc_globalConfig->tmpTextFileNames[TB_VOLUMESET][0]);
703 /* now get a fresh set of information from the database */
704 code = bcdb_GetTextFile(ctPtr);
708 /* fetch the version number */
710 ubik_BUDB_GetTextVersion(uhptr->uh_client, 0, ctPtr->textType,
711 &ctPtr->textVersion);
716 code = bc_ParseVolumeSet();
721 if (lock && ctPtr->lockHandle)
722 bc_UnlockText(ctPtr);