]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/bscan.c
For symmetry, add this file. At present, all it does is update the version table.
[bacula/bacula] / bacula / src / stored / bscan.c
index 9056f635f7419ee1f10730312dae77f507762469..d0d406c7a2582c4d230b636a2e8c854c91dc5344 100644 (file)
@@ -36,7 +36,7 @@
 
 /* Forward referenced functions */
 static void do_scan(void);
-static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
+static int record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
 static int  create_file_attributes_record(B_DB *db, JCR *mjcr, 
                               char *fname, char *lname, int type,
                               char *ap, DEV_RECORD *rec);
@@ -83,6 +83,7 @@ static time_t lasttime = 0;
 static char *db_name = "bacula";
 static char *db_user = "bacula";
 static char *db_password = "";
+static char *db_host = NULL;
 static char *wd = NULL;
 static int update_db = 0;
 static int update_vol_info = 0;
@@ -101,16 +102,17 @@ static void usage()
 "Usage: bscan [-d debug_level] <bacula-archive>\n"
 "       -b bootstrap      specify a bootstrap file\n"
 "       -c <file>         specify configuration file\n"
-"       -dnn              set debug level to nn\n"
+"       -d <nn>           set debug level to nn\n"
 "       -m                update media info in database\n"
-"       -n name           specify the database name (default bacula)\n"
-"       -u user           specify database user name (default bacula)\n"
-"       -p password       specify database password (default none)\n"
+"       -n <name>         specify the database name (default bacula)\n"
+"       -u <user>         specify database user name (default bacula)\n"
+"       -p <password      specify database password (default none)\n"
+"       -h <host>         specify database host (default NULL)\n"
 "       -r                list records\n"
 "       -s                synchronize or store in database\n"
 "       -v                verbose\n"
-"       -V              specify Volume names (separated by |)\n"
-"       -w dir            specify working directory (default from conf file)\n"
+"       -V <Volumes>      specify Volume names (separated by |)\n"
+"       -w <dir>          specify working directory (default from conf file)\n"
 "       -?                print this message\n\n"));
    exit(1);
 }
@@ -125,7 +127,7 @@ int main (int argc, char *argv[])
    init_msg(NULL, NULL);
 
 
