bucoord: Set but not used variables
[openafs.git] / src / bucoord / vol_sets.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <afs/stds.h>
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #else
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netdb.h>
22 #endif
23 #include <errno.h>
24 #include <afs/budb_client.h>
25 #include <afs/cmd.h>
26 #include <afs/com_err.h>
27 #include <afs/bubasics.h>
28 #include "bc.h"
29 #include "error_macros.h"
30 #include "bucoord_internal.h"
31 #include "bucoord_prototypes.h"
32
33 /* code to manage volumesets
34  * specific to the ubik database implementation
35  */
36
37 extern struct bc_config *bc_globalConfig;
38 extern struct udbHandleS udbHandle;
39 extern char *whoami;
40
41 static int ListVolSet(struct bc_volumeSet *aset);
42
43 /* ------------------------------------
44  * command level routines
45  * ------------------------------------
46  */
47
48
49 /* bc_AddVolEntryCmd
50  *      add a volume (or volume expression) to a volume set
51  * params:
52  *      parm 0 is vol set name.
53  *      parm 1 is server name
54  *      parm 2 is partition name
55  *      parm 3 is volume regexp
56  */
57
58 int
59 bc_AddVolEntryCmd(struct cmd_syndesc *as, void *arock)
60 {
61     int code;
62     char *volSetName, *serverName, *partitionName, *volRegExp;
63     udbClientTextP ctPtr;
64     struct bc_volumeSet *tset;
65
66     volSetName = as->parms[0].items->data;
67     serverName = as->parms[1].items->data;
68     partitionName = as->parms[2].items->data;
69     volRegExp = as->parms[3].items->data;
70
71     code = bc_UpdateVolumeSet();
72     if (code) {
73         afs_com_err(whoami, code, "; Can't retrieve volume sets");
74         return (code);
75     }
76
77     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
78
79     tset = bc_FindVolumeSet(bc_globalConfig, volSetName);
80     if (!tset) {
81         afs_com_err(whoami, code, "; Volume entry not added");
82         ERROR(code);
83     }
84
85     if (!(tset->flags & VSFLAG_TEMPORARY)) {
86         code = bc_LockText(ctPtr);
87         if (code)
88             ERROR(code);
89     }
90
91     code = bc_UpdateVolumeSet();
92     if (code) {
93         afs_com_err(whoami, code, "; Can't retrieve volume sets");
94         return (code);
95     }
96
97     code =
98         bc_AddVolumeItem(bc_globalConfig, volSetName, serverName,
99                          partitionName, volRegExp);
100     if (code) {
101         afs_com_err(whoami, code, "; Volume entry not added");
102         ERROR(code);
103     }
104
105     if (!(tset->flags & VSFLAG_TEMPORARY)) {
106         code = bc_SaveVolumeSet();
107         if (code) {
108             afs_com_err(whoami, code, "Cannot save volume set file");
109             afs_com_err(whoami, 0,
110                     "Changes are temporary - for this session only");
111         }
112     }
113
114   error_exit:
115     if (ctPtr->lockHandle)
116         bc_UnlockText(ctPtr);
117     return (code);
118 }
119
120
121
122 /* bc_AddVolSetCmd
123  *      create a new volume set, writing out the new volumeset
124  *      file in a safe manner
125  * params:
126  *      name of new volume set
127  */
128
129 int
130 bc_AddVolSetCmd(struct cmd_syndesc *as, void *arock)
131 {
132     /* parm 0 is vol set name */
133     int code;
134     struct cmd_item *ti;
135     udbClientTextP ctPtr;
136     afs_int32 flags;
137
138     /* lock schedules and check validity */
139     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
140
141     flags = (as->parms[1].items ? VSFLAG_TEMPORARY : 0);
142
143     /* Don't lock if adding a temporary volumeset */
144     if (!(flags & VSFLAG_TEMPORARY)) {
145         code = bc_LockText(ctPtr);
146         if (code)
147             ERROR(code);
148     }
149
150     code = bc_UpdateVolumeSet();
151     if (code) {
152         afs_com_err(whoami, code, "; Can't retrieve volume sets");
153         return (code);
154     }
155
156     /* validate size of volumeset name */
157     code =
158         bc_CreateVolumeSet(bc_globalConfig, (ti = as->parms[0].items)->data,
159                            flags);
160     if (code) {
161         if (code == -1)
162             afs_com_err(whoami, 0, "Volume set '%s' already exists", ti->data);
163         else
164             afs_com_err(whoami, 0, "Unknown problem");
165     } else if (!(flags & VSFLAG_TEMPORARY)) {
166         code = bc_SaveVolumeSet();
167         if (code) {
168             afs_com_err(whoami, code, "Cannot save new volume set file");
169             afs_com_err(whoami, 0,
170                     "Changes are temporary - for this session only");
171         }
172     }
173
174   error_exit:
175     if (ctPtr->lockHandle != 0)
176         bc_UnlockText(ctPtr);
177     return (code);
178 }
179
180
181 /* bc_DeleteVolEntryCmd
182  *      delete a volume specification from a volume set
183  * params:
184  *      parm 0 is vol set name
185  *      parm 1 is entry # (integer, 1 based)
186  */
187
188 int
189 bc_DeleteVolEntryCmd(struct cmd_syndesc *as, void *arock)
190 {
191     int code;
192     afs_int32 entry;
193     char *vsname;
194     udbClientTextP ctPtr;
195     struct bc_volumeSet *tset;
196
197     vsname = as->parms[0].items->data;
198
199     code = bc_UpdateVolumeSet();
200     if (code) {
201         afs_com_err(whoami, code, "; Can't retrieve volume sets");
202         return (code);
203     }
204
205     /* lock schedules and check validity */
206     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
207
208     tset = bc_FindVolumeSet(bc_globalConfig, vsname);
209     if (!tset) {
210         afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
211         ERROR(code);
212     }
213
214     if (!(tset->flags & VSFLAG_TEMPORARY)) {
215         code = bc_LockText(ctPtr);
216         if (code)
217             ERROR(code);
218     }
219
220     code = bc_UpdateVolumeSet();
221     if (code) {
222         afs_com_err(whoami, code, "; Can't retrieve volume sets");
223         return (code);
224     }
225
226     entry = bc_SafeATOI(as->parms[1].items->data);
227     if (entry < 0) {
228         afs_com_err(whoami, 0, "Can't parse entry number '%s' as decimal integer",
229                 as->parms[1].items->data);
230         ERROR(BC_BADARG);
231     }
232
233     code = bc_DeleteVolumeItem(bc_globalConfig, vsname, entry);
234     if (code) {
235         if (code == -1) {
236             afs_com_err(whoami, 0, "No such volume set as '%s'", vsname);
237         } else if (code == -2) {
238             afs_com_err(whoami, 0,
239                     "There aren't %d volume items for this volume set",
240                     entry);
241             afs_com_err(whoami, 0,
242                     "Use the 'listvolsets' command to examine the volume set");
243         }
244         ERROR(code);
245     }
246
247     if (!(tset->flags & VSFLAG_TEMPORARY)) {
248         code = bc_SaveVolumeSet();
249         if (code == 0) {
250             printf("backup: deleted volume entry %d from volume set %s\n",
251                    entry, vsname);
252         } else {
253             afs_com_err(whoami, code, "Cannot save volume set file");
254             afs_com_err(whoami, 0,
255                     "Deletion is temporary - for this session only");
256         }
257     }
258
259   error_exit:
260     if (ctPtr->lockHandle != 0)
261         bc_UnlockText(ctPtr);
262     return (code);
263 }
264
265
266
267
268 /* bc_DeleteVolSetCmd
269  *      delete a volume set, writing out a new configuration file when
270  *      completed
271  * params:
272  *      name of volumeset to delete
273  */
274
275 int
276 bc_DeleteVolSetCmd(struct cmd_syndesc *as, void *arock)
277 {
278     /* parm 0 is vol set name */
279     int code;
280     struct cmd_item *ti;
281     udbClientTextP ctPtr;
282     afs_int32 c;
283     afs_int32 flags, tosave = 0;
284
285     /* lock schedules and check validity */
286     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
287
288     code = bc_LockText(ctPtr);
289     if (code)
290         ERROR(code);
291
292     code = bc_UpdateVolumeSet();
293     if (code) {
294         afs_com_err(whoami, code, "; Can't retrieve volume sets");
295         return (code);
296     }
297
298     for (ti = as->parms[0].items; ti; ti = ti->next) {
299         code = bc_DeleteVolumeSet(bc_globalConfig, ti->data, &flags);
300         if (code) {
301             if (code == -1)
302                 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
303             else
304                 afs_com_err(whoami, code,
305                         "; Unknown problem deleting volume set '%s'",
306                         ti->data);
307         } else {
308             if (!(flags & VSFLAG_TEMPORARY))
309                 tosave = 1;
310             printf("backup: deleted volume set '%s'\n", ti->data);
311         }
312     }
313
314     /* now write out the file */
315     if (tosave) {
316         c = bc_SaveVolumeSet();
317         if (c) {
318             if (!code)
319                 code = c;
320             afs_com_err(whoami, c, "Cannot save updated volume set file");
321             afs_com_err(whoami, 0, "Deletion effective for this session only");
322         }
323
324     }
325
326   error_exit:
327     if (ctPtr->lockHandle)
328         bc_UnlockText(ctPtr);
329     return (code);
330 }
331
332
333 static int
334 ListVolSet(struct bc_volumeSet *aset)
335 {
336     struct bc_volumeEntry *tentry;
337     int i;
338
339     printf("Volume set %s", aset->name);
340     if (aset->flags & VSFLAG_TEMPORARY)
341         printf(" (temporary)");
342     printf(":\n");
343     i = 1;
344     for (tentry = aset->ventries; tentry; tentry = tentry->next, i++) {
345         printf("    Entry %3d: server %s, partition %s, volumes: %s\n", i,
346                tentry->serverName, tentry->partname, tentry->name);
347     }
348     return 0;
349 }
350
351  /* bc_ListVolSetCmd
352   *     list out all the information (?) about a volumeset or about all
353   *     volumesets
354   * entry:
355   *     optional parameter specifies a volumeset name
356   */
357
358 int
359 bc_ListVolSetCmd(struct cmd_syndesc *as, void *arock)
360 {
361     /* parm 0 is optional volume set to display */
362     struct bc_volumeSet *tset;
363     struct cmd_item *ti;
364     int code = 0;
365
366     code = bc_UpdateVolumeSet();
367     if (code) {
368         afs_com_err(whoami, code, "; Can't retrieve volume sets");
369         return (code);
370     }
371
372     /* figure out volume set to list */
373     if ((ti = as->parms[0].items)) {
374         /* for each volume set in the command item list */
375         for (; ti; ti = ti->next) {
376             tset = bc_FindVolumeSet(bc_globalConfig, ti->data);
377             if (tset) {
378                 ListVolSet(tset);
379                 printf("\n");
380             } else {
381                 afs_com_err(whoami, 0, "Can't find volume set '%s'", ti->data);
382                 code = 1;
383             }
384         }
385     } else {
386         /* no command parameters specified, show entire list */
387         for (tset = bc_globalConfig->vset; tset; tset = tset->next) {
388             ListVolSet(tset);
389             printf("\n");
390         }
391     }
392
393     return code;
394 }
395
396
397
398 /* ------------------------------------
399  * support routines
400  * ------------------------------------
401  */
402
403 int
404 bc_ClearVolumeSets(void)
405 {
406     struct bc_volumeSet *vsPtr, *vsNextPtr, **vsPrev;
407
408     extern struct bc_config *bc_globalConfig;
409
410     vsPrev = &(bc_globalConfig->vset);
411     for (vsPtr = bc_globalConfig->vset; vsPtr; vsPtr = vsNextPtr) {
412         vsNextPtr = vsPtr->next;
413
414         if (vsPtr->flags & VSFLAG_TEMPORARY) {  /* Skip temporary volumeSet */
415             vsPrev = &(vsPtr->next);
416             continue;
417         }
418
419         *vsPrev = vsPtr->next;  /* Remove volumeSet from the chain */
420         FreeVolumeSet(vsPtr);
421     }
422     return (0);
423 }
424
425 /* bc_ParseVolumeSet
426  *      Open up the volume set configuration file as specified in our argument,
427  *      then parse the file to set up our internal representation.
428  * exit:
429  *      0 on successful processing,
430  *      -1 otherwise.
431  */
432
433 int
434 bc_ParseVolumeSet(void)
435 {
436     char tbuffer[1024];         /*Buffer for reading config file */
437     char vsname[256];           /*Volume set name */
438     char serverName[256];       /*Server name */
439     char partName[256];         /*Partition name */
440     struct bc_volumeEntry *tve; /*Ptr to generated volume spec struct */
441     struct bc_volumeSet *tvs = NULL;    /*Ptr to volume set struct */
442     struct bc_volumeEntry **ppve, *pve;
443     struct bc_volumeSet **ppvs, *pvs;
444     afs_int32 code;     /*Generalized return code */
445     char *tp;                   /*Result of fgets(), malloc() */
446     int readHeader;             /*Is next thing to read a volume set hdr? */
447
448     udbClientTextP ctPtr;
449     FILE *stream;
450
451     extern struct bc_config *bc_globalConfig;
452
453     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
454     stream = ctPtr->textStream;
455
456     /*
457      * Open up the volume set configuration file, fail if it can't be done.
458      */
459
460     if (ctPtr->textSize == 0)   /* empty is ok */
461         return (0);
462
463     /* stream checks and initialization */
464     if (stream == NULL)
465         return (BC_INTERNALERROR);
466
467     rewind(stream);
468
469     readHeader = 1;
470     while (1) {
471         /* Read in and process the next line of the volume set description
472          * file.
473          */
474         tp = fgets(tbuffer, sizeof(tbuffer), stream);
475         if (!tp)
476             break;
477         if (readHeader) {       /*r */
478             /*
479              * Scan a header entry.
480              */
481             readHeader = 0;
482             code = sscanf(tbuffer, "%s %s", serverName, vsname);
483             if ((code != 2)
484                 || (strcmp(serverName, "volumeset") != 0)
485                 ) {
486                 afs_com_err(whoami, 0, "Bad volume header line: '%s'", tbuffer);
487                 return (-1);
488             }
489
490             /* Create and fill in the volume set descriptor structure from
491              * the info just read placing it at the head of its queue in the
492              * global configuration structure.
493              */
494             tvs = (struct bc_volumeSet *)malloc(sizeof(struct bc_volumeSet));
495             memset(tvs, 0, sizeof(*tvs));
496             tvs->name = (char *)malloc(strlen(vsname) + 1);
497             strcpy(tvs->name, vsname);
498
499             /* append to the end */
500             for (ppvs = &bc_globalConfig->vset, pvs = *ppvs; pvs;
501                  ppvs = &pvs->next, pvs = *ppvs);
502             *ppvs = tvs;
503             tvs->next = (struct bc_volumeSet *)0;
504         } /*r */
505         else {                  /*e */
506             /* Scan a volume name entry, which contains the server name,
507              * partition pattern, and volume pattern.
508              */
509             code = sscanf(tbuffer, "%s %s %s", serverName, partName, vsname);
510             if (code == 1 && strcmp(serverName, "end") == 0) {
511                 /* This was really a line delimiting the current volume set.
512                  * Next time around, we should try to read a header.
513                  */
514                 readHeader = 1;
515                 continue;
516             }
517
518             /* The line just read in is a volume spec.  Create a new volume
519              * spec record, then get the rest of the information regarding
520              * the host, and stuff everything into place.
521              */
522             tve = (struct bc_volumeEntry *)
523                 malloc(sizeof(struct bc_volumeEntry));
524             if (!tve) {
525                 afs_com_err(whoami, 0,
526                         "Can't malloc() a new volume spec record!");
527                 return (-1);
528             }
529             memset(tve, 0, sizeof(*tve));
530             if (bc_ParseHost(serverName, &(tve->server)))
531                 afs_com_err(whoami, 0, "Can't get required info on host '%s'",
532                         serverName);
533
534             /* The above code has filled in the server sockaddr, now fill in
535              * the rest of the fields.
536              */
537             tve->serverName = (char *)malloc(strlen(serverName) + 1);
538             if (!tve->serverName) {
539                 afs_com_err(whoami, 0,
540                         "Can't malloc() a new volume spec server name field!");
541                 return (-1);
542             }
543             strcpy(tve->serverName, serverName);
544             tve->partname = (char *)malloc(strlen(partName) + 1);
545             if (!tve->partname) {
546                 afs_com_err(whoami, 0,
547                         "Can't malloc() a new volume spec partition pattern field!");
548                 return (-1);
549             }
550             strcpy(tve->partname, partName);
551             code = bc_GetPartitionID(partName, &tve->partition);
552             if (code) {
553                 afs_com_err(whoami, 0, "Can't parse partition '%s'", partName);
554                 return -1;
555             }
556             tp = (char *)malloc(strlen(vsname) + 1);
557             if (!tp) {
558                 afs_com_err(whoami, 0,
559                         "Can't malloc() a new volume spec volume pattern field!");
560                 return (-1);
561             }
562             strcpy(tp, vsname);
563             tve->name = tp;
564
565             /* Now, thread it onto the list of other volume spec entries for
566              * the current volume set.
567              */
568
569             for (ppve = &tvs->ventries, pve = *ppve; pve;
570                  ppve = &pve->next, pve = *ppve);
571             *ppve = tve;
572             tve->next = (struct bc_volumeEntry *)0;
573         }
574     }                           /*forever loop */
575
576     /* If we hit an EOF in the middle of a volume set record, we bitch and
577      * moan.
578      */
579     if (!readHeader)
580         return (-1);
581
582     /*
583      * Well, we did it.  Return successfully.
584      */
585     return (0);
586
587 }                               /*bc_ParseVolumeSet */
588
589 /* bc_SaveVolumeSet
590  *      save the current volume set information to disk
591  */
592
593 int
594 bc_SaveVolumeSet(void)
595 {
596     afs_int32 code = 0;
597     struct bc_volumeSet *tset;
598     struct bc_volumeEntry *tentry;
599
600     udbClientTextP ctPtr;
601     FILE *stream;
602
603     extern struct bc_config *bc_globalConfig;
604
605     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
606     stream = ctPtr->textStream;
607
608     /* must be locked */
609     if (ctPtr->lockHandle == 0)
610         return (BC_INTERNALERROR);
611
612     /* truncate the file */
613     code = ftruncate(fileno(stream), 0);
614     if (code)
615         ERROR(errno);
616
617     rewind(stream);
618
619     /* now write the volumeset information */
620
621     for (tset = bc_globalConfig->vset; tset != 0; tset = tset->next) {
622         if (tset->flags & VSFLAG_TEMPORARY)
623             continue;           /* skip temporary entries */
624
625         fprintf(stream, "volumeset %s\n", tset->name);
626         for (tentry = tset->ventries; tentry; tentry = tentry->next) {
627             fprintf(stream, "%s %s %s\n", tentry->serverName,
628                     tentry->partname, tentry->name);
629         }
630         fprintf(stream, "end\n");
631     }
632
633     if (ferror(stream))
634         return (BC_INTERNALERROR);
635
636     /* send to server */
637     code = bcdb_SaveTextFile(ctPtr);
638     if (code)
639         ERROR(code);
640
641     /* do this on bcdb_SaveTextFile */
642     /* increment local version number */
643     ctPtr->textVersion++;
644
645     /* update locally stored file size */
646     ctPtr->textSize = filesize(ctPtr->textStream);
647
648   error_exit:
649     return (code);
650 }
651
652 afs_int32
653 bc_UpdateVolumeSet(void)
654 {
655     struct udbHandleS *uhptr = &udbHandle;
656     udbClientTextP ctPtr;
657     afs_int32 code;
658     int lock = 0;
659
660     /* lock schedules and check validity */
661     ctPtr = &bc_globalConfig->configText[TB_VOLUMESET];
662
663     /* Don't need a lock to check the version */
664     code = bc_CheckTextVersion(ctPtr);
665     if (code != BC_VERSIONMISMATCH) {
666         ERROR(code);            /* version matches or some other error */
667     }
668
669     /* Must update the volume sets */
670     /* If no lock alredy taken, then lock it */
671     if (ctPtr->lockHandle == 0) {
672         code = bc_LockText(ctPtr);
673         if (code)
674             ERROR(code);
675         lock = 1;
676     }
677
678     if (ctPtr->textVersion != -1) {
679         printf("backup: obsolete volumesets - updating\n");
680         bc_ClearVolumeSets();
681     }
682
683     /* open a temp file to store the config text received from buserver *
684      * The open file stream is stored in ctPtr->textStream */
685     code =
686         bc_openTextFile(ctPtr,
687                         &bc_globalConfig->tmpTextFileNames[TB_VOLUMESET][0]);
688     if (code)
689         ERROR(code);
690     /* now get a fresh set of information from the database */
691     code = bcdb_GetTextFile(ctPtr);
692     if (code)
693         ERROR(code);
694
695     /* fetch the version number */
696     code =
697         ubik_BUDB_GetTextVersion(uhptr->uh_client, 0, ctPtr->textType,
698                   &ctPtr->textVersion);
699     if (code)
700         ERROR(code);
701
702     /* parse the file */
703     code = bc_ParseVolumeSet();
704     if (code)
705         ERROR(code);
706
707   error_exit:
708     if (lock && ctPtr->lockHandle)
709         bc_UnlockText(ctPtr);
710     return (code);
711 }