X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fbscan.c;h=8f1c1faec41b8e6dd0cd48d01473854cda8e269d;hb=2499795e233e43bd4eb4d99e0473b67e6c6b60d8;hp=9c7dc32211c9c42b420fafb96a9ed63f45866ba4;hpb=0285e4c97413489deb7a1073d8ed1d824c7b3824;p=bacula%2Fbacula diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 9c7dc32211..8f1c1faec4 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2001-2010 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ /* * * Program to scan a Bacula Volume and compare it with @@ -6,27 +33,6 @@ * * Kern E. Sibbald, December 2001 * - * - * Version $Id$ - */ -/* - Copyright (C) 2001-2005 Kern Sibbald - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. - */ #include "bacula.h" @@ -36,6 +42,7 @@ /* Dummy functions */ int generate_daemon_event(JCR *jcr, const char *event) { return 1; } +extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code); /* Forward referenced functions */ static void do_scan(void); @@ -53,15 +60,7 @@ static int create_client_record(B_DB *db, CLIENT_DBR *cr); static int create_fileset_record(B_DB *db, FILESET_DBR *fsr); static int create_jobmedia_record(B_DB *db, JCR *jcr); static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId); -static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type); - - -/* Global variables */ -#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) -int win32_client = 1; -#else -int win32_client = 0; -#endif +static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type); /* Local variables */ @@ -82,10 +81,12 @@ static ATTR *attr; static time_t lasttime = 0; +static const char *db_driver = "NULL"; static const char *db_name = "bacula"; static const char *db_user = "bacula"; static const char *db_password = ""; static const char *db_host = NULL; +static int db_port = 0; static const char *wd = NULL; static bool update_db = false; static bool update_vol_info = false; @@ -100,8 +101,9 @@ static int num_pools = 0; static int num_media = 0; static int num_files = 0; +static CONFIG *config; #define CONFIG_FILE "bacula-sd.conf" -char *configfile; +char *configfile = NULL; STORES *me = NULL; /* our Global resource */ bool forge_on = false; /* proceed inspite of I/O errors */ pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -111,17 +113,20 @@ pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER; static void usage() { fprintf(stderr, _( -"Copyright (C) 2001-2005 Kern Sibbald.\n" -"\nVersion: " VERSION " (" BDATE ")\n\n" +PROG_COPYRIGHT +"\nVersion: %s (%s)\n\n" "Usage: bscan [ options ] \n" " -b bootstrap specify a bootstrap file\n" " -c specify configuration file\n" -" -d set debug level to nn\n" +" -d set debug level to \n" +" -dt print timestamp in debug output\n" " -m update media info in database\n" +" -D specify the driver database name (default NULL)\n" " -n specify the database name (default bacula)\n" " -u specify database user name (default bacula)\n" -" -P specify database password (default none)\n" " -h specify database host (default NULL)\n" +" -t specify database port (default 0)\n" " -p proceed inspite of I/O errors\n" " -r list records\n" " -s synchronize or store in database\n" @@ -129,7 +134,7 @@ static void usage() " -v verbose\n" " -V specify Volume names (separated by |)\n" " -w specify working directory (default from conf file)\n" -" -? print this message\n\n")); +" -? print this message\n\n"), 2001, VERSION, BDATE); exit(1); } @@ -139,11 +144,18 @@ int main (int argc, char *argv[]) struct stat stat_buf; char *VolumeName = NULL; + setlocale(LC_ALL, ""); + bindtextdomain("bacula", LOCALEDIR); + textdomain("bacula"); + init_stack_dump(); + lmgr_init_thread(); + my_name_is(argc, argv, "bscan"); init_msg(NULL, NULL); + OSDependentInit(); - while ((ch = getopt(argc, argv, "b:c:d:h:mn:pP:rsSu:vV:w:?")) != -1) { + while ((ch = getopt(argc, argv, "b:c:d:D:h:p:mn:pP:rsSt:u:vV:w:?")) != -1) { switch (ch) { case 'S' : showProgress = true; @@ -159,15 +171,28 @@ int main (int argc, char *argv[]) configfile = bstrdup(optarg); break; + case 'D': + db_driver = optarg; + break; + case 'd': /* debug level */ - debug_level = atoi(optarg); - if (debug_level <= 0) - debug_level = 1; + if (*optarg == 't') { + dbg_timestamp = true; + } else { + debug_level = atoi(optarg); + if (debug_level <= 0) { + debug_level = 1; + } + } break; case 'h': db_host = optarg; break; + + case 't': + db_port = atoi(optarg); + break; case 'm': update_vol_info = true; @@ -227,7 +252,8 @@ int main (int argc, char *argv[]) configfile = bstrdup(CONFIG_FILE); } - parse_config(configfile); + config = new_config_parser(); + parse_sd_config(config, configfile, M_ERROR_TERM); LockRes(); me = (STORES *)GetNextRes(R_STORAGE, NULL); if (!me) { @@ -260,18 +286,18 @@ int main (int argc, char *argv[]) if (!bjcr) { exit(1); } - dev = bjcr->dcr->dev; + dev = bjcr->read_dcr->dev; if (showProgress) { char ed1[50]; struct stat sb; - fstat(dev->fd, &sb); + fstat(dev->fd(), &sb); currentVolumeSize = sb.st_size; - Pmsg1(000, _("First Volume Size = %sn"), + Pmsg1(000, _("First Volume Size = %s\n"), edit_uint64(currentVolumeSize, ed1)); } - if ((db=db_init_database(NULL, db_name, db_user, db_password, - db_host, 0, NULL, 0)) == NULL) { + if ((db=db_init(NULL, db_driver, db_name, db_user, db_password, + db_host, db_port, NULL, 0)) == NULL) { Emsg0(M_ERROR_TERM, 0, _("Could not init Bacula database\n")); } if (!db_open_database(NULL, db)) { @@ -283,12 +309,16 @@ int main (int argc, char *argv[]) } do_scan(); - printf("Records %sadded or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n", - update_db?"":"would have been ", - num_media, num_pools, num_jobs, num_files); + if (update_db) { + printf("Records added or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n", + num_media, num_pools, num_jobs, num_files); + } else { + printf("Records would have been added or updated in the catalog:\n%7d Media\n%7d Pool\n%7d Job\n%7d File\n", + num_media, num_pools, num_jobs, num_files); + } free_jcr(bjcr); - term_dev(dev); + dev->term(); return 0; } @@ -301,27 +331,30 @@ static bool bscan_mount_next_read_volume(DCR *dcr) { DEVICE *dev = dcr->dev; DCR *mdcr; - Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName); + Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->getVolCatName()); foreach_dlist(mdcr, dev->attached_dcrs) { JCR *mjcr = mdcr->jcr; + Dmsg1(000, "========== JobId=%u ========\n", mjcr->JobId); if (mjcr->JobId == 0) { continue; } if (verbose) { Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job); } - if (dev->is_tape()) { - mdcr->EndBlock = dcr->EndBlock; - mdcr->EndFile = dcr->EndFile; -// } else { -// mdcr->EndBlock = (uint32_t)dcr->file_addr; -// mdcr->EndFile = (uint32_t)(dcr->file_addr >> 32); - } + mdcr->StartBlock = dcr->StartBlock; + mdcr->StartFile = dcr->StartFile; + mdcr->EndBlock = dcr->EndBlock; + mdcr->EndFile = dcr->EndFile; + mdcr->VolMediaId = dcr->VolMediaId; + mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex; if (!create_jobmedia_record(db, mjcr)) { Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"), - dev->VolCatInfo.VolCatName, mjcr->Job); + dev->getVolCatName(), mjcr->Job); } } + + update_media_record(db, &mr); + /* 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. @@ -331,9 +364,9 @@ static bool bscan_mount_next_read_volume(DCR *dcr) if (showProgress) { char ed1[50]; struct stat sb; - fstat(dev->fd, &sb); + fstat(dev->fd(), &sb); currentVolumeSize = sb.st_size; - Pmsg1(000, _("First Volume Size = %sn"), + Pmsg1(000, _("First Volume Size = %s\n"), edit_uint64(currentVolumeSize, ed1)); } return stat; @@ -341,7 +374,7 @@ static bool bscan_mount_next_read_volume(DCR *dcr) static void do_scan() { - attr = new_attr(); + attr = new_attr(bjcr); memset(&ar, 0, sizeof(ar)); memset(&pr, 0, sizeof(pr)); @@ -352,8 +385,11 @@ static void do_scan() /* Detach bscan's jcr as we are not a real Job on the tape */ - read_records(bjcr->dcr, record_cb, bscan_mount_next_read_volume); + read_records(bjcr->read_dcr, record_cb, bscan_mount_next_read_volume); + if (update_db) { + db_write_batch_file_records(bjcr); /* used by bulk batch file insert */ + } free_attr(attr); } @@ -368,13 +404,14 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) DEVICE *dev = dcr->dev; JCR *bjcr = dcr->jcr; DEV_BLOCK *block = dcr->block; + char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)]; if (rec->data_len > 0) { mr.VolBytes += rec->data_len + WRITE_RECHDR_LENGTH; /* Accumulate Volume bytes */ - if (showProgress) { + if (showProgress && currentVolumeSize > 0) { int pct = (mr.VolBytes * 100) / currentVolumeSize; if (pct != last_pct) { - fprintf(stdout, "done: %d%%\n", pct); + fprintf(stdout, _("done: %d%%\n"), pct); fflush(stdout); last_pct = pct; } @@ -429,7 +466,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) /* Check Media Info */ memset(&mr, 0, sizeof(mr)); - bstrncpy(mr.VolumeName, dev->VolHdr.VolName, sizeof(mr.VolumeName)); + bstrncpy(mr.VolumeName, dev->VolHdr.VolumeName, sizeof(mr.VolumeName)); mr.PoolId = pr.PoolId; num_media++; if (db_get_media_record(bjcr, db, &mr)) { @@ -459,6 +496,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) dcr->VolFirstIndex = dcr->FileIndex = 0; dcr->StartBlock = dcr->EndBlock = 0; dcr->StartFile = dcr->EndFile = 0; + dcr->VolMediaId = 0; } Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName); @@ -489,30 +527,18 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) } } /* Create Client record if not already there */ - bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name)); - create_client_record(db, &cr); - jr.ClientId = cr.ClientId; + bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name)); + create_client_record(db, &cr); + jr.ClientId = cr.ClientId; /* process label, if Job record exists don't update db */ mjcr = create_job_record(db, &jr, &label, rec); - dcr = mjcr->dcr; + dcr = mjcr->read_dcr; update_db = save_update_db; jr.PoolId = pr.PoolId; - /* Set start positions into JCR */ - if (dev->is_tape()) { - /* - * Note, we have already advanced past current block, - * so the correct number is block_num - 1 - */ - dcr->StartBlock = dev->block_num - 1; - dcr->StartFile = dev->file; - } else { - dcr->StartBlock = (uint32_t)dev->file_addr; - dcr->StartFile = (uint32_t)(dev->file_addr >> 32); - } mjcr->start_time = jr.StartTime; - mjcr->JobLevel = jr.JobLevel; + mjcr->set_JobLevel(jr.JobLevel); mjcr->client_name = get_pool_memory(PM_FNAME); pm_strcpy(mjcr->client_name, label.ClientName); @@ -564,8 +590,9 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) mjcr->JobStatus = JS_Terminated; /* Create JobMedia record */ + mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex; create_jobmedia_record(db, mjcr); - dev->attached_dcrs->remove(mjcr->dcr); + free_dcr(mjcr->read_dcr); free_jcr(mjcr); break; @@ -597,7 +624,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) if (!db_update_job_end_record(bjcr, db, &jr)) { Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db)); } - mjcr->dcr = NULL; + mjcr->read_dcr = NULL; free_jcr(mjcr); } } @@ -625,7 +652,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) } return true; } - dcr = mjcr->dcr; + dcr = mjcr->read_dcr; if (dcr->VolFirstIndex == 0) { dcr->VolFirstIndex = block->FirstIndex; } @@ -635,15 +662,10 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) case STREAM_UNIX_ATTRIBUTES: case STREAM_UNIX_ATTRIBUTES_EX: - if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, attr)) { + if (!unpack_attributes_record(bjcr, rec->Stream, rec->data, rec->data_len, attr)) { Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n")); } - if (attr->file_index != rec->FileIndex) { - Emsg2(M_ERROR_TERM, 0, _("Record header file index %ld not equal record index %ld\n"), - rec->FileIndex, attr->file_index); - } - if (verbose > 1) { decode_stat(attr->attr, &attr->statp, &attr->LinkFI); build_attr_output_fnames(bjcr, attr); @@ -665,10 +687,22 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) free_jcr(mjcr); break; + case STREAM_RESTORE_OBJECT: + /* ****FIXME*****/ + /* Implement putting into catalog */ + break; + /* Data stream */ case STREAM_WIN32_DATA: case STREAM_FILE_DATA: case STREAM_SPARSE_DATA: + case STREAM_ENCRYPTED_FILE_DATA: + case STREAM_ENCRYPTED_WIN32_DATA: + case STREAM_ENCRYPTED_MACOS_FORK_DATA: + /* + * For encrypted stream, this is an approximation. + * The data must be decrypted to know the correct length. + */ mjcr->JobBytes += rec->data_len; if (rec->Stream == STREAM_SPARSE_DATA) { mjcr->JobBytes -= sizeof(uint64_t); @@ -678,8 +712,13 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) break; case STREAM_GZIP_DATA: - mjcr->JobBytes += rec->data_len; /* No correct, we should expand it */ - free_jcr(mjcr); /* done using JCR */ + case STREAM_ENCRYPTED_FILE_GZIP_DATA: + case STREAM_ENCRYPTED_WIN32_GZIP_DATA: + /* No correct, we should (decrypt and) expand it + done using JCR + */ + mjcr->JobBytes += rec->data_len; + free_jcr(mjcr); break; case STREAM_SPARSE_GZIP_DATA: @@ -693,24 +732,51 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) free_jcr(mjcr); /* done using JCR */ break; - case STREAM_MD5_SIGNATURE: - char MD5buf[50]; - bin_to_base64(MD5buf, (char *)rec->data, 16); /* encode 16 bytes */ + case STREAM_MD5_DIGEST: + bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_MD5_SIZE, true); + if (verbose > 1) { + Pmsg1(000, _("Got MD5 record: %s\n"), digest); + } + update_digest_record(db, digest, rec, CRYPTO_DIGEST_MD5); + break; + + case STREAM_SHA1_DIGEST: + bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA1_SIZE, true); if (verbose > 1) { - Pmsg1(000, _("Got MD5 record: %s\n"), MD5buf); + Pmsg1(000, _("Got SHA1 record: %s\n"), digest); } - update_SIG_record(db, MD5buf, rec, MD5_SIG); + update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA1); break; - case STREAM_SHA1_SIGNATURE: - char SIGbuf[50]; - bin_to_base64(SIGbuf, (char *)rec->data, 20); /* encode 20 bytes */ + case STREAM_SHA256_DIGEST: + bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA256_SIZE, true); if (verbose > 1) { - Pmsg1(000, _("Got SHA1 record: %s\n"), SIGbuf); + Pmsg1(000, _("Got SHA256 record: %s\n"), digest); } - update_SIG_record(db, SIGbuf, rec, SHA1_SIG); + update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA256); break; + case STREAM_SHA512_DIGEST: + bin_to_base64(digest, sizeof(digest), (char *)rec->data, CRYPTO_DIGEST_SHA512_SIZE, true); + if (verbose > 1) { + Pmsg1(000, _("Got SHA512 record: %s\n"), digest); + } + update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA512); + break; + + case STREAM_ENCRYPTED_SESSION_DATA: + // TODO landonf: Investigate crypto support in bscan + if (verbose > 1) { + Pmsg0(000, _("Got signed digest record\n")); + } + break; + + case STREAM_SIGNED_DIGEST: + // TODO landonf: Investigate crypto support in bscan + if (verbose > 1) { + Pmsg0(000, _("Got signed digest record\n")); + } + break; case STREAM_PROGRAM_NAMES: if (verbose) { @@ -723,8 +789,38 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) Pmsg0(000, _("Got Prog Data Stream record.\n")); } break; + + case STREAM_UNIX_ACCESS_ACL: /* Deprecated Standard ACL attributes on UNIX */ + case STREAM_UNIX_DEFAULT_ACL: /* Deprecated Default ACL attributes on UNIX */ + case STREAM_ACL_AIX_TEXT: + case STREAM_ACL_DARWIN_ACCESS_ACL: + case STREAM_ACL_FREEBSD_DEFAULT_ACL: + case STREAM_ACL_FREEBSD_ACCESS_ACL: + case STREAM_ACL_HPUX_ACL_ENTRY: + case STREAM_ACL_IRIX_DEFAULT_ACL: + case STREAM_ACL_IRIX_ACCESS_ACL: + case STREAM_ACL_LINUX_DEFAULT_ACL: + case STREAM_ACL_LINUX_ACCESS_ACL: + case STREAM_ACL_TRU64_DEFAULT_ACL: + case STREAM_ACL_TRU64_DEFAULT_DIR_ACL: + case STREAM_ACL_TRU64_ACCESS_ACL: + case STREAM_ACL_SOLARIS_ACLENT: + case STREAM_ACL_SOLARIS_ACE: + /* Ignore Unix ACL attributes */ + break; + + case STREAM_XATTR_OPENBSD: + case STREAM_XATTR_SOLARIS_SYS: + case STREAM_XATTR_SOLARIS: + case STREAM_XATTR_DARWIN: + case STREAM_XATTR_FREEBSD: + case STREAM_XATTR_LINUX: + case STREAM_XATTR_NETBSD: + /* Ignore Unix Extended attributes */ + break; + default: - Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data); + Pmsg2(0, _("Unknown stream type!!! stream=%d len=%i\n"), rec->Stream, rec->data_len); break; } return true; @@ -737,7 +833,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) */ static void bscan_free_jcr(JCR *jcr) { - Dmsg0(200, "Start dird free_jcr\n"); + Dmsg0(200, "Start bscan free_jcr\n"); if (jcr->file_bsock) { Dmsg0(200, "Close File bsock\n"); @@ -754,7 +850,11 @@ static void bscan_free_jcr(JCR *jcr) free_dcr(jcr->dcr); jcr->dcr = NULL; } - Dmsg0(200, "End dird free_jcr\n"); + if (jcr->read_dcr) { + free_dcr(jcr->read_dcr); + jcr->read_dcr = NULL; + } + Dmsg0(200, "End bscan free_jcr\n"); } /* @@ -765,13 +865,17 @@ static int create_file_attributes_record(B_DB *db, JCR *mjcr, char *fname, char *lname, int type, char *ap, DEV_RECORD *rec) { - DCR *dcr = mjcr->dcr; + DCR *dcr = mjcr->read_dcr; ar.fname = fname; ar.link = lname; ar.ClientId = mjcr->ClientId; ar.JobId = mjcr->JobId; ar.Stream = rec->Stream; - ar.FileIndex = rec->FileIndex; + if (type == FT_DELETED) { + ar.FileIndex = 0; + } else { + ar.FileIndex = rec->FileIndex; + } ar.attr = ap; if (dcr->VolFirstIndex == 0) { dcr->VolFirstIndex = rec->FileIndex; @@ -806,7 +910,9 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) /* 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 */ + mr->Enabled = 1; if (vl->VerNum >= 11) { + mr->set_first_written = true; /* Save FirstWritten during update_media */ mr->FirstWritten = btime_to_utime(vl->write_btime); mr->LabelDate = btime_to_utime(vl->label_btime); } else { @@ -821,6 +927,12 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) mr->LabelDate = mktime(&tm); } lasttime = mr->LabelDate; + if (mr->VolJobs == 0) { + mr->VolJobs = 1; + } + if (mr->VolMounts == 0) { + mr->VolMounts = 1; + } if (!update_db) { return 1; @@ -889,7 +1001,16 @@ static int create_pool_record(B_DB *db, POOL_DBR *pr) */ static int create_client_record(B_DB *db, CLIENT_DBR *cr) { + /* + * Note, update_db can temporarily be set false while + * updating the database, so we must ensure that ClientId is non-zero. + */ if (!update_db) { + cr->ClientId = 0; + if (!db_get_client_record(bjcr, db, cr)) { + Pmsg1(0, _("Could not get Client record. ERR=%s\n"), db_strerror(db)); + return 0; + } return 1; } if (!db_create_client_record(bjcr, db, cr)) { @@ -1017,6 +1138,9 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, jr->JobStatus = elabel->JobStatus; mjcr->JobStatus = elabel->JobStatus; jr->JobFiles = elabel->JobFiles; + if (jr->JobFiles > 0) { /* If we found files, force PurgedFiles */ + jr->PurgedFiles = 0; + } jr->JobBytes = elabel->JobBytes; jr->VolSessionId = rec->VolSessionId; jr->VolSessionTime = rec->VolSessionTime; @@ -1034,8 +1158,8 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, return 0; } if (verbose) { - Pmsg2(000, _("Updated Job termination record for JobId=%u TermStat=%c\n"), jr->JobId, - jr->JobStatus); + Pmsg3(000, _("Updated Job termination record for JobId=%u Level=%s TermStat=%c\n"), + jr->JobId, job_level_to_str(mjcr->getJobLevel()), jr->JobStatus); } if (verbose > 1) { const char *term_msg; @@ -1047,6 +1171,9 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, case JS_Terminated: term_msg = _("Backup OK"); break; + case JS_Warnings: + term_msg = _("Backup OK -- with warnings"); + break; case JS_FatalError: case JS_ErrorTerminated: term_msg = _("*** Backup Error ***"); @@ -1079,7 +1206,7 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, mjcr->JobId, mjcr->Job, mjcr->fileset_name, - job_level_to_str(mjcr->JobLevel), + job_level_to_str(mjcr->getJobLevel()), mjcr->client_name, sdt, edt, @@ -1097,23 +1224,17 @@ static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel, static int create_jobmedia_record(B_DB *db, JCR *mjcr) { JOBMEDIA_DBR jmr; - DCR *dcr = mjcr->dcr; + DCR *dcr = mjcr->read_dcr; - if (dev->is_tape()) { - dcr->EndBlock = dev->EndBlock; - dcr->EndFile = dev->EndFile; -#ifdef needed - } else { - dcr->EndBlock = (uint32_t)dev->file_addr; - dcr->EndFile = (uint32_t)(dev->file_addr >> 32); -#endif - } + dcr->EndBlock = dev->EndBlock; + dcr->EndFile = dev->EndFile; + dcr->VolMediaId = dev->VolCatInfo.VolMediaId; memset(&jmr, 0, sizeof(jmr)); jmr.JobId = mjcr->JobId; jmr.MediaId = mr.MediaId; jmr.FirstIndex = dcr->VolFirstIndex; - jmr.LastIndex = dcr->FileIndex; + jmr.LastIndex = dcr->VolLastIndex; jmr.StartFile = dcr->StartFile; jmr.EndFile = dcr->EndFile; jmr.StartBlock = dcr->StartBlock; @@ -1138,7 +1259,7 @@ static int create_jobmedia_record(B_DB *db, JCR *mjcr) /* * Simulate the database call that updates the MD5/SHA1 record */ -static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type) +static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type) { JCR *mjcr; @@ -1158,7 +1279,7 @@ static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type) return 1; } - if (!db_add_SIG_to_file_record(bjcr, db, mjcr->FileId, SIGbuf, type)) { + if (!db_add_digest_to_file_record(bjcr, db, mjcr->FileId, digest, type)) { Pmsg1(0, _("Could not add MD5/SHA1 to File record. ERR=%s\n"), db_strerror(db)); free_jcr(mjcr); return 0; @@ -1182,8 +1303,8 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId) * the JobId and the ClientId. */ jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr); - jobjcr->JobType = jr->JobType; - jobjcr->JobLevel = jr->JobLevel; + jobjcr->set_JobType(jr->JobType); + jobjcr->set_JobLevel(jr->JobLevel); jobjcr->JobStatus = jr->JobStatus; bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job)); jobjcr->JobId = JobId; /* this is JobId on tape */ @@ -1192,32 +1313,37 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId) jobjcr->VolSessionId = rec->VolSessionId; jobjcr->VolSessionTime = rec->VolSessionTime; jobjcr->ClientId = jr->ClientId; - new_dcr(jobjcr, dev); + jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev); + return jobjcr; } /* Dummies to replace askdir.c */ -bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { return 1;} bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} -bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; } -bool dir_create_jobmedia_record(DCR *dcr) { return 1; } +bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } +bool dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; } bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} bool dir_send_job_status(JCR *jcr) {return 1;} int generate_job_event(JCR *jcr, const char *event) { return 1; } -bool python_set_prog(JCR*, char const*) { return false; } -bool dir_ask_sysop_to_mount_volume(DCR *dcr) +bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/) { DEVICE *dev = dcr->dev; Dmsg0(20, "Enter dir_ask_sysop_to_mount_volume\n"); /* Close device so user can use autochanger if desired */ - if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { - offline_dev(dev); - } - force_close_dev(dev); - fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ", + fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "), dcr->VolumeName, dev->print_name()); + dev->close(); getchar(); return true; } + +bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) +{ + Dmsg0(100, "Fake dir_get_volume_info\n"); + dcr->setVolCatName(dcr->VolumeName); + dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr); + Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts); + return 1; +}