-   while ((ch = getopt(argc, argv, "b:c:d:mn:p:rsu:vw:?")) != -1) {
+   while ((ch = getopt(argc, argv, "b:c:d:h:mn:p:rsu:vV:w:?")) != -1) {
       switch (ch) {
       case 'b':
         bsr = parse_bsr(NULL, optarg);
@@ -144,6 +146,10 @@ int main (int argc, char *argv[])
            debug_level = 1; 
         break;
 
+      case 'h':
+        db_host = optarg;
+        break;
+
       case 'm':
         update_vol_info = 1;
         break;
@@ -233,7 +239,7 @@ int main (int argc, char *argv[])
       exit(1);
    }
 
-   if ((db=db_init_database(NULL, db_name, db_user, db_password, NULL, 0, NULL)) == NULL) {
+   if ((db=db_init_database(NULL, db_name, db_user, db_password, db_host, 0, NULL)) == NULL) {
       Emsg0(M_ERROR_TERM, 0, _("Could not init Bacula database\n"));
    }
    if (!db_open_database(NULL, db)) {
@@ -250,6 +256,39 @@ int main (int argc, char *argv[])
    return 0;
 }
   
+/*  
+ * We are at the end of reading a tape. Now, we simulate handling
+ *   the end of writing a tape by wiffling through the attached
+ *   jcrs creating jobmedia records.
+ */
+static int bscan_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+{
+   Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+   for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+      if (verbose) {
+         Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
+      }
+      if (dev->state & ST_TAPE) {
+        mjcr->EndBlock = dev->EndBlock;
+        mjcr->EndFile = dev->EndFile;
+      } else {
+        mjcr->EndBlock = (uint32_t)dev->file_addr;
+        mjcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
+      }
+      if (!create_jobmedia_record(db, mjcr)) {
+         Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
+           dev->VolCatInfo.VolCatName, mjcr->Job);
+      }
+   }  
+   /* Now let common read routine get up next tape. Note,
+    * we call mount_next... with bscan's jcr because that is where we
+    * have the Volume list, but we get attached.
+    */
+   int stat = mount_next_read_volume(jcr, dev, block);
+   /* we must once more detach ourselves (attached by mount_next ...) */
+   detach_jcr_from_device(dev, jcr); /* detach bscan jcr */
+   return stat;
+}
 
 static void do_scan()            
 {
@@ -262,16 +301,17 @@ static void do_scan()
    memset(&fsr, 0, sizeof(fsr));
    memset(&fr, 0, sizeof(fr));
 
+   /* Detach bscan's jcr as we are not a real Job on the tape */
    detach_jcr_from_device(dev, bjcr);
 
-   read_records(bjcr, dev, record_cb, mount_next_read_volume);
+   read_records(bjcr, dev, record_cb, bscan_mount_next_read_volume);
    release_device(bjcr, dev);
 
    free_attr(attr);
    term_dev(dev);
 }
 
-static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
 {
    JCR *mjcr;
    char ec1[30];
@@ -297,13 +337,14 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       switch (rec->FileIndex) {
       case PRE_LABEL:
          Pmsg0(000, _("Volume is prelabeled. This tape cannot be scanned.\n"));
-        return;
+        return 1;
         break;
+
       case VOL_LABEL:
         unser_volume_label(dev, rec);
         /* Check Pool info */
-        strcpy(pr.Name, dev->VolHdr.PoolName);
-        strcpy(pr.PoolType, dev->VolHdr.PoolType);
+        bstrncpy(pr.Name, dev->VolHdr.PoolName, sizeof(pr.Name));
+        bstrncpy(pr.PoolType, dev->VolHdr.PoolType, sizeof(pr.PoolType));
         if (db_get_pool_record(bjcr, db, &pr)) {
            if (verbose) {
                Pmsg1(000, _("Pool record for %s found in DB.\n"), pr.Name);
@@ -318,14 +359,14 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) {
             Pmsg2(000, _("VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n"),
               pr.PoolType, dev->VolHdr.PoolType);
-           return;
+           return 1;
         } else if (verbose) {
             Pmsg1(000, _("Pool type \"%s\" is OK.\n"), pr.PoolType);
         }
 
         /* Check Media Info */
         memset(&mr, 0, sizeof(mr));
-        strcpy(mr.VolumeName, dev->VolHdr.VolName);
+        bstrncpy(mr.VolumeName, dev->VolHdr.VolName, sizeof(mr.VolumeName));
         mr.PoolId = pr.PoolId;
         if (db_get_media_record(bjcr, db, &mr)) {
            if (verbose) {
@@ -339,13 +380,13 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
                Pmsg1(000, _("VOL_LABEL: Media record not found for Volume: %s\n"),
                  mr.VolumeName);
            }
-           strcpy(mr.MediaType, dev->VolHdr.MediaType);
+           bstrncpy(mr.MediaType, dev->VolHdr.MediaType, sizeof(mr.MediaType));
            create_media_record(db, &mr, &dev->VolHdr);
         }
         if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) {
             Pmsg2(000, _("VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n"),
               mr.MediaType, dev->VolHdr.MediaType);
-           return;
+           return 1;
         } else if (verbose) {
             Pmsg1(000, _("Media type \"%s\" is OK.\n"), mr.MediaType);
         }
@@ -358,6 +399,7 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
 
          Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName);
         break;
+
       case SOS_LABEL:
         mr.VolJobs++;
         if (ignored_msgs > 0) {
@@ -382,7 +424,7 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
            }
         }
         /* Create Client record if not already there */
-           strcpy(cr.Name, label.ClientName);
+           bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name));
            create_client_record(db, &cr);
            jr.ClientId = cr.ClientId;
 
@@ -415,27 +457,28 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
             Pmsg3(000, _("SOS_LABEL: VolSessId mismatch for JobId=%u. DB=%d Vol=%d\n"),
               jr.JobId,
               jr.VolSessionId, rec->VolSessionId);
