butc: convert butc/dump.c to safer string handling
[openafs.git] / src / butc / dump.c
index 5364949..1f4eb9b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 #include <afsconfig.h>
 #include <afs/param.h>
 
-#include <sys/types.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#else
-#include <sys/time.h>
-#include <sys/file.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
+#include <roken.h>
+
 #include <rx/xdr.h>
 #include <rx/rx.h>
 #include <lwp.h>
 #include <lock.h>
-#include <errno.h>
 #include <afs/tcdata.h>
 #include <afs/bubasics.h>
 #include <afs/budb_client.h>
@@ -37,6 +23,7 @@
 #include <afs/vldbint.h>
 #include <afs/ktime.h>
 #include <afs/vlserver.h>
+#include <afs/afsint.h>
 #include <afs/volser.h>
 #include <afs/volser_prototypes.h>
 #include <afs/volint.h>
@@ -88,27 +75,12 @@ afs_int32 tapeblocks;               /* Number of 16K tape datablocks in buffer (!CONF_XBSA) *
  * 6) Ensure bucoord status calls work
  *
  * notes
- * pass 3: 
+ * pass 3:
  *     keep token timeout. If no user reponse (idle time > some period)
  *     and tokens about to time out, terminate dump. This provides at
  *     least something usable.
  */
 
