/*
- 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 three of the GNU Affero 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 Affero 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.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ 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.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
*
#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);
/* Forward referenced functions */
static void do_scan(void);
static bool record_cb(DCR *dcr, DEV_RECORD *rec);
-static int create_file_attributes_record(B_DB *db, JCR *mjcr,
+static int create_file_attributes_record(BDB *db, JCR *mjcr,
char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec);
-static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
-static bool update_media_record(B_DB *db, MEDIA_DBR *mr);
-static int create_pool_record(B_DB *db, POOL_DBR *pr);
-static JCR *create_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
-static int update_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
+static int create_media_record(BDB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
+static bool update_media_record(BDB *db, MEDIA_DBR *mr);
+static int create_pool_record(BDB *db, POOL_DBR *pr);
+static JCR *create_job_record(BDB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
+static int update_job_record(BDB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
DEV_RECORD *rec);
-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 int create_client_record(BDB *db, CLIENT_DBR *cr);
+static int create_fileset_record(BDB *db, FILESET_DBR *fsr);
+static int create_jobmedia_record(BDB *db, JCR *jcr);
static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
-static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type);
+static int update_digest_record(BDB *db, char *digest, DEV_RECORD *rec, int type);
/* Local variables */
static DEVICE *dev = NULL;
-static B_DB *db;
+static BDB *db;
static JCR *bjcr; /* jcr for bscan */
static BSR *bsr = NULL;
static MEDIA_DBR mr;
static const char *db_user = "bacula";
static const char *db_password = "";
static const char *db_host = NULL;
+static const char *db_ssl_key = NULL;
+static const char *db_ssl_cert = NULL;
+static const char *db_ssl_ca = NULL;
+static const char *db_ssl_capath = NULL;
+static const char *db_ssl_cipher = NULL;
static int db_port = 0;
static const char *wd = NULL;
static bool update_db = false;
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 */
pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER;
-
static void usage()
{
fprintf(stderr, _(
PROG_COPYRIGHT
-"\nVersion: %s (%s)\n\n"
+"\n%sVersion: %s (%s)\n\n"
"Usage: bscan [ options ] <bacula-archive>\n"
" -b bootstrap specify a bootstrap file\n"
" -c <file> specify configuration file\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"
+" -k <sslkey> path name to the key file (default NULL)\n"
+" -e <sslcert> path name to the certificate file (default NULL)\n"
+" -a <sslca> path name to the CA certificate file (default NULL)\n"
" -t <port> specify database port (default 0)\n"
" -p proceed inspite of I/O errors\n"
" -r list records\n"
" -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);
}
OSDependentInit();
- while ((ch = getopt(argc, argv, "b:c:d:D:h:p:mn:pP:rsSt:u:vV:w:?")) != -1) {
+ while ((ch = getopt(argc, argv, "b:c:d:D:h:k:e:a:p:mn:pP:rsSt:u:vV:w:?")) != -1) {
switch (ch) {
case 'S' :
showProgress = true;
case 'h':
db_host = optarg;
break;
-
+
+ case 'k':
+ db_ssl_key = optarg;
+ break;
+
+ case 'e':
+ db_ssl_cert = optarg;
+ break;
+
+ case 'a':
+ db_ssl_ca = 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_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)) {
- Emsg0(M_ERROR_TERM, 0, db_strerror(db));
+ db = db_init_database(NULL, db_driver, db_name, db_user, db_password,
+ db_host, db_port, NULL,
+ db_ssl_key, db_ssl_cert, db_ssl_ca,
+ db_ssl_capath, db_ssl_cipher,
+ false, false);
+ if (!db || !db_open_database(NULL, db)) {
+ Pmsg2(000, _("Could not open Catalog \"%s\", database \"%s\".\n"),
+ db_driver, db_name);
+ if (db) {
+ Jmsg(NULL, M_FATAL, 0, _("%s"), db_strerror(db));
+ Pmsg1(000, "%s", db_strerror(db));
+ db_close_database(NULL, db);
+ }
+ Jmsg(NULL, M_ERROR_TERM, 0, _("Could not open Catalog \"%s\", database \"%s\".\n"),
+ db_driver, db_name);
}
Dmsg0(200, "Database opened\n");
if (verbose) {
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;
}
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;
bool save_update_db = update_db;
if (verbose > 1) {
- dump_label_record(dev, rec, 1);
+ dump_label_record(dev, rec, 1, false);
}
switch (rec->FileIndex) {
case PRE_LABEL:
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);
}
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
+ /* 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);
+ 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;
+ mjcr->bscan_insert_jobmedia_records = false;
} else {
mjcr->bscan_insert_jobmedia_records = true;
}
/* Create JobMedia record */
mjcr->read_dcr->VolLastIndex = dcr->VolLastIndex;
if( mjcr->bscan_insert_jobmedia_records ) {
- create_jobmedia_record(db, mjcr);
+ create_jobmedia_record(db, mjcr);
}
free_dcr(mjcr->read_dcr);
free_jcr(mjcr);
}
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);
}
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:
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: /* 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:
- case STREAM_ACL_AFS_TEXT:
- case STREAM_ACL_AIX_AIXC:
- case STREAM_ACL_AIX_NFS4:
- case STREAM_ACL_FREEBSD_NFS4_ACL:
+ 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_XACL_AIX_TEXT:
+ case STREAM_XACL_DARWIN_ACCESS:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ case STREAM_XACL_HPUX_ACL_ENTRY:
+ case STREAM_XACL_IRIX_DEFAULT:
+ case STREAM_XACL_IRIX_ACCESS:
+ case STREAM_XACL_LINUX_DEFAULT:
+ case STREAM_XACL_LINUX_ACCESS:
+ case STREAM_XACL_TRU64_DEFAULT:
+ case STREAM_XACL_TRU64_DEFAULT_DIR:
+ case STREAM_XACL_TRU64_ACCESS:
+ case STREAM_XACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_NFS4:
+ case STREAM_XACL_AFS_TEXT:
+ case STREAM_XACL_AIX_AIXC:
+ case STREAM_XACL_AIX_NFS4:
+ case STREAM_XACL_FREEBSD_NFS4:
+ case STREAM_XACL_HURD_DEFAULT:
+ case STREAM_XACL_HURD_ACCESS:
/* Ignore Unix ACL attributes */
break;
- 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:
+ case STREAM_XACL_HURD_XATTR:
+ case STREAM_XACL_IRIX_XATTR:
+ case STREAM_XACL_TRU64_XATTR:
+ case STREAM_XACL_AIX_XATTR:
+ case STREAM_XACL_OPENBSD_XATTR:
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
+ case STREAM_XACL_SOLARIS_XATTR:
+ case STREAM_XACL_DARWIN_XATTR:
+ case STREAM_XACL_FREEBSD_XATTR:
+ case STREAM_XACL_LINUX_XATTR:
+ case STREAM_XACL_NETBSD_XATTR:
/* Ignore Unix Extended attributes */
break;
{
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);
}
* We got a File Attributes record on the tape. Now, lookup the Job
* record, and then create the attributes record.
*/
-static int create_file_attributes_record(B_DB *db, JCR *mjcr,
+static int create_file_attributes_record(BDB *db, JCR *mjcr,
char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec)
{
/*
* For each Volume we see, we create a Medium record
*/
-static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
+static int create_media_record(BDB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
{
struct date_time dt;
struct tm tm;
/*
* Called at end of media to update it
*/
-static bool update_media_record(B_DB *db, MEDIA_DBR *mr)
+static bool update_media_record(BDB *db, MEDIA_DBR *mr)
{
if (!update_db && !update_vol_info) {
return true;
}
-static int create_pool_record(B_DB *db, POOL_DBR *pr)
+static int create_pool_record(BDB *db, POOL_DBR *pr)
{
pr->NumVols++;
pr->UseCatalog = 1;
/*
* Called from SOS to create a client for the current Job
*/
-static int create_client_record(B_DB *db, CLIENT_DBR *cr)
+static int create_client_record(BDB *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) {
return 1;
}
-static int create_fileset_record(B_DB *db, FILESET_DBR *fsr)
+static int create_fileset_record(BDB *db, FILESET_DBR *fsr)
{
if (!update_db) {
return 1;
* the Job record and to update it when the Job actually
* begins running.
*/
-static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
+static JCR *create_job_record(BDB *db, JOB_DBR *jr, SESSION_LABEL *label,
DEV_RECORD *rec)
{
JCR *mjcr;
* Simulate the database call that updates the Job
* at Job termination time.
*/
-static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel,
+static int update_job_record(BDB *db, JOB_DBR *jr, SESSION_LABEL *elabel,
DEV_RECORD *rec)
{
struct date_time dt;
return 0;
}
if (verbose) {
- Pmsg3(000, _("Updated Job termination record for JobId=%u Level=%s TermStat=%c\n"),
+ 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) {
return 1;
}
-static int create_jobmedia_record(B_DB *db, JCR *mjcr)
+static int create_jobmedia_record(BDB *db, JCR *mjcr)
{
JOBMEDIA_DBR jmr;
DCR *dcr = mjcr->read_dcr;
/*
* Simulate the database call that updates the MD5/SHA1 record
*/
-static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type)
+static int update_digest_record(BDB *db, char *digest, DEV_RECORD *rec, int type)
{
JCR *mjcr;
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;
}
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, bool zero) { return 1; }
+bool flush_jobmedia_queue(JCR *jcr) { return true; }
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");
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);
+ Dmsg2(500, "Vol=%s VolType=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatType);
return 1;
}