-           return;
+           return 1;
         }
         if (rec->VolSessionTime != jr.VolSessionTime) {
             Pmsg3(000, _("SOS_LABEL: VolSessTime mismatch for JobId=%u. DB=%d Vol=%d\n"),
               jr.JobId,
               jr.VolSessionTime, rec->VolSessionTime);
-           return;
+           return 1;
         }
         if (jr.PoolId != pr.PoolId) {
             Pmsg3(000, _("SOS_LABEL: PoolId mismatch for JobId=%u. DB=%d Vol=%d\n"),
               jr.JobId,
               jr.PoolId, pr.PoolId);
-           return;
+           return 1;
         }
         break;
+
       case EOS_LABEL:
         unser_session_label(&elabel, rec);
 
         /* Create FileSet record */
-        strcpy(fsr.FileSet, label.FileSetName);
-        strcpy(fsr.MD5, label.FileSetMD5);
+        bstrncpy(fsr.FileSet, label.FileSetName, sizeof(fsr.FileSet));
+        bstrncpy(fsr.MD5, label.FileSetMD5, sizeof(fsr.MD5));
         create_fileset_record(db, &fsr);
         jr.FileSetId = fsr.FileSetId;
 
@@ -458,8 +501,10 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         free_jcr(mjcr);
 
         break;
+
       case EOM_LABEL:
         break;
+
       case EOT_LABEL:             /* end of all tapes */
         /* 
          * Wiffle through all jobs still open and close
@@ -486,15 +531,28 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         mr.VolBytes += mr.VolBlocks * WRITE_BLKHDR_LENGTH; /* approx. */
         mr.VolMounts++;
         update_media_record(db, &mr);
-         Pmsg3(0, _("End of Volume. VolFiles=%u VolBlocks=%u VolBytes=%s\n"), mr.VolFiles,
+         Pmsg3(0, _("End of all Volumes. VolFiles=%u VolBlocks=%u VolBytes=%s\n"), mr.VolFiles,
                    mr.VolBlocks, edit_uint64_with_commas(mr.VolBytes, ec1));
         break;
       default:
         break;
       } /* end switch */
-      return;
+      return 1;
    }
 
+   mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+   if (!mjcr) {
+      if (mr.VolJobs > 0) {
+         Pmsg2(000, _("Could not find Job for SessId=%d SessTime=%d record.\n"),
+                     rec->VolSessionId, rec->VolSessionTime);
+      } else {
+        ignored_msgs++;
+      }
+      return 1;
+   }
+   if (mjcr->VolFirstIndex == 0) {
+      mjcr->VolFirstIndex = block->FirstIndex;
+   }
 
    /* File Attributes stream */
    switch (rec->Stream) {
@@ -511,23 +569,13 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       }
        
       if (verbose > 1) {
-        uint32_t LinkFI;
-        decode_stat(attr->attr, &attr->statp, &LinkFI);
+        decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
+        build_attr_output_fnames(bjcr, attr);
         print_ls_output(bjcr, attr);
       }
-      mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
-      if (!mjcr) {
-        if (mr.VolJobs > 0) {
-            Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
-                        rec->VolSessionId, rec->VolSessionTime);
-        } else {
-           ignored_msgs++;
-        }
-        return;
-      }
       fr.JobId = mjcr->JobId;
       fr.FileId = 0;
-      if (db_get_file_attributes_record(bjcr, db, attr->fname, &fr)) {
+      if (db_get_file_attributes_record(bjcr, db, attr->fname, NULL, &fr)) {
         if (verbose > 1) {
             Pmsg1(000, _("File record already exists for: %s\n"), attr->fname);
         }
@@ -542,16 +590,6 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
    case STREAM_WIN32_DATA:
    case STREAM_FILE_DATA:
    case STREAM_SPARSE_DATA:
-      mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
-      if (!mjcr) {
-        if (mr.VolJobs > 0) {
-            Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for File Data record.\n"),
-                        rec->VolSessionId, rec->VolSessionTime);
-        } else {
-           ignored_msgs++;
-        }
-        return;
-      }
       mjcr->JobBytes += rec->data_len;
       if (rec->Stream == STREAM_SPARSE_DATA) {
         mjcr->JobBytes -= sizeof(uint64_t);
@@ -561,47 +599,17 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       break;
 
    case STREAM_GZIP_DATA:
-      mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
-      if (!mjcr) {
-        if (mr.VolJobs > 0) {
-            Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for GZIP Data record.\n"),
-                        rec->VolSessionId, rec->VolSessionTime);
-        } else {
-           ignored_msgs++;
-        }
-        return;
-      }
       mjcr->JobBytes += rec->data_len; /* No correct, we should expand it */
       free_jcr(mjcr);                /* done using JCR */
       break;
 
    case STREAM_SPARSE_GZIP_DATA:
-      mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
-      if (!mjcr) {
-        if (mr.VolJobs > 0) {
-            Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Sparse GZIP Data record.\n"),
-                        rec->VolSessionId, rec->VolSessionTime);
-        } else {
-           ignored_msgs++;
-        }
-        return;
-      }
       mjcr->JobBytes += rec->data_len - sizeof(uint64_t); /* No correct, we should expand it */
       free_jcr(mjcr);                /* done using JCR */
       break;
 
    /* Win32 GZIP stream */
    case STREAM_WIN32_GZIP_DATA:
