/*
Bacula® - The Network Backup Solution
- Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2001-2014 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.
+ 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 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.
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
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.
*/
/*
*
*
* Kern E. Sibbald, December 2001
*
- *
- * Version $Id$
*/
#include "bacula.h"
#include "stored.h"
#include "findlib/find.h"
#include "cats/cats.h"
-
+#include "cats/sql_glue.h"
+
/* 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);
static CONFIG *config;
#define CONFIG_FILE "bacula-sd.conf"
+
+void *start_heap;
char *configfile = NULL;
STORES *me = NULL; /* our Global resource */
bool forge_on = false; /* proceed inspite of I/O errors */
" -v verbose\n"
" -V <Volumes> specify Volume names (separated by |)\n"
" -w <dir> specify working directory (default from conf file)\n"
-" -? print this message\n\n"), 2001, VERSION, BDATE);
+" -? print this message\n\n"),
+ 2001, VERSION, BDATE);
exit(1);
}
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:dD:h:p:mn:pP:rsSt:u: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;
case 'h':
db_host = optarg;
break;
-
+
case 't':
db_port = atoi(optarg);
break;
config = new_config_parser();
parse_sd_config(config, configfile, M_ERROR_TERM);
- LockRes();
- me = (STORES *)GetNextRes(R_STORAGE, NULL);
- if (!me) {
- UnlockRes();
- Emsg1(M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
- configfile);
- }
- UnlockRes();
+ setup_me();
+ load_sd_plugins(me->plugin_directory);
+
/* Check if -w option given, otherwise use resource for working directory */
if (wd) {
working_directory = wd;
working_directory);
}
- bjcr = setup_jcr("bscan", argv[0], bsr, VolumeName, 1); /* read device */
+ bjcr = setup_jcr("bscan", argv[0], bsr, VolumeName, SD_READ);
if (!bjcr) {
exit(1);
}
struct stat sb;
fstat(dev->fd(), &sb);
currentVolumeSize = sb.st_size;
- Pmsg1(000, _("First Volume Size = %s\n"),
+ Pmsg1(000, _("First Volume Size = %s\n"),
edit_uint64(currentVolumeSize, ed1));
}
- if ((db=db_init(NULL, db_driver, db_name, db_user, db_password,
- db_host, db_port, NULL, 0)) == NULL) {
+ if ((db = db_init_database(NULL, db_driver, db_name, db_user, db_password,
+ db_host, db_port, NULL, false, false)) == NULL) {
Emsg0(M_ERROR_TERM, 0, _("Could not init Bacula database\n"));
}
if (!db_open_database(NULL, db)) {
{
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);
+ Dmsg1(100, "========== JobId=%u ========\n", mjcr->JobId);
if (mjcr->JobId == 0) {
continue;
}
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);
+ if( mjcr->bscan_insert_jobmedia_records ) {
+ if (!create_jobmedia_record(db, mjcr)) {
+ Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
+ dev->getVolCatName(), mjcr->Job);
+ }
}
}
struct stat sb;
fstat(dev->fd(), &sb);
currentVolumeSize = sb.st_size;
- Pmsg1(000, _("First Volume Size = %s\n"),
+ Pmsg1(000, _("First Volume Size = %s\n"),
edit_uint64(currentVolumeSize, ed1));
}
return stat;
DEVICE *dev = dcr->dev;
JCR *bjcr = dcr->jcr;
DEV_BLOCK *block = dcr->block;
+ POOL_MEM sql_buffer;
+ db_int64_ctx jmr_count;
+
char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
if (rec->data_len > 0) {
bstrncpy(pr.Name, dev->VolHdr.PoolName, sizeof(pr.Name));
bstrncpy(pr.PoolType, dev->VolHdr.PoolType, sizeof(pr.PoolType));
num_pools++;
- if (db_get_pool_record(bjcr, db, &pr)) {
+ if (db_get_pool_numvols(bjcr, db, &pr)) {
if (verbose) {
Pmsg1(000, _("Pool record for %s found in DB.\n"), pr.Name);
}
jr.JobId);
}
}
+
/* 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);
jr.PoolId = pr.PoolId;
mjcr->start_time = jr.StartTime;
- mjcr->set_JobLevel(jr.JobLevel);
+ mjcr->setJobLevel(jr.JobLevel);
mjcr->client_name = get_pool_memory(PM_FNAME);
pm_strcpy(mjcr->client_name, label.ClientName);
bstrncpy(dcr->pool_type, label.PoolType, sizeof(dcr->pool_type));
bstrncpy(dcr->pool_name, label.PoolName, sizeof(dcr->pool_name));
+ /* Look for existing Job Media records for this job. If there are
+ any, no new ones need be created. This may occur if File
+ Retention has expired before Job Retention, or if the volume
+ has already been bscan'd */
+ Mmsg(sql_buffer, "SELECT count(*) from JobMedia where JobId=%d", jr.JobId);
+ db_sql_query(db, sql_buffer.c_str(), db_int64_handler, &jmr_count);
+ if( jmr_count.value > 0 ) {
+ //FIELD NAME TO BE DEFINED/CONFIRMED (maybe a struct?)
+ mjcr->bscan_insert_jobmedia_records = false;
+ } else {
+ mjcr->bscan_insert_jobmedia_records = true;
+ }
+
if (rec->VolSessionId != jr.VolSessionId) {
Pmsg3(000, _("SOS_LABEL: VolSessId mismatch for JobId=%u. DB=%d Vol=%d\n"),
jr.JobId,
/* Create JobMedia record */
mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
- create_jobmedia_record(db, mjcr);
- detach_dcr_from_dev(mjcr->read_dcr);
+ if( mjcr->bscan_insert_jobmedia_records ) {
+ create_jobmedia_record(db, mjcr);
+ }
+ free_dcr(mjcr->read_dcr);
free_jcr(mjcr);
break;
jr.VolSessionTime = mjcr->VolSessionTime;
jr.JobTDate = (utime_t)mjcr->start_time;
jr.ClientId = mjcr->ClientId;
- if (!db_update_job_end_record(bjcr, db, &jr, false)) {
+ if (!db_update_job_end_record(bjcr, db, &jr)) {
Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
}
mjcr->read_dcr = NULL;
}
/* File Attributes stream */
- switch (rec->Stream) {
+ switch (rec->maskedStream) {
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);
+ decode_stat(attr->attr, &attr->statp, sizeof(attr->statp), &attr->LinkFI);
build_attr_output_fnames(bjcr, attr);
print_ls_output(bjcr, attr);
}
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_MACOS_FORK_DATA:
case STREAM_ENCRYPTED_FILE_DATA:
case STREAM_ENCRYPTED_WIN32_DATA:
case STREAM_ENCRYPTED_MACOS_FORK_DATA:
* The data must be decrypted to know the correct length.
*/
mjcr->JobBytes += rec->data_len;
- if (rec->Stream == STREAM_SPARSE_DATA) {
+ if (rec->maskedStream == STREAM_SPARSE_DATA) {
mjcr->JobBytes -= sizeof(uint64_t);
}
break;
case STREAM_GZIP_DATA:
+ case STREAM_COMPRESSED_DATA:
case STREAM_ENCRYPTED_FILE_GZIP_DATA:
+ case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
- /* No correct, we should (decrypt and) expand it
- done using JCR
+ case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
+ /* No correct, we should (decrypt and) expand it
+ done using JCR
*/
mjcr->JobBytes += rec->data_len;
- free_jcr(mjcr);
+ free_jcr(mjcr);
break;
case STREAM_SPARSE_GZIP_DATA:
+ case STREAM_SPARSE_COMPRESSED_DATA:
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:
+ case STREAM_WIN32_COMPRESSED_DATA:
mjcr->JobBytes += rec->data_len;
free_jcr(mjcr); /* done using JCR */
break;
}
break;
- case STREAM_UNIX_ACCESS_ACL: /* Standard ACL attributes on UNIX */
- case STREAM_UNIX_DEFAULT_ACL: /* Default ACL attributes on UNIX */
- /* Ignore Unix attributes */
+ case STREAM_UNIX_ACCESS_ACL: /* Deprecated Standard ACL attributes on UNIX */
+ case STREAM_UNIX_DEFAULT_ACL: /* Deprecated Default ACL attributes on UNIX */
+ case STREAM_HFSPLUS_ATTRIBUTES:
+ 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:
+ case STREAM_ACL_AFS_TEXT:
+ case STREAM_ACL_AIX_AIXC:
+ case STREAM_ACL_AIX_NFS4:
+ case STREAM_ACL_FREEBSD_NFS4_ACL:
+ case STREAM_ACL_HURD_DEFAULT_ACL:
+ case STREAM_ACL_HURD_ACCESS_ACL:
+ /* Ignore Unix ACL attributes */
+ break;
+
+ case STREAM_XATTR_HURD:
+ case STREAM_XATTR_IRIX:
+ case STREAM_XATTR_TRU64:
+ case STREAM_XATTR_AIX:
+ 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:
{
Dmsg0(200, "Start bscan free_jcr\n");
- if (jcr->file_bsock) {
- Dmsg0(200, "Close File bsock\n");
- bnet_close(jcr->file_bsock);
- }
- if (jcr->store_bsock) {
- Dmsg0(200, "Close Store bsock\n");
- bnet_close(jcr->store_bsock);
- }
+ free_bsock(jcr->file_bsock);
+ free_bsock(jcr->store_bsock);
if (jcr->RestoreBootstrap) {
free(jcr->RestoreBootstrap);
}
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 {
static int create_client_record(B_DB *db, CLIENT_DBR *cr)
{
/*
- * Note, update_db can temporarily be set false while
+ * Note, update_db can temporarily be set false while
* updating the database, so we must ensure that ClientId is non-zero.
*/
if (!update_db) {
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;
return 1;
}
- if (!db_update_job_end_record(bjcr, db, jr, false)) {
+ if (!db_update_job_end_record(bjcr, db, jr)) {
Pmsg2(0, _("Could not update JobId=%u record. ERR=%s\n"), jr->JobId, db_strerror(db));
free_jcr(mjcr);
return 0;
}
if (verbose) {
- Pmsg3(000, _("Updated Job termination record for JobId=%u Level=%s TermStat=%c\n"),
- jr->JobId, job_level_to_str(mjcr->get_JobLevel()), 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;
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 ***");
mjcr->JobId,
mjcr->Job,
mjcr->fileset_name,
- job_level_to_str(mjcr->get_JobLevel()),
+ job_level_to_str(mjcr->getJobLevel()),
mjcr->client_name,
sdt,
edt,
* the JobId and the ClientId.
*/
jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr);
- jobjcr->set_JobType(jr->JobType);
- jobjcr->set_JobLevel(jr->JobLevel);
+ jobjcr->setJobType(jr->JobType);
+ jobjcr->setJobLevel(jr->JobLevel);
jobjcr->JobStatus = jr->JobStatus;
bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job));
jobjcr->JobId = JobId; /* this is JobId on tape */
jobjcr->VolSessionId = rec->VolSessionId;
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
- jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev);
+ jobjcr->dcr = jobjcr->read_dcr = new_dcr(jobjcr, NULL, dev, SD_READ);
return jobjcr;
}
/* Dummies to replace askdir.c */
bool dir_find_next_appendable_volume(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) { 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 dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
+bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool /*writing*/)
{
DEVICE *dev = dcr->dev;
Dmsg0(20, "Enter dir_ask_sysop_to_mount_volume\n");
return true;
}
-bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
+bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
{
Dmsg0(100, "Fake dir_get_volume_info\n");
- bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
+ dcr->setVolCatName(dcr->VolumeName);
+#ifdef BUILD_DVD
dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
- Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);
+#endif
+ Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);
return 1;
}