convert-from-bsd-to-posix-string-and-memory-functions-20010807
[openafs.git] / src / butc / dbentries.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 RCSID("$Header$");
14
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #else
19 #include <sys/file.h>
20 #include <netinet/in.h>
21 #include <sys/socket.h>
22 #include <sys/time.h>
23 #include <netdb.h>
24 #endif
25 #include <stdlib.h>
26 #include <rx/xdr.h>
27 #include <rx/rx.h>
28 #include <lwp.h>
29 #include <lock.h>
30 #include <afs/tcdata.h>
31 #include <afs/bubasics.h>
32 #include <afs/budb_client.h>
33 #include <afs/vldbint.h>
34
35 #include <afs/vlserver.h>
36 #include <afs/volser.h>
37 #include <afs/volint.h>
38 #include <afs/cellconfig.h>
39
40 #include "error_macros.h"
41
42 extern struct ubik_client *cstruct;
43 dlqlinkT savedEntries;
44 dlqlinkT entries_to_flush;
45
46 int dbWatcherinprogress;
47
48 afs_int32 threadEntryDir(anEntry, size, type)
49      char  *anEntry;
50      afs_int32 size, type;
51 {
52     dlqlinkP entryPtr;
53     char     *entry = (char *)0;
54     int      tried;
55
56     for (tried=0; tried<5; tried++) {
57       entryPtr = (dlqlinkP)malloc(sizeof(dlqlinkT));
58       entry    = (char *)  malloc(size);
59       if (entryPtr && entry)
60          break;
61
62       /* sleep a minute and try again */
63       if (entryPtr) free(entryPtr);
64       if (entry)    free(entry);
65
66       if ((tried > 0) && !dbWatcherinprogress)
67          return(TC_NOMEMORY);
68 #ifdef AFS_PTHREAD_ENV
69       sleep(60);
70 #else
71       IOMGR_Sleep(60);
72 #endif
73     }
74     entryPtr->dlq_prev      = entryPtr->dlq_next = (dlqlinkP)NULL;
75     entryPtr->dlq_type      = type;
76     entryPtr->dlq_structPtr = entry;
77
78     memcpy(entry, anEntry, size);
79     dlqLinkb (&entries_to_flush, entryPtr);
80     return(0);
81 }
82
83 /*
84  * threadEntry.
85  *     Creates an entry and puts it onto the savedEntries list.
86  *     Will retry up to 5 times if not enough memory. Hopfully, the 
87  *     Watcher thread will free up some memory for it to continue.
88  */
89
90 afs_int32 
91 threadEntry(anEntry, size, type)
92      char  *anEntry;
93      afs_int32 size, type;
94 {
95     dlqlinkP entryPtr;
96     char     *entry = (char *)0;
97     int      tried;
98
99     for (tried=0; tried<5; tried++) {
100         entryPtr = (dlqlinkP)malloc(sizeof(dlqlinkT));
101         entry    = (char *)  malloc(size);
102         if (entryPtr && entry)
103            break;
104
105         /* sleep a minute and try again */
106         if (entryPtr) free(entryPtr);
107         if (entry)    free(entry);
108
109         if ((tried > 0) && !dbWatcherinprogress)
110            return(TC_NOMEMORY);
111 #ifdef AFS_PTHREAD_ENV
112         sleep(60);
113 #else
114         IOMGR_Sleep(60);
115 #endif
116     }
117
118     entryPtr->dlq_prev      = entryPtr->dlq_next = (dlqlinkP)NULL;
119     entryPtr->dlq_type      = type;
120     entryPtr->dlq_structPtr = entry;
121
122     memcpy(entry, anEntry, size);
123     dlqLinkb (&savedEntries, (dlqlinkP)entryPtr);
124     return(0);
125 }
126
127 /* ------------------------------------------------------------------ */
128
129 afs_int32 useDump(dumpEntryPtr)
130      struct budb_dumpEntry *dumpEntryPtr;
131 {
132     afs_int32                 code = 0;
133
134     code = threadEntry(dumpEntryPtr, sizeof(struct budb_dumpEntry), DLQ_USEDUMP);
135     return(code);
136 }
137
138 /*
139  * finishDump
140  *     Creates a dump entry (finished) and puts it onto the savedEntries list.
141  */
142 afs_int32 finishDump (aDumpEntryPtr)
143     struct budb_dumpEntry *aDumpEntryPtr;
144 {
145     afs_int32 code=0;
146     
147     code = threadEntry(aDumpEntryPtr, sizeof(struct budb_dumpEntry), DLQ_FINISHDUMP);
148     return (code);
149 }
150
151 /*
152  * useTape
153  *     Creates a tape entry and puts it onto the savedEntries list.
154  */
155 afs_int32 useTape (aTapeEntryPtr, dumpID, tapename, tapeSeq, useCount, written, expiration, tapepos)
156      struct budb_tapeEntry *aTapeEntryPtr;
157      afs_int32                 dumpID;
158      char                  *tapename;
159      afs_int32                 tapeSeq;
160      afs_int32                 useCount;
161      Date                  written;
162      Date                  expiration;
163      afs_int32                 tapepos;
164 {
165     afs_int32 code = 0;
166
167     memset(aTapeEntryPtr, 0, sizeof(struct budb_tapeEntry));
168     strcpy(aTapeEntryPtr->name, tapename);
169     aTapeEntryPtr->flags    = BUDB_TAPE_BEINGWRITTEN;
170     aTapeEntryPtr->written  = written;                  /* When label was written */
171     aTapeEntryPtr->expires  = expiration;
172     aTapeEntryPtr->seq      = tapeSeq;
173     aTapeEntryPtr->useCount = useCount;
174     aTapeEntryPtr->dump     = dumpID;
175     aTapeEntryPtr->labelpos = tapepos;
176     
177     code = threadEntry(aTapeEntryPtr, sizeof(struct budb_tapeEntry), DLQ_USETAPE);
178     return(code);
179 }
180
181 /*
182  * finishTape
183  *     Creates a tape entry (finished) and puts it onto the savedEntries list.
184  */
185 afs_int32 finishTape (aTapeEntryPtr, useKBytes)
186      struct budb_tapeEntry *aTapeEntryPtr;
187      afs_int32                 useKBytes;
188 {
189     afs_int32 code=0;
190     
191     aTapeEntryPtr->flags     = BUDB_TAPE_WRITTEN;
192     aTapeEntryPtr->useKBytes = useKBytes;
193
194     code = threadEntry(aTapeEntryPtr, sizeof(struct budb_tapeEntry), DLQ_FINISHTAPE);
195     return (code);
196 }
197
198 /*
199  * addVolume
200  *     Creates a volume entry and puts it onto the savedEntries list.
201  */
202 afs_int32 addVolume(aVolEntryPtr, dumpID, tapename, volname, volid, cloneDate, 
203                 startPos, volBytes, fragment, flags)
204      struct budb_volumeEntry *aVolEntryPtr;
205      afs_int32 dumpID;
206      char *tapename;
207      char *volname;
208      afs_int32 volid;
209      Date  cloneDate;
210      afs_int32 startPos;
211      afs_int32 volBytes;
212      int fragment;
213      afs_int32 flags;
214 {
215     afs_int32                   code = 0;
216     int                     allo = 0;
217
218     if (!aVolEntryPtr) {
219         aVolEntryPtr = (struct budb_volumeEntry *)malloc(sizeof(struct budb_volumeEntry));
220         if (!aVolEntryPtr) ERROR_EXIT(TC_NOMEMORY);
221         allo = 1;
222     }
223         
224     memset(aVolEntryPtr, 0, sizeof(struct budb_volumeEntry));
225     strcpy(aVolEntryPtr->name, volname);
226     aVolEntryPtr->flags    = flags;
227     aVolEntryPtr->id       = volid;
228     aVolEntryPtr->position = startPos;
229     aVolEntryPtr->clone    = cloneDate;
230     aVolEntryPtr->nBytes   = volBytes;
231     aVolEntryPtr->seq      = fragment;
232     aVolEntryPtr->dump     = dumpID;
233     strcpy(aVolEntryPtr->tape, tapename);
234
235     code = threadEntry(aVolEntryPtr, sizeof(struct budb_volumeEntry), DLQ_VOLENTRY);
236
237 error_exit:
238     if (code && allo) free(aVolEntryPtr);
239     return(code);
240 }
241
242 /*
243  * flushSavedEntries
244  *     Runs through the list of savedEntries and adds the volumes and 
245  *     tapes to the database.
246  *     A status of DUMP_NORETRYEOT means the tape(s) contains no useful data,
247  *     and tapes and volumes should not be added to the DB.
248  */
249 afs_int32 flushSavedEntries (status)
250      afs_int32 status;
251 {
252     dlqlinkP entryPtr;
253     struct budb_tapeEntry *tapePtr;
254     struct budb_volumeEntry *volPtr;
255     afs_int32 code = 0;
256
257     /*
258      * On DUMP_NORETRYEOT, the volume being dumped was the first on the tape and hit the
259      * EOT. This means the volume is larger than the tape. Instead of going onto the next
260      * tape, backup reuses the tape. Thus, we must remove this tape entry and free it
261      * without adding it to the backup database.
262      */
263     if (status == DUMP_NORETRYEOT) {
264         entryPtr = dlqUnlinkb(&savedEntries);
265         if ( !entryPtr || (entryPtr->dlq_type != DLQ_USETAPE) )
266             ERROR_EXIT(TC_INTERNALERROR);
267
268         tapePtr = (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
269         if (tapePtr)  free(tapePtr);
270         if (entryPtr) free(entryPtr);
271     }
272
273     /* 
274      * Add dump, tape, and volume entries to the list for the dbWatcher to 
275      * flush. Volume entries are not added if the volume failed to dump.
276      */
277     while (entryPtr = dlqUnlinkf(&savedEntries)) {
278         if ((entryPtr->dlq_type == DLQ_VOLENTRY) && (status != DUMP_SUCCESS)) {
279             volPtr = (struct budb_volumeEntry *)entryPtr->dlq_structPtr;
280             if (volPtr)   free(volPtr);
281             if (entryPtr) free(entryPtr);
282         }
283         else {
284             dlqLinkb (&entries_to_flush, entryPtr);
285         }
286     }
287
288 error_exit:
289     /* Free anything that remains on dlq */
290     dlqTraverseQueue (&savedEntries, free, free);
291     return (code);
292 }
293
294 waitDbWatcher()
295 {
296   int message = 0;
297
298   while (dbWatcherinprogress || !dlqEmpty(&entries_to_flush)) {
299       if (!message) {
300           printf("Updating database\n");
301           message++;
302       }
303 #ifdef AFS_PTHREAD_ENV
304       sleep(2);
305 #else
306       IOMGR_Sleep(2);
307 #endif
308   }
309
310   if (message) {
311       printf("Updating database - done\n");
312   }
313 }
314
315 #define MAXVOLUMESTOADD 100
316 int addvolumes=1;
317
318 dbWatcher()
319 {
320   dlqlinkP                entryPtr;
321   struct budb_dumpEntry   *dumpPtr;
322   struct budb_tapeEntry   *tapePtr;
323   struct budb_volumeEntry *volPtr, volumes[MAXVOLUMESTOADD];
324   afs_int32                   new;
325   afs_int32                   code = 0;
326   int                     i, c, addedDump;
327   
328   dlqInit(&entries_to_flush);
329   dlqInit(&savedEntries);
330
331   dbWatcherinprogress = 0;
332   addedDump           = 1;
333   while (1) {
334       /*while*/
335       /* Add tape and volume enties to the backup database */
336       while (entryPtr = dlqUnlinkf(&entries_to_flush)) {
337           dbWatcherinprogress = 1;
338
339           if (!entryPtr->dlq_structPtr) {
340              ErrorLog(0, 0, TC_BADQUEUE, 0,
341                       "Warning: Invalid database entry - nota added\n");
342           }
343           else switch (entryPtr->dlq_type) {
344               case DLQ_USEDUMP:
345                   dumpPtr = (struct budb_dumpEntry *)entryPtr->dlq_structPtr;
346                   /* Now call the database to create the entry */
347                   code = bcdb_CreateDump(dumpPtr);
348                   if (code) {
349                      if (code == BUDB_DUMPIDEXISTS) {
350                         printf("Dump %s (DumpID %u) already exists in backup database\n",
351                                dumpPtr->name, dumpPtr->id);
352                      } else {
353                         ErrorLog(0, 0, code, 0, 
354                                  "Warning: Can't create dump %s (DumpID %u) in backup database\n",
355                                  dumpPtr->name, dumpPtr->id);
356                      }
357                   }
358                   addedDump = (code ? 0 : 1);
359                   break;
360
361               case DLQ_FINISHDUMP:
362                   dumpPtr = (struct budb_dumpEntry *)entryPtr->dlq_structPtr;
363                   if (addedDump) {
364                      code = bcdb_FinishDump(dumpPtr);
365                      if (code) {
366                         ErrorLog(0, 0, code, 0, 
367                                  "Warning: Can't finish dump %s (DumpID %u) in backup database\n",
368                                  dumpPtr->name, dumpPtr->id);
369                      }
370                   }
371                   addedDump = 1;
372                   break;
373
374               case DLQ_USETAPE:
375                   tapePtr = (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
376                   if (addedDump) {
377                      code = bcdb_UseTape(tapePtr, &new);
378                      if (code) {
379                         ErrorLog(0, 0, code, 0, 
380                                  "Warning: Can't add tape %s of DumpID %u to backup database\n",
381                                  tapePtr->name, tapePtr->dump);
382                      }
383                   }
384                   break;
385
386               case DLQ_FINISHTAPE:
387                   tapePtr = (struct budb_tapeEntry *)entryPtr->dlq_structPtr;
388                   if (addedDump) {
389                      code = bcdb_FinishTape(tapePtr, &new);
390                      if (code) {
391                         ErrorLog(0, 0, code, 0, 
392                                  "Warning: Can't finish tape %s of DumpID %u in backup database\n",
393                                  tapePtr->name, tapePtr->dump);
394                      }
395                   }
396                   break;
397
398               case DLQ_VOLENTRY:
399                   /* collect array of volumes to add to the dump */
400                   for (c=0; c<MAXVOLUMESTOADD; c++) {
401                      if (c > 0) { /* don't read the 1st - already did */
402                         entryPtr = dlqUnlinkf(&entries_to_flush);       /* Get the next entry */
403                         if (!entryPtr) break;
404                      }
405
406                      if (entryPtr->dlq_type != DLQ_VOLENTRY) {
407                         /* Place back onto list and add the vol entries we have */
408                         dlqLinkf(&entries_to_flush, entryPtr);
409                         entryPtr = (dlqlinkP)0;   /* don't want to deallocate below */
410                         break;
411                      }
412
413                      volPtr = (struct budb_volumeEntry *)entryPtr->dlq_structPtr;
414                      if (!volPtr) {
415                         ErrorLog(0, 0, TC_BADQUEUE, 0, 
416                                  "Warning: Invalid database entry - not added\n");
417                         break;
418                      }
419
420                      memcpy(&volumes[c], volPtr, sizeof(struct budb_volumeEntry));
421                      free(volPtr);
422                      free(entryPtr);
423                      entryPtr = (dlqlinkP)0;
424                   }
425
426                   if (addedDump) {
427                      if (addvolumes) {
428                         code = bcdb_AddVolumes(&volumes[0], c);
429                         if (code) {
430                            if (code < 0)
431                               addvolumes = 0;
432                            else {
433                               ErrorLog(0, 0, code, 0, 
434                                        "Warning: Can't add %d volumes to dumpid %u\n",
435                                        c, volumes[0].dump);
436                            }
437                         }
438                      }
439                      if (!addvolumes) {
440                         for (i=0; i<c; i++) {
441                            code = bcdb_AddVolume(&volumes[i]);
442                            if (code) {
443                               ErrorLog(0, 0, code, 0, 
444                                        "Warning: Can't add volume %s %u to backup database\n",
445                                        volumes[i].name, volumes[i].id);
446                            }
447                         }
448                      }
449                   }
450                   break;
451
452               default:
453                   ErrorLog(0, 0, 0, 0,
454                            "Warning: dbWatcher: Unrecognized entry type %d\n",
455                            entryPtr->dlq_type);
456                   break;                  /* ignore */
457           }
458
459           if (entryPtr) {
460              if (entryPtr->dlq_structPtr)
461                 free(entryPtr->dlq_structPtr);
462              free(entryPtr);
463           }
464           entryPtr = (dlqlinkP)0;
465           dumpPtr  = (budb_dumpEntry   *)0;
466           volPtr   = (budb_volumeEntry *)0;
467           tapePtr  = (budb_tapeEntry   *)0;
468       } /*while*/
469       
470       dbWatcherinprogress = 0;
471 #ifdef AFS_PTHREAD_ENV
472       sleep(2);
473 #else
474       IOMGR_Sleep(2);
475 #endif
476   }
477 }