-      mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
-      if (!mjcr) {
-        if (mr.VolJobs > 0) {
-            Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Win32 GZIP Data record.\n"),
-                        rec->VolSessionId, rec->VolSessionTime);
-        } else {
-           ignored_msgs++;
-        }
-        return;
-      }
       mjcr->JobBytes += rec->data_len;
       free_jcr(mjcr);                /* done using JCR */
       break;
@@ -640,7 +648,7 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data);
       break;
    }
-   return;
+   return 1;
 }
 
 /*
@@ -712,7 +720,8 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
    struct date_time dt;
    struct tm tm;
 
-   strcpy(mr->VolStatus, "Full");
+   /* We mark Vols as Archive to keep them from being re-written */
+   bstrncpy(mr->VolStatus, "Archive", sizeof(mr->VolStatus));
    mr->VolRetention = 365 * 3600 * 24; /* 1 year */
    if (vl->VerNum >= 11) {
       mr->FirstWritten = btime_to_utime(vl->write_btime);
@@ -853,8 +862,8 @@ static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
    jr->Type = label->JobType;
    jr->Level = label->JobLevel;
    jr->JobStatus = JS_Created;
-   strcpy(jr->Name, label->JobName);
-   strcpy(jr->Job, label->Job);
+   bstrncpy(jr->Name, label->JobName, sizeof(jr->Name));
+   bstrncpy(jr->Job, label->Job, sizeof(jr->Job));
    if (label->VerNum >= 11) {
       jr->SchedTime = btime_to_unix(label->write_btime);
    } else {
@@ -1089,7 +1098,7 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
    jobjcr->JobType = jr->Type;
    jobjcr->JobLevel = jr->Level;
    jobjcr->JobStatus = jr->JobStatus;
-   strcpy(jobjcr->Job, jr->Job);
+   bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job));
    jobjcr->JobId = JobId;      /* this is JobId on tape */
    jobjcr->sched_time = jr->SchedTime;
    jobjcr->start_time = jr->StartTime;
@@ -1101,9 +1110,9 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
 }
 
 /* Dummies to replace askdir.c */
-int    dir_get_volume_info(JCR *jcr, int writing) { return 1;}
+int    dir_get_volume_info(JCR *jcr, enum get_vol_info_rw  writing) { return 1;}
 int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
+int    dir_update_volume_info(JCR *jcr, DEVICE *dev, int relabel) { return 1; }
 int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
 int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
 int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
@@ -1112,29 +1121,6 @@ int      dir_send_job_status(JCR *jcr) {return 1;}
 
 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
 {
-   /*  
-    * We are at the end of reading a tape. Now, we simulate handling
-    *  the end of writing a tape by wiffling through the attached
-    *  jcrs creating jobmedia records.
-    */
-   Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
-   for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
-      if (verbose) {
-         Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
-      }
-      if (dev->state & ST_TAPE) {
-        mjcr->EndBlock = dev->EndBlock;
-        mjcr->EndFile = dev->EndFile;
-      } else {
-        mjcr->EndBlock = (uint32_t)dev->file_addr;
-        mjcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
-      }
-      if (!create_jobmedia_record(db, mjcr)) {
-         Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
-           dev->VolCatInfo.VolCatName, mjcr->Job);
-      }
-   }
-
    fprintf(stderr, _("Mount Volume %s on device %s and press return when ready: "),
       jcr->VolumeName, dev_name(dev));
    getchar();