-#define DUMPNAME(dumpname, name, dbDumpId) \
-   if (dbDumpId == 0) \
-     sprintf(dumpname, "%s", name); \
-   else \
-     sprintf(dumpname, "%s (DumpId %u)", name, dbDumpId);
-
-#if defined(AFS_NT40_ENV) || defined(AFS_SUN4_ENV)
-int
-localtime_r(time_t * t, struct tm *tm)
-{
-    memcpy(tm, localtime(t), sizeof(struct tm));
-    return 0;
-}
-#endif
-
 struct dumpRock {
     /* status only */
     int tapeSeq;
@@ -167,11 +139,9 @@ calcExpirationDate(afs_int32 expType, afs_int32 expDate, afs_int32 createTime)
         */
        Int32To_ktimeRelDate(expDate, &kd);
        return (Add_RelDate_to_Time(&kd, createTime));
-       break;
 
     case BC_ABS_EXPDATE:
        return (expDate);
-       break;
 
     case BC_NO_EXPDATE:
     default:
@@ -206,10 +176,10 @@ Bind(afs_uint32 server)
 /* notes
  * 1) save the chunksize or otherwise ensure tape space remaining is
  *     check frequently enough
- * 2) This is called once. For partial dumps, need to 
+ * 2) This is called once. For partial dumps, need to
  *     ensure that the tape device is left in the correct state for
  *     further dumps.
- * 
+ *
  */
 #define BIGCHUNK 102400
 
@@ -284,7 +254,7 @@ dumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     buffer = bufferBlock + BUTM_HDRSIZE;
 
     /* Dump one volume fragment at a time until we dump the full volume.
-     * A volume with more than 1 fragment means the volume will 'span' 
+     * A volume with more than 1 fragment means the volume will 'span'
      * 2 or more tapes.
      */
     for (fragmentNumber = 1; !endofvolume; fragmentNumber++) { /*frag */
@@ -321,8 +291,6 @@ dumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
        chunkSize = 0;
        fragmentvolume = 0;
        while (!endofvolume && !fragmentvolume) {       /*w */
-           bytesread = 0;
-
            /* Check for abort in the middle of writing data */
            if (volBytesRead >= chunkSize) {
                chunkSize += BIGCHUNK;
@@ -338,11 +306,11 @@ dumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
            /* Determine how much data to read in upcoming RX_Read() call */
            toread = dataSize;
            /* Check if we are close to the EOT. There should at least be some
-            * data on the tape before it is switched. HACK: we have to split a 
-            * volume across tapes because the volume trailer says the dump 
-            * continues on the next tape (and not the filemark). This could 
-            * result in a volume starting on one tape (no volume data dumped) and 
-            * continued on the next tape. It'll work, just requires restore to 
+            * data on the tape before it is switched. HACK: we have to split a
+            * volume across tapes because the volume trailer says the dump
+            * continues on the next tape (and not the filemark). This could
+            * result in a volume starting on one tape (no volume data dumped) and
+            * continued on the next tape. It'll work, just requires restore to
             * switch tapes. This allows many small volumes (<16K) to be dumped.
             */
            kRemaining = butm_remainingKSpace(tapeInfoPtr);
@@ -482,7 +450,7 @@ dumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     dparamsPtr->curVolumeStatus = DUMP_SUCCESS;
 
   error_exit:
-    /* 
+    /*
      * If we hit the end, see if this is the first volume on the tape or not.
      * Also, mark the tape as finished if the tape contains other dumps.
      */
@@ -505,7 +473,7 @@ dumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
        }
     }
 
-    /* 
+    /*
      * This is used when an error occurs part way into a volume dump. Clean
      * the tape state by writing an FileEnd mark. Forgo this action if we hit
      * the end of tape.
@@ -564,7 +532,6 @@ xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     afs_uint32 statuscount = statusSize, tsize = 0, esize;
     afs_hyper_t estSize;
 
-    char dumpIdStr[XBSA_MAX_OSNAME];
     char volumeNameStr[XBSA_MAX_PATHNAME];
     static char *dumpDescription = "AFS volume dump";
     static char *objectDescription = "XBSA - butc";
@@ -624,14 +591,12 @@ xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     dparamsPtr->curVolStartPos = tapeInfoPtr->position;
 
     /* Tell XBSA what the name and size of volume to write */
-    strcpy(dumpIdStr, butcdumpIdStr);  /* "backup_afs_volume_dumps" */
-    sprintf(volumeNameStr, "/%d", dparamsPtr->databaseDumpId);
-    strcat(volumeNameStr, "/");
-    strcat(volumeNameStr, curDump->name);      /* <dumpid>/<volname> */
+    snprintf(volumeNameStr, sizeof(volumeNameStr), "/%d/%s",
+            dparamsPtr->databaseDumpId, curDump->name);
     hset32(estSize, esize);
     hshlft(estSize, 10);       /* Multiply by 1024 so its in KB */
 
-    rc = xbsa_WriteObjectBegin(&butxInfo, dumpIdStr, volumeNameStr,
+    rc = xbsa_WriteObjectBegin(&butxInfo, butcdumpIdStr, volumeNameStr,
                               xbsalGName, estSize, dumpDescription,
                               objectDescription);
     if (rc != XBSA_SUCCESS) {
@@ -646,7 +611,7 @@ xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     hostVolumeHeader.contd = 0;
     volumeHeader_hton(&hostVolumeHeader, (struct volumeHeader *)buffer);
 
-    rc = xbsa_WriteObjectData(&butxInfo, (struct volumeHeader *)buffer,
+    rc = xbsa_WriteObjectData(&butxInfo, buffer,
                              sizeof(struct volumeHeader), &bytesWritten);
     if (rc != XBSA_SUCCESS) {
        ErrorLog(1, taskId, rc, 0,
@@ -659,7 +624,7 @@ xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     bytesWritten = sizeof(struct volumeHeader);
     if (bytesWritten != sizeof(struct volumeHeader)) {
        ErrorLog(1, taskId, rc, 0,
-                "The size of VolumeHeader written (%d) does not equal its actual size (%d)\n",
+                "The size of VolumeHeader written (%d) does not equal its actual size (%" AFS_SIZET_FMT ")\n",
                 bytesWritten, sizeof(struct volumeHeader));
        ERROR_EXIT(TC_INTERNALERROR);
     }
@@ -673,8 +638,6 @@ xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
     volBytesRead = 0;
     chunkSize = 0;
     while (!endofvolume) {     /*w */
-       bytesread = 0;
-
        /* Check for abort in the middle of writing data */
        if (volBytesRead >= chunkSize) {
            chunkSize += BIGCHUNK;
@@ -708,11 +671,11 @@ xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr)
            hostVolumeHeader.contd = 0;
            hostVolumeHeader.magic = TC_VOLENDMAGIC;
            hostVolumeHeader.endTime = time(0);
-           volumeHeader_hton(&hostVolumeHeader, &buffer[bytesread]);
+           volumeHeader_hton(&hostVolumeHeader, (struct volumeHeader *)&buffer[bytesread]);
            bytesread += sizeof(hostVolumeHeader);
 
            /* End the dump and transaction with the volserver. We end it now, before
-            * we make the XBSA call because if XBSA blocks, we could time out on the 
+            * we make the XBSA call because if XBSA blocks, we could time out on the
             * volserver (After last read, the transaction with the volserver is idle).
             */
            rc = rx_EndCall(fromcall, 0);
@@ -897,7 +860,7 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
 
            switch (curDump->vtype) {
            case BACKVOL:
-               if (!(vldbEntry.flags & BACK_EXISTS)) {
+               if (!(vldbEntry.flags & VLF_BACKEXISTS)) {
                    ErrorLog(0, taskId, 0, 0,
                             "Volume %s (%u) failed - Backup volume no longer exists\n",
                             curDump->name, curDump->vid);
@@ -909,7 +872,7 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
 
            case RWVOL:
                for (e = 0; e < vldbEntry.nServers; e++) {      /* Find the RW volume */
-                   if (vldbEntry.serverFlags[e] & ITSRWVOL)
+                   if (vldbEntry.serverFlags[e] & VLSF_RWVOL)
                        break;
                }
                break;
@@ -927,7 +890,7 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
 
                if (e >= vldbEntry.nServers) {  /* Didn't find RO volume */
                    for (e = 0; e < vldbEntry.nServers; e++) {  /* Find the first RO volume */
-                       if (vldbEntry.serverFlags[e] & ITSROVOL)
+                       if (vldbEntry.serverFlags[e] & VLSF_ROVOL)
                            break;
                    }
                }
@@ -939,7 +902,6 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
                         curDump->name, curDump->vid);
                curDump->hostAddr = 0;
                continue;
-               break;
            }
 
            if (e >= vldbEntry.nServers) {
@@ -978,8 +940,8 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
        if (checkAbortByTaskId(taskId))
            ERROR_EXIT(TC_ABORTEDBYREQUEST);
 
-       /* Establish connection to volume - UV_ routine expects 
-        * host address in network order 
+       /* Establish connection to volume - UV_ routine expects
+        * host address in network order
         */
        if (CONF_XBSA) {
            dvcode = xbsaDumpVolume(curDump, dparamsPtr);
@@ -1031,7 +993,6 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
                case 'r':       /* retry */
                    dparamsPtr->curVolume--;    /* redump this volume */
                    continue;
-                   break;
                case 'o':       /* omit */
                    ErrorLog(1, taskId, 0, 0, "Volume %s (%u) omitted\n",
                             curDump->name, curDump->vid);
@@ -1063,7 +1024,6 @@ dumpPass(struct dumpRock * dparamsPtr, int passNumber)
 
            dparamsPtr->curVolume--;    /* redump this volume */
            continue;
-           break;
 
        case DUMP_NORETRYEOT:
            ErrorLog(1, taskId, 0, 0,
@@ -1146,9 +1106,9 @@ Dumper(void *param)
     int dumpedvolumes = 0;
     int nodumpvolumes = 0;
     char strlevel[5];
-    char msg[20];
-    char finishedMsg1[50];
-    char finishedMsg2[50];
+    char msg[128];
+    char finishedMsg1[128];
+    char finishedMsg2[128];
     time_t startTime = 0;
     time_t endTime = 0;
     afs_int32 allocbufferSize;
@@ -1156,6 +1116,7 @@ Dumper(void *param)
     extern struct deviceSyncNode *deviceLatch;
     extern struct tapeConfig globalTapeConfig;
 
+    afs_pthread_setname_self("dumper");
     taskId = nodePtr->taskID;  /* Get task Id */
     setStatus(taskId, DRIVE_WAIT);
     EnterDeviceQueue(deviceLatch);
@@ -1216,7 +1177,7 @@ Dumper(void *param)
      * Used when requesting a tape. Done now because once we create the dump, the
      * routine will then find the newly created dump.
      */
-    sprintf(strlevel, "%d", nodePtr->level);
+    snprintf(strlevel, sizeof(strlevel), "%d", nodePtr->level);
     code =
        bcdb_FindLatestDump(nodePtr->volumeSetName, strlevel,
                            &dparams.lastDump);
@@ -1272,7 +1233,7 @@ Dumper(void *param)
            break;
     }
 
-    /* 
+    /*
      * Log the error but ignore it since the dump is effectively done.
      * Scantape may assume another volume and ask for next tape.
      */
@@ -1321,15 +1282,21 @@ Dumper(void *param)
 
     lastPass = 1;              /* In case we aborted */
 
-    DUMPNAME(finishedMsg1, nodePtr->dumpSetName, dparams.databaseDumpId);
-    sprintf(finishedMsg2, "%d volumes dumped", dumpedvolumes);
+    /* Format and log finished message. */
+    snprintf(finishedMsg1, sizeof(finishedMsg1), "%s", nodePtr->dumpSetName);
+    if (dparams.databaseDumpId != 0) {
+       snprintf(msg, sizeof(msg), " (DumpId %u)", dparams.databaseDumpId);
+       strlcat(finishedMsg1, msg, sizeof(finishedMsg1));
+    }
+    snprintf(finishedMsg2, sizeof(finishedMsg2),
+            "%d volumes dumped", dumpedvolumes);
     if (failedvolumes) {
-       sprintf(msg, ", %d failed", failedvolumes);
-       strcat(finishedMsg2, msg);
+       snprintf(msg, sizeof(msg), ", %d failed", failedvolumes);
+       strlcat(finishedMsg2, msg, sizeof(finishedMsg2));
     }
     if (nodumpvolumes) {
-       sprintf(msg, ", %d unchanged", nodumpvolumes);
-       strcat(finishedMsg2, msg);
+       snprintf(msg, sizeof(msg), ", %d unchanged", nodumpvolumes);
+       strlcat(finishedMsg2, msg, sizeof(finishedMsg2));
     }
 
     if (code == TC_ABORTEDBYREQUEST) {
@@ -1350,7 +1317,7 @@ Dumper(void *param)
     if (centralLogIO && startTime) {
        long timediff;
        afs_int32 hrs, min, sec, tmp;
-       char line[1024];
+       char *line = NULL;
        struct tm tmstart, tmend;
 
        localtime_r(&startTime, &tmstart);
@@ -1361,7 +1328,7 @@ Dumper(void *param)
        min = tmp / 60;
        sec = tmp % 60;
 
-       sprintf(line,
+       code = asprintf(&line,
                "%-5d  %02d/%02d/%04d %02d:%02d:%02d  "
                "%02d/%02d/%04d %02d:%02d:%02d  " "%02d:%02d:%02d  "
                "%s %d of %d volumes dumped (%lu KB)\n", taskId,
@@ -1372,9 +1339,13 @@ Dumper(void *param)
                nodePtr->volumeSetName, dumpedvolumes,
                dumpedvolumes + failedvolumes,
                afs_printable_uint32_lu(dparams.tapeInfoPtr->kBytes + 1));
-
-       fwrite(line, strlen(line), 1, centralLogIO);
-       fflush(centralLogIO);
+       if (code < 0)
+           line = NULL;
+       if (line != NULL) {
+           fwrite(line, strlen(line), 1, centralLogIO);
+           fflush(centralLogIO);
+       }
+       free(line);
     }
 
     setStatus(taskId, TASK_DONE);
@@ -1392,7 +1363,7 @@ Dumper(void *param)
  *     volume parameters describe the volume that failed
  * entry:
  *     volumeName - name of volume
- *     volumeId - volume id 
+ *     volumeId - volume id
  *     taskId - for job contrl
  * fn return:
  *     character typed by user, one of r, o or a
@@ -1422,11 +1393,7 @@ retryPrompt(char *volumeName, afs_int32 volumeId, afs_uint32 taskId)
 
        start = time(0);
        while (1) {
-#ifdef AFS_PTHREAD_ENV
-           code = GetResponseKey(5, &ch);      /* ch stores key pressed */
-#else
            code = LWP_GetResponseKey(5, &ch);  /* ch stores key pressed */
-#endif
            if (code == 1)
                break;          /* input is available */
 
@@ -1728,7 +1695,7 @@ getDumpTape(struct dumpRock *dparamsPtr, int interactiveFlag,
                        code = bcdb_FindDumpByID(dmp, &de);
                        if (code)
                            break;
-                       sprintf(strlevel, "%d", de.level);
+                       snprintf(strlevel, sizeof(strlevel), "%d", de.level);
                        code =
                            bcdb_FindLatestDump(de.volumeSetName, strlevel,
                                                &de2);
@@ -1754,7 +1721,7 @@ getDumpTape(struct dumpRock *dparamsPtr, int interactiveFlag,
 
        /*
         * Now have the right tape. Create a new label for the tape
-        * Appended labels have the dump's dumpId - labels at beginnings of 
+        * Appended labels have the dump's dumpId - labels at beginnings of
         *     tape have the initial dump's dumpId.
         * Appended labels do not increment the useCount.
         * Labels at beginnings of tape use the most future expiration of the dump set.
@@ -1884,7 +1851,7 @@ makeVolumeHeader(struct volumeHeader *vhptr, struct dumpRock *dparamsPtr,
     strcpy(vhptr->dumpSetName, nodePtr->dumpSetName);
     strcpy(vhptr->preamble, "H++NAME#");
     strcpy(vhptr->postamble, "T--NAME#");
-  
+
     return (code);
 }
 
@@ -1893,6 +1860,8 @@ volumeHeader_hton(struct volumeHeader *hostPtr, struct volumeHeader *netPtr)
 {
     struct volumeHeader volHdr;
 
+    memset(&volHdr, 0, sizeof(volHdr));
+
     strcpy(volHdr.preamble, hostPtr->preamble);
     strcpy(volHdr.postamble, hostPtr->postamble);
     strcpy(volHdr.volumeName, hostPtr->volumeName);
@@ -2061,13 +2030,14 @@ DeleteDump(void *param)
     extern struct udbHandleS udbHandle;
     extern struct deviceSyncNode *deviceLatch;
 
+    dumpid = ptr->dumpID;
+    taskId = ptr->taskId;      /* Get task Id */
+
+    afs_pthread_setname_self("deletedump");
     setStatus(taskId, DRIVE_WAIT);
     EnterDeviceQueue(deviceLatch);
     clearStatus(taskId, DRIVE_WAIT);
 
-    dumpid = ptr->dumpID;
-    taskId = ptr->taskId;      /* Get task Id */
-
     printf("\n\n");
     TapeLog(2, taskId, 0, 0, "Delete Dump %u\n", dumpid);
 
@@ -2159,15 +2129,14 @@ DeleteDump(void *param)
        for (i = 0; i < vl.budb_volumeList_len; i++) {
            if (dumpEntry.flags & BUDB_DUMP_BUTA) {
                /* dump was from buta, use old buta style names */
-               sprintf(dumpIdStr, "/%d", dumpid);
-               strcpy(volumeNameStr, "/");
-               strcat(volumeNameStr, (char *)vl.budb_volumeList_val[i].name);
+               snprintf(dumpIdStr, sizeof(dumpIdStr), "/%d", dumpid);
+               snprintf(volumeNameStr, sizeof(volumeNameStr), "/%s",
+                        (char *)vl.budb_volumeList_val[i].name);
            } else {            /* BUDB_DUMP_ADSM */
                /* dump was from butc to ADSM, use butc names */
-               strcpy(dumpIdStr, butcdumpIdStr);
-               sprintf(volumeNameStr, "/%d", dumpid);
-               strcat(volumeNameStr, "/");
-               strcat(volumeNameStr, (char *)vl.budb_volumeList_val[i].name);
+               snprintf(dumpIdStr, sizeof(dumpIdStr), "%s", butcdumpIdStr);
+               snprintf(volumeNameStr, sizeof(volumeNameStr), "/%d/%s",
+                        dumpid, (char *)vl.budb_volumeList_val[i].name);
            }
 
            rc = xbsa_DeleteObject(&butxInfo, dumpIdStr, volumeNameStr);
@@ -2225,6 +2194,6 @@ DeleteDump(void *param)
        code = BUTX_DELETENOVOL;
        setStatus(taskId, TASK_ERROR);
     }
-    return (void *)(code);
+    return (void *)(uintptr_t)(code);
 }
 #endif