From f52955c3e03b6fef083df5b77ce25a75213e2539 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Fri, 23 Aug 2002 20:49:22 +0000 Subject: [PATCH] Add jcr to BSOCK and BDB SpoolAttr NoAttributs finish up multiple simultaneous jobs restore git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@119 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/cats/bdb.c | 3 +- bacula/src/cats/cats.h | 3 + bacula/src/cats/mysql.c | 3 +- bacula/src/cats/protos.h | 4 +- bacula/src/cats/sql_create.c | 27 +- bacula/src/cats/sqlite.c | 3 +- bacula/src/console/console.c | 2 +- bacula/src/dird/dird.c | 28 +- bacula/src/dird/dird_conf.c | 1 + bacula/src/dird/dird_conf.h | 203 +++++------ bacula/src/dird/job.c | 2 +- bacula/src/dird/msgchan.c | 9 +- bacula/src/dird/ua_cmds.c | 2 +- bacula/src/filed/job.c | 1 + bacula/src/lib/bnet.c | 52 +-- bacula/src/lib/bnet_server.c | 6 +- bacula/src/lib/bsock.h | 1 + bacula/src/lib/message.c | 12 +- bacula/src/lib/protos.h | 194 +++++------ bacula/src/stored/Makefile.in | 25 +- bacula/src/stored/acquire.c | 242 +++++++++++++ bacula/src/stored/append.c | 1 - bacula/src/stored/bextract.c | 405 +++++++++++----------- bacula/src/stored/bls.c | 16 +- bacula/src/stored/bscan.c | 348 ++++++++++--------- bacula/src/stored/device.c | 631 +--------------------------------- bacula/src/stored/fd_cmds.c | 2 + bacula/src/stored/job.c | 12 +- bacula/src/stored/label.c | 12 +- bacula/src/stored/mount.c | 475 +++++++++++++++++++++++++ bacula/src/stored/protos.h | 18 +- bacula/src/stored/read.c | 207 +++++------ bacula/src/stored/record.c | 156 +-------- bacula/src/tools/dbcheck.c | 2 +- 34 files changed, 1560 insertions(+), 1548 deletions(-) create mode 100644 bacula/src/stored/acquire.c create mode 100644 bacula/src/stored/mount.c diff --git a/bacula/src/cats/bdb.c b/bacula/src/cats/bdb.c index ae1819abf4..dea6aff127 100644 --- a/bacula/src/cats/bdb.c +++ b/bacula/src/cats/bdb.c @@ -100,7 +100,7 @@ int bdb_write_control_file(B_DB *mdb) * never have errors, or it is really fatal. */ B_DB * -db_init_database(char *db_name, char *db_user, char *db_password) +db_init_database(void *jcr, char *db_name, char *db_user, char *db_password) { B_DB *mdb; P(mutex); /* lock DB queue */ @@ -127,6 +127,7 @@ db_init_database(char *db_name, char *db_user, char *db_password) qinsert(&db_list, &mdb->bq); /* put db in list */ Dmsg0(200, "Done db_open_database()\n"); mdb->cfd = -1; + mdb->jcr = jcr; V(mutex); return mdb; } diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 4fc6c7d3ef..7944051bf0 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -99,6 +99,7 @@ typedef struct s_db { uint32_t cached_path_id; int transaction; /* transaction started */ int changes; /* changes during transaction */ + void *jcr; /* JCR or NULL */ } B_DB; @@ -162,6 +163,7 @@ typedef struct s_db { POOLMEM *cached_path; uint32_t cached_path_id; int changes; /* changes made to db */ + void *jcr; /* JCR or NULL */ } B_DB; @@ -224,6 +226,7 @@ typedef struct s_db { POOLMEM *cmd; /* Command string */ POOLMEM *cached_path; uint32_t cached_path_id; + void *jcr; /* JCR or NULL */ } B_DB; #endif /* HAVE_MYSQL */ diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index 5ad818e7b0..89539ccc64 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -56,7 +56,7 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; * never have errors, or it is really fatal. */ B_DB * -db_init_database(char *db_name, char *db_user, char *db_password) +db_init_database(void *jcr, char *db_name, char *db_user, char *db_password) { B_DB *mdb; @@ -84,6 +84,7 @@ db_init_database(char *db_name, char *db_user, char *db_password) mdb->cached_path_id = 0; mdb->ref_count = 1; qinsert(&db_list, &mdb->bq); /* put db in list */ + mdb->jcr = jcr; V(mutex); return mdb; } diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 66f2c72989..ab1fb39c18 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -30,7 +30,7 @@ /* Database prototypes */ /* sql.c */ -B_DB *db_init_database(char *db_name, char *db_user, char *db_password); +B_DB *db_init_database(void *jcr, char *db_name, char *db_user, char *db_password); int db_open_database(B_DB *db); void db_close_database(B_DB *db); void db_escape_string(char *snew, char *old, int len); @@ -90,7 +90,7 @@ int db_update_job_start_record(B_DB *db, JOB_DBR *jr); int db_update_job_end_record(B_DB *db, JOB_DBR *jr); int db_update_pool_record(B_DB *db, POOL_DBR *pr); int db_update_media_record(B_DB *db, MEDIA_DBR *mr); -int db_add_MD5_to_file_record(B_DB *mdb, FileId_t FileId, char *MD5); +int db_add_MD5_to_file_record(B_DB *mdb, FileId_t FileId, char *MD5); int db_mark_file_record(B_DB *mdb, FileId_t FileId, JobId_t JobId); #endif /* __SQL_PROTOS_H */ diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 7674ec14a3..033d5451f0 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -285,11 +285,12 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr) /* If more than one, report error, but return first row */ if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("More than one Client!: %d\n"), (int)(mdb->num_rows)); - Emsg0(M_ERROR, 0, mdb->errmsg); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); } if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); sql_free_result(mdb); db_unlock(mdb); return 0; @@ -312,6 +313,7 @@ FileRetention, JobRetention) VALUES \ if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); cr->ClientId = 0; stat = 0; } else { @@ -345,11 +347,12 @@ FileSet='%s' and MD5='%s'", fsr->FileSet, fsr->MD5); if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("More than one FileSet!: %d\n"), (int)(mdb->num_rows)); - Emsg0(M_ERROR, 0, mdb->errmsg); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); } if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); sql_free_result(mdb); db_unlock(mdb); return 0; @@ -369,6 +372,7 @@ FileSet='%s' and MD5='%s'", fsr->FileSet, fsr->MD5); if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); fsr->FileSetId = 0; stat = 0; } else { @@ -427,6 +431,7 @@ int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar) */ if (ar->Stream != STREAM_UNIX_ATTRIBUTES) { Mmsg0(&mdb->errmsg, _("Attempt to put non-attributes into catalog\n")); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); return 0; } @@ -454,7 +459,7 @@ int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar) */ fnl = p - l; if (fnl > 255) { - Emsg1(M_WARNING, 0, _("Filename truncated to 255 chars: %s\n"), l); + Jmsg(mdb->jcr, M_WARNING, 0, _("Filename truncated to 255 chars: %s\n"), l); fnl = 255; } if (fnl > 0) { @@ -468,7 +473,7 @@ int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar) pnl = l - ar->fname; if (pnl > 255) { - Emsg1(M_WARNING, 0, _("Path name truncated to 255 chars: %s\n"), ar->fname); + Jmsg(mdb->jcr, M_WARNING, 0, _("Path name truncated to 255 chars: %s\n"), ar->fname); pnl = 255; } strncpy(spath, ar->fname, pnl); @@ -476,7 +481,7 @@ int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar) if (pnl == 0) { Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), ar->fname); - Emsg0(M_ERROR, 0, mdb->errmsg); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); spath[0] = ' '; spath[1] = 0; pnl = 1; @@ -527,6 +532,7 @@ LStat, MD5) VALUES (%d, %d, %d, %d, '%s', '0')", if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"), mdb->cmd, sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); ar->FileId = 0; stat = 0; } else { @@ -545,6 +551,7 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) if (*path == 0) { Mmsg0(&mdb->errmsg, _("Null path given to db_create_path_record\n")); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); ar->PathId = 0; ASSERT(ar->PathId); return 0; @@ -569,13 +576,13 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) char ed1[30]; Mmsg2(&mdb->errmsg, _("More than one Path!: %s for Path=%s\n"), edit_uint64(mdb->num_rows, ed1), path); - Emsg1(M_ERROR, 0, "%s", mdb->errmsg); - Emsg1(M_ERROR, 0, "%s\n", mdb->cmd); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); } if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { db_unlock(mdb); Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); sql_free_result(mdb); ar->PathId = 0; ASSERT(ar->PathId); @@ -603,6 +610,7 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); ar->PathId = 0; stat = 0; } else { @@ -635,13 +643,13 @@ static int db_create_filename_record(B_DB *mdb, ATTR_DBR *ar, char *fname) if (mdb->num_rows > 1) { Mmsg2(&mdb->errmsg, _("More than one Filename!: %d File=%s\n"), (int)(mdb->num_rows), fname); - Emsg1(M_ERROR, 0, "%s", mdb->errmsg); - Emsg1(M_ERROR, 0, "%s\n", mdb->cmd); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); } if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg2(&mdb->errmsg, _("error fetching row for file=%s: ERR=%s\n"), fname, sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); ar->FilenameId = 0; } else { ar->FilenameId = atoi(row[0]); @@ -659,6 +667,7 @@ VALUES ('%s')", fname); if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); + Jmsg(mdb->jcr, M_ERROR, 0, "%s", mdb->errmsg); ar->FilenameId = 0; } else { ar->FilenameId = sql_insert_id(mdb); diff --git a/bacula/src/cats/sqlite.c b/bacula/src/cats/sqlite.c index ee9022d809..4628f698c8 100644 --- a/bacula/src/cats/sqlite.c +++ b/bacula/src/cats/sqlite.c @@ -59,7 +59,7 @@ int QueryDB(char *file, int line, B_DB *db, char *select_cmd); * never have errors, or it is really fatal. */ B_DB * -db_init_database(char *db_name, char *db_user, char *db_password) +db_init_database(void *jcr, char *db_name, char *db_user, char *db_password) { B_DB *mdb; @@ -85,6 +85,7 @@ db_init_database(char *db_name, char *db_user, char *db_password) mdb->cached_path_id = 0; mdb->ref_count = 1; qinsert(&db_list, &mdb->bq); /* put db in list */ + mdb->jcr = jcr; V(mutex); return mdb; } diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 616cbaf980..49b8beb2f1 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -245,7 +245,7 @@ Without that I don't how to speak to the Director :-(\n", configfile); memset(&jcr, 0, sizeof(jcr)); if (ndir > 1) { - UA_sock = init_bsock(0, "", "", 0); + UA_sock = init_bsock(NULL, 0, "", "", 0); try_again: fprintf(output, "Available Directors:\n"); LockRes(); diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index d89099596d..09a6080fad 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -166,7 +166,7 @@ int main (int argc, char *argv[]) parse_config(configfile); if (!check_resources()) { - Emsg1(M_ERROR_TERM, 0, "Please correct configuration file: %s\n", configfile); + Jmsg(NULL, M_ERROR_TERM, 0, "Please correct configuration file: %s\n", configfile); } if (test_config) { @@ -268,7 +268,7 @@ static void reload_config(int sig) Dmsg0(200, "check_resources()\n"); if (!check_resources()) { - Emsg1(M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile); + Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile); } /* Reset globals */ @@ -299,48 +299,48 @@ static int check_resources() job = (JOB *)GetNextRes(R_JOB, NULL); director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL); if (!director) { - Emsg1(M_FATAL, 0, _("No Director resource defined in %s\n\ + Jmsg(NULL, M_FATAL, 0, _("No Director resource defined in %s\n\ Without that I don't know who I am :-(\n"), configfile); OK = FALSE; } else { if (!director->working_directory) { - Emsg0(M_FATAL, 0, _("No working directory specified. Cannot continue.\n")); + Jmsg(NULL, M_FATAL, 0, _("No working directory specified. Cannot continue.\n")); OK = FALSE; } working_directory = director->working_directory; if (!director->messages) { /* If message resource not specified */ director->messages = (MSGS *)GetNextRes(R_MSGS, NULL); if (!director->messages) { - Emsg1(M_FATAL, 0, _("No Messages resource defined in %s\n"), configfile); + Jmsg(NULL, M_FATAL, 0, _("No Messages resource defined in %s\n"), configfile); OK = FALSE; } } if (GetNextRes(R_DIRECTOR, (RES *)director) != NULL) { - Emsg1(M_FATAL, 0, _("Only one Director resource permitted in %s\n"), + Jmsg(NULL, M_FATAL, 0, _("Only one Director resource permitted in %s\n"), configfile); OK = FALSE; } } if (!job) { - Emsg1(M_FATAL, 0, _("No Job records defined in %s\n"), configfile); + Jmsg(NULL, M_FATAL, 0, _("No Job records defined in %s\n"), configfile); OK = FALSE; } for (job=NULL; (job = (JOB *)GetNextRes(R_JOB, (RES *)job)); ) { if (!job->client) { - Emsg1(M_FATAL, 0, _("No Client record defined for job %s\n"), job->hdr.name); + Jmsg(NULL, M_FATAL, 0, _("No Client record defined for job %s\n"), job->hdr.name); OK = FALSE; } if (!job->fileset) { - Emsg1(M_FATAL, 0, _("No FileSet record defined for job %s\n"), job->hdr.name); + Jmsg(NULL, M_FATAL, 0, _("No FileSet record defined for job %s\n"), job->hdr.name); OK = FALSE; } if (!job->storage && job->JobType != JT_VERIFY) { - Emsg1(M_FATAL, 0, _("No Storage resource defined for job %s\n"), job->hdr.name); + Jmsg(NULL, M_FATAL, 0, _("No Storage resource defined for job %s\n"), job->hdr.name); OK = FALSE; } if (!job->pool) { - Emsg1(M_FATAL, 0, _("No Pool resource defined for job %s\n"), job->hdr.name); + Jmsg(NULL, M_FATAL, 0, _("No Pool resource defined for job %s\n"), job->hdr.name); OK = FALSE; } if (job->client && job->client->catalog) { @@ -351,15 +351,15 @@ Without that I don't know who I am :-(\n"), configfile); * Make sure we can open catalog, otherwise print a warning * message because the server is probably not running. */ - db = db_init_database(catalog->db_name, catalog->db_user, + db = db_init_database(NULL, catalog->db_name, catalog->db_user, catalog->db_password); if (!db_open_database(db)) { - Emsg1(M_FATAL, 0, "%s", db_strerror(db)); + Jmsg(NULL, M_FATAL, 0, "%s", db_strerror(db)); } db_close_database(db); } else { if (job->client) { - Emsg1(M_FATAL, 0, _("No Catalog resource defined for client %s\n"), + Jmsg(NULL, M_FATAL, 0, _("No Catalog resource defined for client %s\n"), job->client->hdr.name); OK = FALSE; } diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index dd00ff9c18..79b910fd70 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -179,6 +179,7 @@ static struct res_items job_items[] = { {"prunevolumes", store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0}, {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0}, {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0}, + {"spoolattributes", store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 7c3e6d0284..2689d89b0e 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -30,43 +30,43 @@ /* * Resource codes -- they must be sequential for indexing */ -#define R_FIRST 1001 - -#define R_DIRECTOR 1001 -#define R_CLIENT 1002 -#define R_JOB 1003 -#define R_STORAGE 1004 -#define R_CATALOG 1005 -#define R_SCHEDULE 1006 -#define R_FILESET 1007 -#define R_GROUP 1008 -#define R_POOL 1009 -#define R_MSGS 1010 -#define R_COUNTER 1011 - -#define R_LAST R_COUNTER +#define R_FIRST 1001 + +#define R_DIRECTOR 1001 +#define R_CLIENT 1002 +#define R_JOB 1003 +#define R_STORAGE 1004 +#define R_CATALOG 1005 +#define R_SCHEDULE 1006 +#define R_FILESET 1007 +#define R_GROUP 1008 +#define R_POOL 1009 +#define R_MSGS 1010 +#define R_COUNTER 1011 + +#define R_LAST R_COUNTER /* * Some resource attributes */ -#define R_NAME 1020 -#define R_ADDRESS 1021 -#define R_PASSWORD 1022 -#define R_TYPE 1023 -#define R_BACKUP 1024 +#define R_NAME 1020 +#define R_ADDRESS 1021 +#define R_PASSWORD 1022 +#define R_TYPE 1023 +#define R_BACKUP 1024 /* Used for certain KeyWord tables */ -struct s_kw { +struct s_kw { char *name; - int token; + int token; }; /* Job Level keyword structure */ struct s_jl { - char *level_name; /* level keyword */ - int level; /* level */ - int job_type; /* JobType permitting this level */ + char *level_name; /* level keyword */ + int level; /* level */ + int job_type; /* JobType permitting this level */ }; /* Job Type keyword structure */ @@ -78,21 +78,21 @@ struct s_jt { /* Definition of the contents of each Resource */ /* - * Director Resource + * Director Resource * */ struct s_res_dir { - RES hdr; - int DIRport; /* where we listen -- UA port server port */ - char *password; /* Password for UA access */ - char *query_file; /* SQL query file */ - char *working_directory; /* WorkingDirectory */ - char *pid_directory; /* PidDirectory */ - char *subsys_directory; /* SubsysDirectory */ + RES hdr; + int DIRport; /* where we listen -- UA port server port */ + char *password; /* Password for UA access */ + char *query_file; /* SQL query file */ + char *working_directory; /* WorkingDirectory */ + char *pid_directory; /* PidDirectory */ + char *subsys_directory; /* SubsysDirectory */ struct s_res_msgs *messages; /* Daemon message handler */ - int MaxConcurrentJobs; - btime_t FDConnectTimeout; /* timeout for connect in seconds */ - btime_t SDConnectTimeout; /* timeout in seconds */ + int MaxConcurrentJobs; + btime_t FDConnectTimeout; /* timeout for connect in seconds */ + btime_t SDConnectTimeout; /* timeout in seconds */ }; typedef struct s_res_dir DIRRES; @@ -101,12 +101,12 @@ typedef struct s_res_dir DIRRES; * */ struct s_res_client { - RES hdr; + RES hdr; - int FDport; /* Where File daemon listens */ - int AutoPrune; /* Do automatic pruning? */ - btime_t FileRetention; /* file retention period in seconds */ - btime_t JobRetention; /* job retention period in seconds */ + int FDport; /* Where File daemon listens */ + int AutoPrune; /* Do automatic pruning? */ + btime_t FileRetention; /* file retention period in seconds */ + btime_t JobRetention; /* job retention period in seconds */ char *address; char *password; struct s_res_cat *catalog; /* Catalog resource */ @@ -118,10 +118,10 @@ typedef struct s_res_client CLIENT; * */ struct s_res_store { - RES hdr; + RES hdr; - int SDport; /* port where Directors connect */ - int SDDport; /* data port for File daemon */ + int SDport; /* port where Directors connect */ + int SDDport; /* data port for File daemon */ char *address; char *password; char *media_type; @@ -134,9 +134,9 @@ typedef struct s_res_store STORE; * */ struct s_res_cat { - RES hdr; + RES hdr; - int DBport; /* Port -- not yet implemented */ + int DBport; /* Port -- not yet implemented */ char *address; char *db_password; char *db_user; @@ -149,28 +149,29 @@ typedef struct s_res_cat CAT; * */ struct s_res_job { - RES hdr; - - int JobType; /* job type (backup, verify, restore */ - int level; /* default backup/verify level */ - int RestoreJobId; /* What -- JobId to restore */ - char *RestoreWhere; /* Where on disk to restore -- directory */ - char *RestoreBootstrap; /* Bootstrap file */ - char *RunBeforeJob; /* Run program before Job */ - char *RunAfterJob; /* Run program after Job */ - int RestoreOptions; /* How (overwrite, ..) */ - btime_t MaxRunTime; /* max run time in seconds */ - btime_t MaxStartDelay; /* max start delay in seconds */ - int PruneJobs; /* Force pruning of Jobs */ - int PruneFiles; /* Force pruning of Files */ - int PruneVolumes; /* Force pruning of Volumes */ + RES hdr; + + int JobType; /* job type (backup, verify, restore */ + int level; /* default backup/verify level */ + int RestoreJobId; /* What -- JobId to restore */ + char *RestoreWhere; /* Where on disk to restore -- directory */ + char *RestoreBootstrap; /* Bootstrap file */ + char *RunBeforeJob; /* Run program before Job */ + char *RunAfterJob; /* Run program after Job */ + int RestoreOptions; /* How (overwrite, ..) */ + btime_t MaxRunTime; /* max run time in seconds */ + btime_t MaxStartDelay; /* max start delay in seconds */ + int PruneJobs; /* Force pruning of Jobs */ + int PruneFiles; /* Force pruning of Files */ + int PruneVolumes; /* Force pruning of Volumes */ + int SpoolAttributes; /* Set to spool attributes in SD */ struct s_res_msgs *messages; /* How and where to send messages */ struct s_res_sch *schedule; /* When -- Automatic schedule */ struct s_res_client *client; /* Who to backup */ struct s_res_fs *fileset; /* What to backup -- Fileset */ struct s_res_store *storage; /* Where is device -- Storage daemon */ - struct s_res_pool *pool; /* Where is media -- Media Pool */ + struct s_res_pool *pool; /* Where is media -- Media Pool */ }; typedef struct s_res_job JOB; @@ -179,7 +180,7 @@ typedef struct s_res_job JOB; * */ struct s_res_fs { - RES hdr; + RES hdr; char **include_array; int num_includes; @@ -187,8 +188,8 @@ struct s_res_fs { char **exclude_array; int num_excludes; int exclude_size; - int have_MD5; /* set if MD5 initialized */ - struct MD5Context md5c; /* MD5 of include/exclude */ + int have_MD5; /* set if MD5 initialized */ + struct MD5Context md5c; /* MD5 of include/exclude */ }; typedef struct s_res_fs FILESET; @@ -198,7 +199,7 @@ typedef struct s_res_fs FILESET; * */ struct s_res_sch { - RES hdr; + RES hdr; struct s_run *run; }; @@ -209,7 +210,7 @@ typedef struct s_res_sch SCHED; * */ struct s_res_group { - RES hdr; + RES hdr; }; typedef struct s_res_group GROUP; @@ -217,12 +218,12 @@ typedef struct s_res_group GROUP; * Counter Resource */ struct s_res_counter { - RES hdr; + RES hdr; - int32_t MinValue; /* Minimum value */ - int32_t MaxValue; /* Maximum value */ - int Global; /* global/local */ - char *WrapCounter; /* Wrap counter name */ + int32_t MinValue; /* Minimum value */ + int32_t MaxValue; /* Maximum value */ + int Global; /* global/local */ + char *WrapCounter; /* Wrap counter name */ }; typedef struct s_res_counter COUNTER; @@ -231,19 +232,19 @@ typedef struct s_res_counter COUNTER; * */ struct s_res_pool { - RES hdr; + RES hdr; struct s_res_counter counter; /* Counter resources */ - char *pool_type; /* Pool type */ - char *label_format; /* Label format string */ - int use_catalog; /* maintain catalog for media */ - int catalog_files; /* maintain file entries in catalog */ - int use_volume_once; /* write on volume only once */ - int accept_any_volume; /* accept any volume */ - int max_volumes; /* max number of volumes */ - btime_t VolRetention; /* volume retention period in seconds */ - int AutoPrune; /* default for pool auto prune */ - int Recycle; /* default for media recycle yes/no */ + char *pool_type; /* Pool type */ + char *label_format; /* Label format string */ + int use_catalog; /* maintain catalog for media */ + int catalog_files; /* maintain file entries in catalog */ + int use_volume_once; /* write on volume only once */ + int accept_any_volume; /* accept any volume */ + int max_volumes; /* max number of volumes */ + btime_t VolRetention; /* volume retention period in seconds */ + int AutoPrune; /* default for pool auto prune */ + int Recycle; /* default for media recycle yes/no */ }; typedef struct s_res_pool POOL; @@ -252,16 +253,16 @@ typedef struct s_res_pool POOL; * resource structure definitions. */ union u_res { - struct s_res_dir res_dir; - struct s_res_client res_client; - struct s_res_store res_store; - struct s_res_cat res_cat; - struct s_res_job res_job; - struct s_res_fs res_fs; - struct s_res_sch res_sch; - struct s_res_group res_group; - struct s_res_pool res_pool; - struct s_res_msgs res_msgs; + struct s_res_dir res_dir; + struct s_res_client res_client; + struct s_res_store res_store; + struct s_res_cat res_cat; + struct s_res_job res_job; + struct s_res_fs res_fs; + struct s_res_sch res_sch; + struct s_res_group res_group; + struct s_res_pool res_pool; + struct s_res_msgs res_msgs; struct s_res_counter res_counter; RES hdr; }; @@ -271,17 +272,17 @@ typedef union u_res URES; /* Run structure contained in Schedule Resource */ struct s_run { - struct s_run *next; /* points to next run record */ - int level; /* level override */ + struct s_run *next; /* points to next run record */ + int level; /* level override */ int job_type; - POOL *pool; /* Pool override */ - STORE *storage; /* Storage override */ - MSGS *msgs; /* Messages override */ + POOL *pool; /* Pool override */ + STORE *storage; /* Storage override */ + MSGS *msgs; /* Messages override */ char *since; int level_no; - int minute; /* minute to run job */ - time_t last_run; /* last time run */ - time_t next_run; /* next time to run */ + int minute; /* minute to run job */ + time_t last_run; /* last time run */ + time_t next_run; /* next time to run */ char hour[nbytes_for_bits(24)]; /* bit set for each hour */ char mday[nbytes_for_bits(31)]; /* bit set for each day of month */ char month[nbytes_for_bits(12)]; /* bit set for each month */ diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index e5b22303c1..1ed219546f 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -92,7 +92,7 @@ void run_job(JCR *jcr) * Open database */ Dmsg0(50, "Open database\n"); - jcr->db=db_init_database(jcr->catalog->db_name, jcr->catalog->db_user, + jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user, jcr->catalog->db_password); if (!db_open_database(jcr->db)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index 9f813eff60..d3a88d7e71 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -40,7 +40,7 @@ /* Commands sent to Storage daemon */ static char jobcmd[] = "JobId=%d job=%s job_name=%s client_name=%s \ -type=%d level=%d FileSet=%s Allow=%s Session=%s\n"; +type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d\n"; static char use_device[] = "use device=%s media_type=%s pool_name=%s pool_type=%s\n"; /* Response from Storage daemon */ @@ -107,7 +107,8 @@ int start_storage_daemon_job(JCR *jcr) bash_spaces(jcr->client->hdr.name); bnet_fsend(sd, jobcmd, jcr->JobId, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name, jcr->JobType, jcr->JobLevel, - jcr->fileset->hdr.name, "append", "*"); + jcr->fileset->hdr.name, !jcr->pool->catalog_files, + jcr->job->SpoolAttributes); unbash_spaces(jcr->job->hdr.name); unbash_spaces(jcr->client->hdr.name); unbash_spaces(jcr->fileset->hdr.name); @@ -146,7 +147,7 @@ int start_storage_daemon_job(JCR *jcr) bash_spaces(media_type); bash_spaces(pool_type); bash_spaces(pool_name); - sd->msg = (char *) check_pool_memory_size(sd->msg, sizeof(device_name) + + sd->msg = check_pool_memory_size(sd->msg, sizeof(device_name) + device_name_len + media_type_len + pool_type_len + pool_name_len); bnet_fsend(sd, use_device, device_name, media_type, pool_name, pool_type); Dmsg1(110, ">stored: %s", sd->msg); @@ -173,7 +174,7 @@ int start_storage_daemon_message_thread(JCR *jcr) jcr->use_count++; /* mark in use by msg thread */ V(jcr->mutex); if ((status=pthread_create(&thid, NULL, msg_thread, (void *)jcr)) != 0) { - Emsg1(M_ABORT, 0, _("Cannot create message thread: %s\n"), strerror(status)); + Jmsg1(jcr, M_ABORT, 0, _("Cannot create message thread: %s\n"), strerror(status)); } jcr->SD_msg_chan = thid; return 1; diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 4c48d64cfe..bbfcc73a6f 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -1328,7 +1328,7 @@ int open_db(UAContext *ua) } Dmsg0(150, "Open database\n"); - ua->db = db_init_database(ua->catalog->db_name, ua->catalog->db_user, + ua->db = db_init_database(NULL, ua->catalog->db_name, ua->catalog->db_user, ua->catalog->db_password); if (!db_open_database(ua->db)) { bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"), diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 937831421d..2c8e98111c 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -156,6 +156,7 @@ void *handle_client_request(void *dirp) jcr->last_fname = get_pool_memory(PM_FNAME); jcr->client_name = get_memory(strlen(my_name) + 1); strcpy(jcr->client_name, my_name); + dir->jcr = (void *)jcr; /**********FIXME******* add command handler error code */ diff --git a/bacula/src/lib/bnet.c b/bacula/src/lib/bnet.c index b63ce59991..670bdd4d5a 100644 --- a/bacula/src/lib/bnet.c +++ b/bacula/src/lib/bnet.c @@ -79,7 +79,7 @@ static int32_t write_nbytes(BSOCK *bsock, char *ptr, int32_t nbytes) if (bsock->spool) { nwritten = fwrite(ptr, 1, nbytes, bsock->spool_fd); if (nwritten != nbytes) { - Emsg1(M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno)); + Jmsg1(bsock->jcr, M_ERROR, 0, _("Spool write error. ERR=%s\n"), strerror(errno)); Dmsg2(400, "nwritten=%d nbytes=%d.\n", nwritten, nbytes); return -1; } @@ -139,7 +139,7 @@ bnet_recv(BSOCK *bsock) if (nbytes != sizeof(int32_t)) { bsock->errors++; bsock->b_errno = EIO; - Emsg3(M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t), + Jmsg3(bsock->jcr, M_ERROR, 0, _("Read %d expected %d from %s\n"), nbytes, sizeof(int32_t), bsock->who); return -2; } @@ -172,7 +172,7 @@ bnet_recv(BSOCK *bsock) bsock->b_errno = errno; } bsock->errors++; - Emsg4(M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"), + Jmsg4(bsock->jcr, M_ERROR, 0, _("Read error from %s:%s:%d: ERR=%s\n"), bsock->who, bsock->host, bsock->port, bnet_strerror(bsock)); return -2; } @@ -182,7 +182,7 @@ bnet_recv(BSOCK *bsock) if (nbytes != pktsiz) { bsock->b_errno = EIO; bsock->errors++; - Emsg5(M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes, + Jmsg5(bsock->jcr, M_ERROR, 0, _("Read expected %d got %d from %s:%s:%d\n"), pktsiz, nbytes, bsock->who, bsock->host, bsock->port); return -2; } @@ -210,14 +210,14 @@ int bnet_despool(BSOCK *bsock) nbytes = fread(bsock->msg, 1, bsock->msglen, bsock->spool_fd); if (nbytes != (size_t)bsock->msglen) { Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, bsock->msglen); - Emsg1(M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno)); + Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno)); return 0; } } bnet_send(bsock); } if (ferror(bsock->spool_fd)) { - Emsg1(M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno)); + Jmsg1(bsock->jcr, M_ERROR, 0, _("fread error. ERR=%s\n"), strerror(errno)); return 0; } return 1; @@ -254,11 +254,10 @@ bnet_send(BSOCK *bsock) bsock->b_errno = errno; } if (rc < 0) { - /****FIXME***** use Mmsg */ - Emsg4(M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), + Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), bsock->who, bsock->host, bsock->port, bnet_strerror(bsock)); } else { - Emsg5(M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), + Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), bsock->who, bsock->host, bsock->port, bsock->msglen, rc); } return 0; @@ -283,10 +282,10 @@ bnet_send(BSOCK *bsock) } if (rc < 0) { /************FIXME********* use Pmsg() **/ - Emsg4(M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), + Jmsg4(bsock->jcr, M_ERROR, 0, _("Write error sending to %s:%s:%d: ERR=%s\n"), bsock->who, bsock->host, bsock->port, bnet_strerror(bsock)); } else { - Emsg5(M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), + Jmsg5(bsock->jcr, M_ERROR, 0, _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), bsock->who, bsock->host, bsock->port, bsock->msglen, rc); } return 0; @@ -334,7 +333,7 @@ bnet_wait_data(BSOCK *bsock, int sec) * Convert a hostname or dotted IP address into * a s_addr. We handle only IPv4. */ -static uint32_t *bget_host_ip(char *host) +static uint32_t *bget_host_ip(void *jcr, char *host) { struct in_addr inaddr; uint32_t *addr_list; /* this really should be struct in_addr */ @@ -353,7 +352,7 @@ static uint32_t *bget_host_ip(char *host) return NULL; } if (hp->h_length != sizeof(inaddr.s_addr) || hp->h_addrtype != AF_INET) { - Emsg2(M_WARNING, 0, _("gethostbyname() network address length error.\n\ + Jmsg2(jcr, M_WARNING, 0, _("gethostbyname() network address length error.\n\ Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length); return NULL; } @@ -380,7 +379,7 @@ Wanted %d got %d bytes for s_addr.\n"), sizeof(inaddr.s_addr), hp->h_length); * ***FIXME*** implement service from /etc/services */ static BSOCK * -bnet_open(char *name, char *host, char *service, int port) +bnet_open(void *jcr, char *name, char *host, char *service, int port) { int sockfd; struct sockaddr_in tcp_serv_addr; /* socket information */ @@ -396,7 +395,7 @@ bnet_open(char *name, char *host, char *service, int port) tcp_serv_addr.sin_family = AF_INET; tcp_serv_addr.sin_port = htons(port); - if ((addr_list=bget_host_ip(host)) == NULL) { + if ((addr_list=bget_host_ip(jcr, host)) == NULL) { return NULL; } @@ -410,7 +409,7 @@ bnet_open(char *name, char *host, char *service, int port) * Receive notification when connection dies. */ if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &turnon, sizeof(turnon)) < 0) { - Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno)); + Jmsg(jcr, M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"), strerror(errno)); } for (i = 0; addr_list[i] != ((uint32_t) -1); i++) { @@ -428,7 +427,7 @@ bnet_open(char *name, char *host, char *service, int port) close(sockfd); return NULL; } - return init_bsock(sockfd, name, host, port); + return init_bsock(jcr, sockfd, name, host, port); } /* @@ -441,7 +440,7 @@ bnet_connect(void *jcr, int retry_interval, int max_retry_time, char *name, int i; BSOCK *bsock; - for (i=0; (bsock = bnet_open(name, host, service, port)) == NULL; i -= retry_interval) { + for (i=0; (bsock = bnet_open(jcr, name, host, service, port)) == NULL; i -= retry_interval) { Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n", name, host, port, strerror(errno)); if (i <= 0) { @@ -519,20 +518,20 @@ int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw) dbuf_size = size; if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) { - Emsg0(M_FATAL, 0, _("Could not malloc 32K BSOCK data buffer\n")); + Jmsg0(bs->jcr, M_FATAL, 0, _("Could not malloc 32K BSOCK data buffer\n")); return 0; } if (rw & BNET_SETBUF_READ) { while ((dbuf_size > TAPE_BSIZE) && (setsockopt(bs->fd, SOL_SOCKET, SO_RCVBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) { - Emsg1(M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno)); + Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno)); dbuf_size -= TAPE_BSIZE; } Dmsg1(200, "set network buffer size=%d\n", dbuf_size); if (dbuf_size != MAX_NETWORK_BUFFER_SIZE) - Emsg1(M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size); + Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size); if (dbuf_size % TAPE_BSIZE != 0) { - Emsg1(M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"), + Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"), dbuf_size); } } @@ -540,14 +539,14 @@ int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw) if (rw & BNET_SETBUF_WRITE) { while ((dbuf_size > TAPE_BSIZE) && (setsockopt(bs->fd, SOL_SOCKET, SO_SNDBUF, (char *)&dbuf_size, sizeof(dbuf_size)) < 0)) { - Emsg1(M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno)); + Jmsg1(bs->jcr, M_ERROR, 0, _("sockopt error: %s\n"), strerror(errno)); dbuf_size -= TAPE_BSIZE; } Dmsg1(200, "set network buffer size=%d\n", dbuf_size); if (dbuf_size != MAX_NETWORK_BUFFER_SIZE) - Emsg1(M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size); + Jmsg1(bs->jcr, M_WARNING, 0, _("Warning network buffer = %d bytes not max size.\n"), dbuf_size); if (dbuf_size % TAPE_BSIZE != 0) { - Emsg1(M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"), + Jmsg1(bs->jcr, M_ABORT, 0, _("Network buffer size %d not multiple of tape block size.\n"), dbuf_size); } } @@ -605,7 +604,7 @@ char *bnet_sig_to_ascii(BSOCK *bs) * This probably should be done in net_open */ BSOCK * -init_bsock(int sockfd, char *who, char *host, int port) +init_bsock(void *jcr, int sockfd, char *who, char *host, int port) { BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK)); memset(bsock, 0, sizeof(BSOCK)); @@ -621,6 +620,7 @@ init_bsock(int sockfd, char *who, char *host, int port) * heartbeats are implemented */ bsock->timeout = 60 * 60 * 6 * 24; /* 6 days timeout */ + bsock->jcr = jcr; return bsock; } diff --git a/bacula/src/lib/bnet_server.c b/bacula/src/lib/bnet_server.c index 7254463713..1c2150226e 100644 --- a/bacula/src/lib/bnet_server.c +++ b/bacula/src/lib/bnet_server.c @@ -124,7 +124,7 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, fromhost(&request); if (!hosts_access(&request)) { V(mutex); - Emsg2(M_WARNING, 0, _("Connection from %s:%d refused by hosts.access"), + Jmsg2(NULL, M_WARNING, 0, _("Connection from %s:%d refused by hosts.access"), inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); close(newsockfd); continue; @@ -147,8 +147,8 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, /* Queue client to be served */ if ((stat = workq_add(client_wq, - (void *)init_bsock(newsockfd, "client", caller, port))) != 0) { - Emsg1(M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"), strerror(stat)); + (void *)init_bsock(NULL, newsockfd, "client", caller, port))) != 0) { + Jmsg1(NULL, M_ABORT, 0, _("Could not add job to client queue: ERR=%s\n"), strerror(stat)); } } } diff --git a/bacula/src/lib/bsock.h b/bacula/src/lib/bsock.h index d347a6bff0..54d1ed3d5c 100644 --- a/bacula/src/lib/bsock.h +++ b/bacula/src/lib/bsock.h @@ -53,6 +53,7 @@ typedef struct s_bsock { struct s_bsock *next; /* next BSOCK if duped */ int spool; /* set for spooling */ FILE *spool_fd; /* spooling file */ + void *jcr; /* jcr or NULL for error msgs */ } BSOCK; /* Signal definitions for use in bnet_sig() */ diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 93019a31c6..003b76a0a4 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -789,11 +789,11 @@ e_msg(char *file, int line, int type, int level, char *fmt,...) return; /* no destination */ switch (type) { case M_ABORT: - sprintf(buf, "%s ABORTING due to ERROR in %s:%d\n", + sprintf(buf, "%s: ABORTING due to ERROR in %s:%d\n", my_name, file, line); break; case M_ERROR_TERM: - sprintf(buf, "%s ERROR TERMINATION at %s:%d\n", + sprintf(buf, "%s: ERROR TERMINATION at %s:%d\n", my_name, file, line); break; case M_FATAL: @@ -861,7 +861,7 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) msgs = daemon_msgs; } if (!job) { - job = "*None*"; + job = ""; } buf = rbuf; /* we are the Director */ @@ -881,19 +881,19 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) sprintf(buf, "%s ERROR TERMINATION\n", my_name); break; case M_FATAL: - sprintf(buf, "%s: Job %s Fatal error: ", my_name, job); + sprintf(buf, "%s: %s Fatal error: ", my_name, job); if (jcr) { jcr->JobStatus = JS_FatalError; } break; case M_ERROR: - sprintf(buf, "%s: Job %s Error: ", my_name, job); + sprintf(buf, "%s: %s Error: ", my_name, job); if (jcr) { jcr->Errors++; } break; case M_WARNING: - sprintf(buf, "%s: Job %s Warning: ", my_name, job); + sprintf(buf, "%s: %s Warning: ", my_name, job); break; default: sprintf(buf, "%s: ", my_name); diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index ca9266cc2f..746ee9761b 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -24,146 +24,146 @@ */ /* base64.c */ -void base64_init (void); -int to_base64 (intmax_t value, char *where); -int from_base64 (intmax_t *value, char *where); -void encode_stat (char *buf, struct stat *statp); -void decode_stat (char *buf, struct stat *statp); -int bin_to_base64 (char *buf, char *bin, int len); +void base64_init (void); +int to_base64 (intmax_t value, char *where); +int from_base64 (intmax_t *value, char *where); +void encode_stat (char *buf, struct stat *statp); +void decode_stat (char *buf, struct stat *statp); +int bin_to_base64 (char *buf, char *bin, int len); /* bmisc.c */ -char *bstrncpy (char *dest, char *src, int maxlen); -void *b_malloc (char *file, int line, size_t size); +char *bstrncpy (char *dest, char *src, int maxlen); +void *b_malloc (char *file, int line, size_t size); #ifndef DEBUG -void *bmalloc (size_t size); +void *bmalloc (size_t size); #endif -void *brealloc (void *buf, size_t size); -void *bcalloc (size_t size1, size_t size2); -int bsnprintf (char *str, size_t size, const char *format, ...); -int bvsnprintf (char *str, size_t size, const char *format, va_list ap); -int pool_sprintf (char *pool_buf, char *fmt, ...); -void create_pid_file (char *dir, char *progname, int port); -int delete_pid_file (char *dir, char *progname, int port); +void *brealloc (void *buf, size_t size); +void *bcalloc (size_t size1, size_t size2); +int bsnprintf (char *str, size_t size, const char *format, ...); +int bvsnprintf (char *str, size_t size, const char *format, va_list ap); +int pool_sprintf (char *pool_buf, char *fmt, ...); +void create_pid_file (char *dir, char *progname, int port); +int delete_pid_file (char *dir, char *progname, int port); #ifndef HAVE_STRERROR_R -int strerror_r (int errnum, char *buf, size_t bufsiz); +int strerror_r (int errnum, char *buf, size_t bufsiz); #endif /* bnet.c */ -int32_t bnet_recv (BSOCK *bsock); -int bnet_send (BSOCK *bsock); -int bnet_fsend (BSOCK *bs, char *fmt, ...); -int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); -int bnet_sig (BSOCK *bs, int sig); -BSOCK * bnet_connect (void *jcr, int retry_interval, - int max_retry_time, char *name, char *host, char *service, - int port, int verbose); -int bnet_wait_data (BSOCK *bsock, int sec); -void bnet_close (BSOCK *bsock); -BSOCK * init_bsock (int sockfd, char *who, char *ip, int port); -BSOCK * dup_bsock (BSOCK *bsock); -void term_bsock (BSOCK *bsock); -char * bnet_strerror (BSOCK *bsock); -char * bnet_sig_to_ascii (BSOCK *bsock); -int bnet_wait_data (BSOCK *bsock, int sec); -int bnet_despool (BSOCK *bsock); +int32_t bnet_recv (BSOCK *bsock); +int bnet_send (BSOCK *bsock); +int bnet_fsend (BSOCK *bs, char *fmt, ...); +int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); +int bnet_sig (BSOCK *bs, int sig); +BSOCK * bnet_connect (void *jcr, int retry_interval, + int max_retry_time, char *name, char *host, char *service, + int port, int verbose); +int bnet_wait_data (BSOCK *bsock, int sec); +void bnet_close (BSOCK *bsock); +BSOCK * init_bsock (void *jcr, int sockfd, char *who, char *ip, int port); +BSOCK * dup_bsock (BSOCK *bsock); +void term_bsock (BSOCK *bsock); +char * bnet_strerror (BSOCK *bsock); +char * bnet_sig_to_ascii (BSOCK *bsock); +int bnet_wait_data (BSOCK *bsock, int sec); +int bnet_despool (BSOCK *bsock); /* cram-md5.c */ int cram_md5_get_auth(BSOCK *bs, char *password); int cram_md5_auth(BSOCK *bs, char *password); void hmac_md5(uint8_t* text, int text_len, uint8_t* key, - int key_len, uint8_t *hmac); + int key_len, uint8_t *hmac); /* create_file.c */ int create_file(void *jcr, char *fname, char *ofile, char *lname, - int type, struct stat *statp, int *ofd); + int type, struct stat *statp, int *ofd); int set_statp(void *jcr, char *fname, char *ofile, char *lname, int type, - struct stat *statp); + struct stat *statp); /* crc32.c */ uint32_t bcrc32(uint8_t *buf, int len); /* daemon.c */ -void daemon_start (); +void daemon_start (); /* lex.c */ -LEX * lex_close_file (LEX *lf); -LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); -int lex_get_char (LEX *lf); -void lex_unget_char (LEX *lf); -char * lex_tok_to_str (int token); -int lex_get_token (LEX *lf, int expect); +LEX * lex_close_file (LEX *lf); +LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); +int lex_get_char (LEX *lf); +void lex_unget_char (LEX *lf); +char * lex_tok_to_str (int token); +int lex_get_token (LEX *lf, int expect); /* makepath.c */ int make_path( - void *jcr, - const char *argpath, - int mode, - int parent_mode, - uid_t owner, - gid_t group, - int preserve_existing, - char *verbose_fmt_string); + void *jcr, + const char *argpath, + int mode, + int parent_mode, + uid_t owner, + gid_t group, + int preserve_existing, + char *verbose_fmt_string); /* message.c */ -void my_name_is (int argc, char *argv[], char *name); -void init_msg (void *jcr, MSGS *msg); -void term_msg (void); -void close_msg (void *jcr); -void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code); -void rem_msg_dest (MSGS *msg, int dest, int type, char *where); -void Jmsg (void *jcr, int type, int level, char *fmt, ...); -void dispatch_message (void *jcr, int type, int level, char *buf); -void init_console_msg (char *wd); -void free_msgs_res (MSGS *msgs); -int open_spool_file (void *jcr, BSOCK *bs); -int close_spool_file (void *vjcr, BSOCK *bs); +void my_name_is (int argc, char *argv[], char *name); +void init_msg (void *jcr, MSGS *msg); +void term_msg (void); +void close_msg (void *jcr); +void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code); +void rem_msg_dest (MSGS *msg, int dest, int type, char *where); +void Jmsg (void *jcr, int type, int level, char *fmt, ...); +void dispatch_message (void *jcr, int type, int level, char *buf); +void init_console_msg (char *wd); +void free_msgs_res (MSGS *msgs); +int open_spool_file (void *jcr, BSOCK *bs); +int close_spool_file (void *vjcr, BSOCK *bs); /* bnet_server.c */ -void bnet_thread_server(int port, int max_clients, workq_t *client_wq, - void handle_client_request(void *bsock)); -void bnet_server (int port, void handle_client_request(BSOCK *bsock)); -int net_connect (int port); -BSOCK * bnet_bind (int port); -BSOCK * bnet_accept (BSOCK *bsock, char *who); +void bnet_thread_server(int port, int max_clients, workq_t *client_wq, + void handle_client_request(void *bsock)); +void bnet_server (int port, void handle_client_request(BSOCK *bsock)); +int net_connect (int port); +BSOCK * bnet_bind (int port); +BSOCK * bnet_accept (BSOCK *bsock, char *who); /* signal.c */ -void init_signals (void terminate(int sig)); -void init_stack_dump (void); +void init_signals (void terminate(int sig)); +void init_stack_dump (void); /* util.c */ -void lcase (char *str); -void bash_spaces (char *str); -void unbash_spaces (char *str); -void strip_trailing_junk (char *str); -void strip_trailing_slashes (char *dir); -int skip_spaces (char **msg); -int skip_nonspaces (char **msg); -int fstrsch (char *a, char *b); -char * encode_time (time_t time, char *buf); -char * encode_mode (mode_t mode, char *buf); -char * edit_uint64_with_commas (uint64_t val, char *buf); -char * add_commas (char *val, char *buf); -char * edit_uint64 (uint64_t val, char *buf); -int do_shell_expansion (char *name); -int is_a_number (const char *num); -int string_to_btime (char *str, btime_t *value); -char *edit_btime (btime_t val, char *buf); -void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); -void pm_strcat (POOLMEM **pm, char *str); -void pm_strcpy (POOLMEM **pm, char *str); -int run_program (char *prog, int wait, POOLMEM *results); -char * job_type_to_str (int type); -char * job_status_to_str (int stat); -char * job_level_to_str (int level); +void lcase (char *str); +void bash_spaces (char *str); +void unbash_spaces (char *str); +void strip_trailing_junk (char *str); +void strip_trailing_slashes (char *dir); +int skip_spaces (char **msg); +int skip_nonspaces (char **msg); +int fstrsch (char *a, char *b); +char * encode_time (time_t time, char *buf); +char * encode_mode (mode_t mode, char *buf); +char * edit_uint64_with_commas (uint64_t val, char *buf); +char * add_commas (char *val, char *buf); +char * edit_uint64 (uint64_t val, char *buf); +int do_shell_expansion (char *name); +int is_a_number (const char *num); +int string_to_btime (char *str, btime_t *value); +char *edit_btime (btime_t val, char *buf); +void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); +void pm_strcat (POOLMEM **pm, char *str); +void pm_strcpy (POOLMEM **pm, char *str); +int run_program (char *prog, int wait, POOLMEM *results); +char * job_type_to_str (int type); +char * job_status_to_str (int stat); +char * job_level_to_str (int level); /* - *void print_ls_output (char *fname, char *lname, int type, struct stat *statp); + *void print_ls_output (char *fname, char *lname, int type, struct stat *statp); */ /* watchdog.c */ diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 07a58ba813..f1a5be9ee2 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -18,16 +18,18 @@ first_rule: all dummy: # -SVRSRCS = stored.c append.c askdir.c authenticate.c block.c dev.c \ +SVRSRCS = stored.c acquire.c append.c askdir.c authenticate.c \ + block.c dev.c \ device.c dircmd.c fd_cmds.c fdmsg.c job.c \ label.c match_bsr.c parse_bsr.c \ - read.c record.c stored_conf.c -SVROBJS = stored.o append.o askdir.o authenticate.o block.o dev.o \ + read.c record.c stored_conf.c mount.c +SVROBJS = stored.o acquire.o append.o askdir.o authenticate.o \ + block.o dev.o \ device.o dircmd.o fd_cmds.o fdmsg.o job.o \ - label.o match_bsr.o parse_bsr.o \ - read.o record.o stored_conf.o + label.o match_bsr.o mount.o parse_bsr.o \ + read.o record.o stored_conf.o -# bpool is depricated +# bpool is deprecated #POOLSRCS = bpool.c block.c dev.c device.c askdir.c label.c \ # record.c stored_conf.c #POOLOBJS = bpool.o block.o dev.o device.o askdir.o label.o \ @@ -35,17 +37,18 @@ SVROBJS = stored.o append.o askdir.o authenticate.o block.o dev.o \ # TAPESRCS = btape.c block.c dev.c device.c askdir.c label.c \ - record.c stored_conf.c + acquire.c mount.c record.c stored_conf.c TAPEOBJS = btape.o block.o dev.o device.o askdir.o label.o \ - record.o stored_conf.o + acquire.o mount.o record.o stored_conf.o BLSOBJS = bls.o block.o device.o dev.o label.o match_bsr.o \ - parse_bsr.o record.o + acquire.o mount.o parse_bsr.o record.o BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \ - match_bsr.o parse_bsr.o + acquire.o mount.o match_bsr.o parse_bsr.o -SCNOBJS = bscan.o block.o device.o dev.o askdir.o label.o record.o +SCNOBJS = bscan.o block.o device.o dev.o askdir.o label.o \ + acquire.o mount.o record.o match_bsr.o parse_bsr.o diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c new file mode 100644 index 0000000000..0433fbdea0 --- /dev/null +++ b/bacula/src/stored/acquire.c @@ -0,0 +1,242 @@ +/* + * Routines to acquire and release a device for read/write + * + * Kern Sibbald, August MMII + * + * Version $Id$ + */ +/* + Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + + 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" /* pull in global headers */ +#include "stored.h" /* pull in Storage Deamon headers */ + + +/********************************************************************* + * Acquire device for reading. We permit (for the moment) + * only one reader. We read the Volume label from the block and + * leave the block pointers just after the label. + * + * Returns: 0 if failed for any reason + * 1 if successful + */ +int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +{ + int stat; + + lock_device(dev); + if (dev->state & ST_READ || dev->num_writers > 0) { + Jmsg(jcr, M_FATAL, 0, _("Device %s is busy.\n"), dev_name(dev)); + unlock_device(dev); + return 0; + } + dev->state &= ~ST_LABEL; /* force reread of label */ + block_device(dev, BST_DOING_ACQUIRE); + unlock_device(dev); + stat = ready_dev_for_read(jcr, dev, block); + P(dev->mutex); + unblock_device(dev); + V(dev->mutex); + return stat; +} + +/* + * Acquire device for writing. We permit multiple writers. + * If this is the first one, we read the label. + * + * Returns: 0 if failed for any reason + * 1 if successful + */ +int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +{ + int release = 0; + int do_mount = 0; + + lock_device(dev); + Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk"); + + + if (dev->state & ST_APPEND) { + /* + * Device already in append mode + * + * Check if we have the right Volume mounted + * OK if AnonVols and volume info OK + * OK if next volume matches current volume + * otherwise mount desired volume obtained from + * dir_find_next_appendable_volume + */ + strcpy(jcr->VolumeName, dev->VolHdr.VolName); + if (((dev->capabilities & CAP_ANONVOLS) && + !dir_get_volume_info(jcr)) || + (!dir_find_next_appendable_volume(jcr) || + strcmp(dev->VolHdr.VolName, jcr->VolumeName) != 0)) { /* wrong tape mounted */ + if (dev->num_writers != 0) { + Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing with another Volume.\n"), dev_name(dev)); + unlock_device(dev); + return 0; + } + /* Wrong tape mounted, release it, then fall through to get correct one */ + release = 1; + do_mount = 1; + } + } else { + /* Not already in append mode, so mount the device */ + if (dev->state & ST_READ) { + Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev)); + unlock_device(dev); + return 0; + } + ASSERT(dev->num_writers == 0); + do_mount = 1; + } + + if (do_mount) { + block_device(dev, BST_DOING_ACQUIRE); + unlock_device(dev); + if (!mount_next_write_volume(jcr, dev, block, release)) { + Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), + dev_name(dev)); + P(dev->mutex); + unblock_device(dev); + unlock_device(dev); + return 0; + } + P(dev->mutex); + unblock_device(dev); + } + + dev->num_writers++; + if (dev->num_writers > 1) { + Dmsg2(0, "Hey!!!! There are %d writers on device %s\n", dev->num_writers, + dev_name(dev)); + } + if (jcr->NumVolumes == 0) { + jcr->NumVolumes = 1; + } + attach_jcr_to_device(dev, jcr); /* attach jcr to device */ + unlock_device(dev); + return 1; /* got it */ +} + +/* + * This job is done, so release the device. From a Unix standpoint, + * the device remains open. + * + */ +int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +{ + P(dev->mutex); + Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk"); + if (dev->state & ST_READ) { + dev->state &= ~ST_READ; /* clear read bit */ + if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) { + if (dev->capabilities & CAP_OFFLINEUNMOUNT) { + offline_dev(dev); + } + close_dev(dev); + } + /******FIXME**** send read volume usage statistics to director */ + + } else if (dev->num_writers > 0) { + dev->num_writers--; + Dmsg1(00, "There are %d writers in release_device\n", dev->num_writers); + if (dev->num_writers == 0) { + weof_dev(dev, 1); + Dmsg0(100, "dir_create_jobmedia_record. Release\n"); + dir_create_jobmedia_record(jcr); + dev->VolCatInfo.VolCatFiles++; /* increment number of files */ + /* Note! do volume update before close, which zaps VolCatInfo */ + Dmsg0(100, "dir_update_vol_info. Release\n"); + dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */ + + if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) { + if (dev->capabilities & CAP_OFFLINEUNMOUNT) { + offline_dev(dev); + } + close_dev(dev); + } + } else { + Dmsg0(100, "dir_create_jobmedia_record. Release\n"); + dir_create_jobmedia_record(jcr); + Dmsg0(100, "dir_update_vol_info. Release\n"); + dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */ + } + } else { + Jmsg1(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s not in use.\n"), dev_name(dev)); + } + detach_jcr_from_device(dev, jcr); + V(dev->mutex); + return 1; +} + + + +/* + * This routine ensures that the device is ready for + * reading. If it is a file, it opens it. + * If it is a tape, it checks the volume name + * + * Returns 0 on failure + * Returns 1 on success + */ +int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +{ + if (!(dev->state & ST_OPENED)) { + Dmsg1(120, "bstored: open vol=%s\n", jcr->VolumeName); + if (open_dev(dev, jcr->VolumeName, READ_ONLY) < 0) { + Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"), + dev_name(dev), jcr->VolumeName, strerror_dev(dev)); + return 0; + } + Dmsg1(129, "open_dev %s OK\n", dev_name(dev)); + } + + for (;;) { + if (job_cancelled(jcr)) { + Mmsg0(&dev->errmsg, _("Job cancelled.\n")); + return 0; + } + if (!rewind_dev(dev)) { + Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + } + switch (read_dev_volume_label(jcr, dev, block)) { + case VOL_OK: + break; /* got it */ + default: + /* Send error message generated by read_dev_volume_label() */ + Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + if (!rewind_dev(dev)) { + Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + } + /* Mount a specific volume and no other */ + if (!dir_ask_sysop_to_mount_volume(jcr, dev)) { + return 0; /* error return */ + } + continue; /* try reading again */ + } + break; + } + + dev->state |= ST_READ; + return 1; +} diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index 20b6bfedaa..e1c8efd396 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -60,7 +60,6 @@ int do_append_data(JCR *jcr) // jcr->spool_attributes = 1; jcr->no_attributes = 1; #endif - jcr->spool_attributes = 1; if (!jcr->no_attributes && jcr->spool_attributes) { open_spool_file(jcr, jcr->dir_bsock); diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index f286a7c62d..d6b8de9605 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -45,6 +45,9 @@ static FF_PKT *ff = &my_ff; static BSR *bsr = NULL; +static DEV_RECORD *rec; +static DEV_BLOCK *block; + static void usage() { fprintf(stderr, @@ -162,8 +165,6 @@ static void do_extract(char *devname, char *where) int type; long record_file_index; long total = 0; - DEV_RECORD rec; - DEV_BLOCK *block; POOLMEM *fname; /* original file name */ POOLMEM *ofile; /* output name with prefix */ POOLMEM *lname; /* link name */ @@ -217,58 +218,29 @@ static void do_extract(char *devname, char *where) return; } - memset(&rec, 0, sizeof(rec)); - rec.data = get_memory(70000); + rec = new_record(); + free_pool_memory(rec->data); + rec->data = get_memory(70000); uint32_t compress_buf_size = 70000; POOLMEM *compress_buf = get_memory(compress_buf_size); for ( ;; ) { - int ok; - DEV_RECORD *record; /* for reading label of multi-volumes */ - - if (!read_record(dev, block, &rec)) { + if (!read_block_from_device(dev, block)) { uint32_t status; - Dmsg1(500, "Main read record failed. rem=%d\n", rec.remainder); + Dmsg1(500, "Main read record failed. rem=%d\n", rec->remainder); if (dev->state & ST_EOT) { - if (rec.remainder) { - Dmsg0(500, "Not end of record.\n"); - } - Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume); - /* - * End Of Tape -- mount next Volume (if another specified) - */ - if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) { - VOL_LIST *vol = jcr->VolList; - /* Find next Volume */ - jcr->CurVolume++; - for (int i=1; iCurVolume; i++) { - vol = vol->next; - } - strcpy(jcr->VolumeName, vol->VolumeName); - Dmsg1(400, "There is another volume %s.\n", jcr->VolumeName); - - close_dev(dev); - dev->state &= ~ST_READ; - if (!acquire_device_for_read(jcr, dev, block)) { - Emsg2(M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), - jcr->VolumeName); - ok = FALSE; - break; - } - record = new_record(); - Dmsg1(500, "read record after new tape. rem=%d\n", record->remainder); - read_record(dev, block, record); /* read vol label */ - dump_label_record(dev, record, 0); - free_record(record); - continue; + if (!mount_next_read_volume(jcr, dev, block)) { + break; } - Dmsg0(90, "End of Device reached.\n"); - break; /* End of Tape */ + continue; } if (dev->state & ST_EOF) { continue; /* try again */ } + if (dev->state & ST_SHORT) { + continue; + } Pmsg0(0, "Read Record got a bad record\n"); status_dev(dev, &status); Dmsg1(20, "Device status: %x\n", status); @@ -287,209 +259,219 @@ static void do_extract(char *devname, char *where) status, dev_name(dev), strerror(errno)); } - - /* This is no longer used */ - if (rec.VolSessionId == 0 && rec.VolSessionTime == 0) { - Emsg0(M_ERROR, 0, "Zero header record. This shouldn't happen.\n"); - break; /* END OF FILE */ - } - - /* - * Check for Start or End of Session Record - * - */ - if (rec.FileIndex < 0) { - char *rtype; - memset(&sessrec, 0, sizeof(sessrec)); - switch (rec.FileIndex) { - case PRE_LABEL: - rtype = "Fresh Volume Label"; - break; - case VOL_LABEL: - rtype = "Volume Label"; - unser_volume_label(dev, &rec); - break; - case SOS_LABEL: - rtype = "Begin Session"; - unser_session_label(&sessrec, &rec); - break; - case EOS_LABEL: - rtype = "End Session"; - break; - case EOM_LABEL: - rtype = "End of Media"; - break; - default: - rtype = "Unknown"; - break; - } - if (debug_level > 0) { - printf("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", - rtype, rec.VolSessionId, rec.VolSessionTime, rec.Stream, rec.data_len); + for (rec->state=0; !is_block_empty(rec); ) { + if (!read_record_from_block(block, rec)) { + break; } - Dmsg1(40, "Got label = %d\n", rec.FileIndex); - if (rec.FileIndex == EOM_LABEL) { /* end of tape? */ - Dmsg0(40, "Get EOM LABEL\n"); - break; /* yes, get out */ + /* This is no longer used */ + if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) { + Emsg0(M_ERROR, 0, "Zero header record. This shouldn't happen.\n"); + break; /* END OF FILE */ } - continue; /* ignore other labels */ - } /* end if label record */ - - /* Is this the file we want? */ - if (bsr && !match_bsr(bsr, &rec, &dev->VolHdr, &sessrec)) { - continue; - } - /* File Attributes stream */ - if (rec.Stream == STREAM_UNIX_ATTRIBUTES) { - char *ap, *lp, *fp; - - /* If extracting, it was from previous stream, so - * close the output file. + /* + * Check for Start or End of Session Record + * */ - if (extract) { - if (ofd < 0) { - Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); + if (rec->FileIndex < 0) { + char *rtype; + memset(&sessrec, 0, sizeof(sessrec)); + switch (rec->FileIndex) { + case PRE_LABEL: + rtype = "Fresh Volume Label"; + break; + case VOL_LABEL: + rtype = "Volume Label"; + unser_volume_label(dev, rec); + break; + case SOS_LABEL: + rtype = "Begin Session"; + unser_session_label(&sessrec, rec); + break; + case EOS_LABEL: + rtype = "End Session"; + break; + case EOM_LABEL: + rtype = "End of Media"; + break; + default: + rtype = "Unknown"; + break; + } + if (debug_level > 0) { + printf("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", + rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); } - close(ofd); - ofd = -1; - extract = FALSE; - set_statp(jcr, fname, ofile, lname, type, &statp); - } - if (sizeof_pool_memory(fname) < rec.data_len) { - fname = realloc_pool_memory(fname, rec.data_len + 1); - } - if (sizeof_pool_memory(ofile) < sizeof_pool_memory(fname) + wherelen + 1) { - ofile = realloc_pool_memory(ofile, sizeof_pool_memory(fname) + wherelen + 1); - } - if (sizeof_pool_memory(lname) < rec.data_len) { - ofile = realloc_pool_memory(ofile, rec.data_len + 1); + Dmsg1(40, "Got label = %d\n", rec->FileIndex); + if (rec->FileIndex == EOM_LABEL) { /* end of tape? */ + Dmsg0(40, "Get EOM LABEL\n"); + break; /* yes, get out */ + } + continue; /* ignore other labels */ + } /* end if label record */ + + /* Is this the file we want? */ + if (bsr && !match_bsr(bsr, rec, &dev->VolHdr, &sessrec)) { + rec->remainder = 0; + continue; } - *fname = 0; - *lname = 0; - - /* - * An Attributes record consists of: - * File_index - * Type (FT_types) - * Filename - * Attributes - * Link name (if file linked i.e. FT_LNK) - * - */ - sscanf(rec.data, "%ld %d", &record_file_index, &type); - if (record_file_index != rec.FileIndex) - Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", - rec.FileIndex, record_file_index); - ap = rec.data; - while (*ap++ != ' ') /* skip record file index */ - ; - while (*ap++ != ' ') /* skip type */ - ; - /* Save filename and position to attributes */ - fp = fname; - while (*ap != 0) { - *fp++ = *ap++; + if (is_partial_record(rec)) { + break; } - *fp = *ap++; /* terminate filename & point to attribs */ - /* Skip to Link name */ - if (type == FT_LNK) { - lp = ap; - while (*lp++ != 0) { - ; + /* File Attributes stream */ + if (rec->Stream == STREAM_UNIX_ATTRIBUTES) { + char *ap, *lp, *fp; + + /* If extracting, it was from previous stream, so + * close the output file. + */ + if (extract) { + if (ofd < 0) { + Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); + } + close(ofd); + ofd = -1; + extract = FALSE; + set_statp(jcr, fname, ofile, lname, type, &statp); } - strcat(lname, lp); /* "save" link name */ - } else { - *lname = 0; - } - - if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { + if (sizeof_pool_memory(fname) < rec->data_len) { + fname = realloc_pool_memory(fname, rec->data_len + 1); + } + if (sizeof_pool_memory(ofile) < sizeof_pool_memory(fname) + wherelen + 1) { + ofile = realloc_pool_memory(ofile, sizeof_pool_memory(fname) + wherelen + 1); + } + if (sizeof_pool_memory(lname) < rec->data_len) { + lname = realloc_pool_memory(lname, rec->data_len + 1); + } + *fname = 0; + *lname = 0; - decode_stat(ap, &statp); - /* - * Prepend the where directory so that the - * files are put where the user wants. + /* + * An Attributes record consists of: + * File_index + * Type (FT_types) + * Filename + * Attributes + * Link name (if file linked i.e. FT_LNK) * - * We do a little jig here to handle Win32 files with - * a drive letter. - * If where is null and we are running on a win32 client, - * change nothing. - * Otherwise, if the second character of the filename is a - * colon (:), change it into a slash (/) -- this creates - * a reasonable pathname on most systems. */ - strcpy(ofile, where); - if (fname[1] == ':') { - fname[1] = '/'; - strcat(ofile, fname); - fname[1] = ':'; + sscanf(rec->data, "%ld %d", &record_file_index, &type); + if (record_file_index != rec->FileIndex) + Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", + rec->FileIndex, record_file_index); + ap = rec->data; + while (*ap++ != ' ') /* skip record file index */ + ; + while (*ap++ != ' ') /* skip type */ + ; + /* Save filename and position to attributes */ + fp = fname; + while (*ap != 0) { + *fp++ = *ap++; + } + *fp = *ap++; /* terminate filename & point to attribs */ + + /* Skip to Link name */ + if (type == FT_LNK) { + lp = ap; + while (*lp++ != 0) { + ; + } + strcat(lname, lp); /* "save" link name */ } else { - strcat(ofile, fname); + *lname = 0; } -/* Pmsg1(000, "Restoring: %s\n", ofile); */ - extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd); + + if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { + + decode_stat(ap, &statp); + /* + * Prepend the where directory so that the + * files are put where the user wants. + * + * We do a little jig here to handle Win32 files with + * a drive letter. + * If where is null and we are running on a win32 client, + * change nothing. + * Otherwise, if the second character of the filename is a + * colon (:), change it into a slash (/) -- this creates + * a reasonable pathname on most systems. + */ + strcpy(ofile, where); + if (fname[1] == ':') { + fname[1] = '/'; + strcat(ofile, fname); + fname[1] = ':'; + } else { + strcat(ofile, fname); + } + /* Pmsg1(000, "Restoring: %s\n", ofile); */ - if (extract) { - print_ls_output(ofile, lname, type, &statp); + extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd); + + if (extract) { + print_ls_output(ofile, lname, type, &statp); + } } - } - /* Data stream and extracting */ - } else if (rec.Stream == STREAM_FILE_DATA) { - if (extract) { - total += rec.data_len; - Dmsg2(8, "Write %ld bytes, total=%ld\n", rec.data_len, total); - if ((uint32_t)write(ofd, rec.data, rec.data_len) != rec.data_len) { - Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno)); + /* Data stream and extracting */ + } else if (rec->Stream == STREAM_FILE_DATA) { + if (extract) { + total += rec->data_len; + Dmsg2(8, "Write %ld bytes, total=%ld\n", rec->data_len, total); + if ((uint32_t)write(ofd, rec->data, rec->data_len) != rec->data_len) { + Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno)); + } } - } - - } else if (rec.Stream == STREAM_GZIP_DATA) { + + } else if (rec->Stream == STREAM_GZIP_DATA) { #ifdef HAVE_LIBZ - if (extract) { - uLongf compress_len; + if (extract) { + uLongf compress_len; - compress_len = compress_buf_size; - if (uncompress((Bytef *)compress_buf, &compress_len, - (const Bytef *)rec.data, (uLong)rec.data_len) != Z_OK) { - Emsg0(M_ERROR_TERM, 0, _("Uncompression error.\n")); - } + compress_len = compress_buf_size; + if (uncompress((Bytef *)compress_buf, &compress_len, + (const Bytef *)rec->data, (uLong)rec->data_len) != Z_OK) { + Emsg0(M_ERROR_TERM, 0, _("Uncompression error.\n")); + } - Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total); - if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) { - Pmsg0(0, "===Write error===\n"); - Emsg2(M_ERROR_TERM, 0, "Write error on %s: %s\n", ofile, strerror(errno)); + Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total); + if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) { + Pmsg0(0, "===Write error===\n"); + Emsg2(M_ERROR_TERM, 0, "Write error on %s: %s\n", ofile, strerror(errno)); + } + total += compress_len; + Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len, + compress_len); } - total += compress_len; - Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec.data_len, - compress_len); - } #else - if (extract) { - Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n"); - } + if (extract) { + Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n"); + } #endif - /* If extracting, wierd stream (not 1 or 2), close output file anyway */ - } else if (extract) { - if (ofd < 0) { - Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); + /* If extracting, wierd stream (not 1 or 2), close output file anyway */ + } else if (extract) { + if (ofd < 0) { + Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n"); + } + close(ofd); + ofd = -1; + extract = FALSE; + set_statp(jcr, fname, ofile, lname, type, &statp); + } else if (rec->Stream != STREAM_MD5_SIGNATURE) { + Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data); } - close(ofd); - ofd = -1; - extract = FALSE; - set_statp(jcr, fname, ofile, lname, type, &statp); - } else if (rec.Stream != STREAM_MD5_SIGNATURE) { - Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec.Stream, rec.data); } } + /* If output file is still open, it was the last one in the * archive since we just hit an end of file, so close the file. */ @@ -505,6 +487,7 @@ static void do_extract(char *devname, char *where) free_pool_memory(compress_buf); term_dev(dev); free_block(block); + free_record(rec); return; } diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 6b59140e75..011e849588 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -224,6 +224,13 @@ static void my_free_jcr(JCR *jcr) static void do_setup(char *infname) { jcr = new_jcr(sizeof(JCR), my_free_jcr); + jcr->VolSessionId = 1; + jcr->VolSessionTime = (uint32_t)time(NULL); + jcr->bsr = bsr; + strcpy(jcr->Job, "bls"); + jcr->dev_name = get_pool_memory(PM_FNAME); + strcpy(jcr->dev_name, infname); + VolName = Vol; VolName[0] = 0; if (strncmp(infname, "/dev/", 5) != 0) { @@ -262,8 +269,7 @@ static void do_setup(char *infname) NumVolumes++; } - jcr->VolumeName = (char *)check_pool_memory_size(jcr->VolumeName, strlen(VolName)+1); - strcpy(jcr->VolumeName, VolName); + pm_strcpy(&jcr->VolumeName, VolName); if (!acquire_device_for_read(jcr, dev, block)) { Emsg0(M_ERROR, 0, dev->errmsg); exit(1); @@ -291,9 +297,7 @@ static int mount_next_volume(char *infname) CurVolume++; Dmsg1(20, "There is another volume %s.\n", p); VolName = p; - jcr->VolumeName = check_pool_memory_size(jcr->VolumeName, - strlen(VolName)+1); - strcpy(jcr->VolumeName, VolName); + pm_strcpy(&jcr->VolumeName, VolName); close_dev(dev); dev->state &= ~ST_READ; @@ -505,7 +509,7 @@ Warning, this Volume is a continuation of Volume %s\n", record = 0; for (rec->state=0; !is_block_empty(rec); ) { - if (!new_read_record_from_block(block, rec)) { + if (!read_record_from_block(block, rec)) { Dmsg2(30, "!read-break. stat=%s blk=%d\n", rec_state_to_str(rec), block->BlockNumber); break; diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 6c7720e41f..c5edb803cf 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -41,6 +41,7 @@ static void print_ls_output(char *fname, struct stat *statp); static DEVICE *dev = NULL; static B_DB *db; static JCR *jcr; +static BSR *bsr; static void usage() { @@ -64,8 +65,11 @@ int main (int argc, char *argv[]) init_msg(NULL, NULL); - while ((ch = getopt(argc, argv, "d:?")) != -1) { + while ((ch = getopt(argc, argv, "b:d:?")) != -1) { switch (ch) { + case 'b': + bsr = parse_bsr(NULL, optarg); + break; case 'd': /* debug level */ debug_level = atoi(optarg); if (debug_level <= 0) @@ -90,9 +94,13 @@ int main (int argc, char *argv[]) jcr->VolSessionId = 1; jcr->VolSessionTime = (uint32_t)time(NULL); jcr->NumVolumes = 1; + jcr->bsr = bsr; + strcpy(jcr->Job, "bscan"); + jcr->dev_name = get_pool_memory(PM_FNAME); + strcpy(jcr->dev_name, argv[0]); /* *** FIXME **** need to put in corect db, user, and password */ - if ((db=db_init_database("bacula", "bacula", "")) == NULL) { + if ((db=db_init_database(NULL, "bacula", "bacula", "")) == NULL) { Emsg0(M_ABORT, 0, "Could not init Bacula database\n"); } if (!db_open_database(db)) { @@ -115,11 +123,11 @@ static void do_scan(char *devname) struct stat statp; int type; long record_file_index; - DEV_RECORD rec; + DEV_RECORD *rec; DEV_BLOCK *block; - char *fname; /* original file name */ - char *ofile; /* output name with prefix */ - char *lname; /* link name */ + POOLMEM *fname; /* original file name */ + POOLMEM *ofile; /* output name with prefix */ + POOLMEM *lname; /* link name */ MEDIA_DBR mr; POOL_DBR pr; JOB_DBR jr; @@ -135,6 +143,7 @@ static void do_scan(char *devname) *p = 0; } } + strcpy(jcr->VolumeName, VolName); dev = init_dev(NULL, devname); if (!dev || !open_device(dev)) { @@ -142,33 +151,40 @@ static void do_scan(char *devname) } Dmsg0(90, "Device opened for read.\n"); - fname = (char *)get_pool_memory(PM_FNAME); - ofile = (char *)get_pool_memory(PM_FNAME); - lname = (char *)get_pool_memory(PM_FNAME); + fname = get_pool_memory(PM_FNAME); + ofile = get_pool_memory(PM_FNAME); + lname = get_pool_memory(PM_FNAME); block = new_block(dev); - - strcpy(jcr->VolumeName, VolName); + + create_vol_list(jcr); if (!acquire_device_for_read(jcr, dev, block)) { Emsg1(M_ABORT, 0, "Cannot open %s\n", devname); } - memset(&rec, 0, sizeof(rec)); - rec.data = (char *)get_memory(70000); + rec = new_record(); + free_pool_memory(rec->data); + rec->data = get_memory(70000); memset(&mr, 0, sizeof(mr)); memset(&pr, 0, sizeof(pr)); for ( ;; ) { - if (!read_record(dev, block, &rec)) { + if (!read_block_from_device(dev, block)) { uint32_t status; if (dev->state & ST_EOT) { - break; + if (!mount_next_read_volume(jcr, dev, block)) { + break; + } + continue; } if (dev->state & ST_EOF) { continue; /* try again */ } + if (dev->state & ST_SHORT) { + continue; + } Pmsg0(0, "Read Record got a bad record\n"); status_dev(dev, &status); Dmsg1(20, "Device status: %x\n", status); @@ -187,160 +203,181 @@ static void do_scan(char *devname) status, dev_name(dev), strerror(errno)); } + for (rec->state=0; !is_block_empty(rec); ) { + SESSION_LABEL label, elabel; + if (!read_record_from_block(block, rec)) { + break; + } - /* This is no longer used */ - if (rec.VolSessionId == 0 && rec.VolSessionTime == 0) { - Emsg0(M_ERROR, 0, "Zero header record. This shouldn't happen.\n"); - break; /* END OF FILE */ - } - - /* - * Check for Start or End of Session Record - * - */ - if (rec.FileIndex < 0) { - SESSION_LABEL label, elabel; - if (debug_level > 1) { - dump_label_record(dev, &rec, 1); - } - switch (rec.FileIndex) { - case PRE_LABEL: - Pmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n"); - return; - break; - case VOL_LABEL: - unser_volume_label(dev, &rec); - strcpy(mr.VolumeName, dev->VolHdr.VolName); - if (!db_get_media_record(db, &mr)) { - Pmsg1(000, "VOL_LABEL: Media record not found for Volume: %s\n", - mr.VolumeName); - continue; - } - if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) { - Pmsg2(000, "VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n", - mr.MediaType, dev->VolHdr.MediaType); - continue; - } - strcpy(pr.Name, dev->VolHdr.PoolName); - if (!db_get_pool_record(db, &pr)) { - Pmsg1(000, "VOL_LABEL: Pool record not found for Pool: %s\n", - pr.Name); - continue; - } - if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) { - Pmsg2(000, "VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n", - pr.PoolType, dev->VolHdr.PoolType); - continue; - } - Pmsg1(000, "VOL_LABEL: OK for Volume: %s\n", mr.VolumeName); - break; - case SOS_LABEL: - unser_session_label(&label, &rec); - memset(&jr, 0, sizeof(jr)); - jr.JobId = label.JobId; - if (!db_get_job_record(db, &jr)) { - Pmsg1(000, "SOS_LABEL: Job record not found for JobId: %d\n", - jr.JobId); - continue; - } - if (rec.VolSessionId != jr.VolSessionId) { - Pmsg2(000, "SOS_LABEL: VolSessId mismatch. DB=%d Vol=%d\n", - jr.VolSessionId, rec.VolSessionId); - continue; - } - if (rec.VolSessionTime != jr.VolSessionTime) { - Pmsg2(000, "SOS_LABEL: VolSessTime mismatch. DB=%d Vol=%d\n", - jr.VolSessionTime, rec.VolSessionTime); - continue; - } - if (jr.PoolId != pr.PoolId) { - Pmsg2(000, "SOS_LABEL: PoolId mismatch. DB=%d Vol=%d\n", - jr.PoolId, pr.PoolId); - continue; - } - break; - case EOS_LABEL: - unser_session_label(&elabel, &rec); - if (elabel.JobId != label.JobId) { - Pmsg2(000, "EOS_LABEL: Start/End JobId mismatch. Start=%d End=%d\n", - label.JobId, elabel.JobId); - continue; - } - if (elabel.JobFiles != jr.JobFiles) { - Pmsg2(000, "EOS_LABEL: JobFiles mismatch. DB=%d EOS=%d\n", - jr.JobFiles, elabel.JobFiles); - continue; - } - if (elabel.JobBytes != jr.JobBytes) { - Pmsg2(000, "EOS_LABEL: JobBytes mismatch. DB=%d EOS=%d\n", - jr.JobBytes, elabel.JobBytes); - continue; - } - Pmsg1(000, "EOS_LABEL: OK for JobId=%d\n", elabel.JobId); - break; - case EOM_LABEL: - break; - default: - break; + /* This is no longer used */ + if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) { + Emsg0(M_ERROR, 0, "Zero header record. This shouldn't happen.\n"); + break; /* END OF FILE */ } - continue; - } - /* File Attributes stream */ - if (rec.Stream == STREAM_UNIX_ATTRIBUTES) { - char *ap, *lp; + /* + * Check for Start or End of Session Record + * + */ + if (rec->FileIndex < 0) { - if (sizeof_pool_memory(fname) < rec.data_len) { - fname = (char *)realloc_pool_memory(fname, rec.data_len + 1); + if (debug_level > 1) { + dump_label_record(dev, rec, 1); + } + switch (rec->FileIndex) { + case PRE_LABEL: + Pmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n"); + return; + break; + case VOL_LABEL: + unser_volume_label(dev, rec); + strcpy(mr.VolumeName, dev->VolHdr.VolName); + if (!db_get_media_record(db, &mr)) { + Pmsg1(000, "VOL_LABEL: Media record not found for Volume: %s\n", + mr.VolumeName); + continue; + } + if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) { + Pmsg2(000, "VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n", + mr.MediaType, dev->VolHdr.MediaType); + continue; + } + strcpy(pr.Name, dev->VolHdr.PoolName); + if (!db_get_pool_record(db, &pr)) { + Pmsg1(000, "VOL_LABEL: Pool record not found for Pool: %s\n", + pr.Name); + continue; + } + if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) { + Pmsg2(000, "VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n", + pr.PoolType, dev->VolHdr.PoolType); + continue; + } + Pmsg1(000, "VOL_LABEL: OK for Volume: %s\n", mr.VolumeName); + break; + case SOS_LABEL: + unser_session_label(&label, rec); + memset(&jr, 0, sizeof(jr)); + jr.JobId = label.JobId; + if (!db_get_job_record(db, &jr)) { + Pmsg1(000, "SOS_LABEL: Job record not found for JobId: %d\n", + jr.JobId); + continue; + } + if (rec->VolSessionId != jr.VolSessionId) { + Pmsg2(000, "SOS_LABEL: VolSessId mismatch. DB=%d Vol=%d\n", + jr.VolSessionId, rec->VolSessionId); + continue; + } + if (rec->VolSessionTime != jr.VolSessionTime) { + Pmsg2(000, "SOS_LABEL: VolSessTime mismatch. DB=%d Vol=%d\n", + jr.VolSessionTime, rec->VolSessionTime); + continue; + } + if (jr.PoolId != pr.PoolId) { + Pmsg2(000, "SOS_LABEL: PoolId mismatch. DB=%d Vol=%d\n", + jr.PoolId, pr.PoolId); + continue; + } + break; + case EOS_LABEL: + unser_session_label(&elabel, rec); + if (elabel.JobId != label.JobId) { + Pmsg2(000, "EOS_LABEL: Start/End JobId mismatch. Start=%d End=%d\n", + label.JobId, elabel.JobId); + continue; + } + if (elabel.JobFiles != jr.JobFiles) { + Pmsg2(000, "EOS_LABEL: JobFiles mismatch. DB=%d EOS=%d\n", + jr.JobFiles, elabel.JobFiles); + continue; + } + if (elabel.JobBytes != jr.JobBytes) { + Pmsg2(000, "EOS_LABEL: JobBytes mismatch. DB=%d EOS=%d\n", + jr.JobBytes, elabel.JobBytes); + continue; + } + Pmsg1(000, "EOS_LABEL: OK for JobId=%d\n", elabel.JobId); + break; + case EOM_LABEL: + break; + default: + break; + } + continue; } - if (sizeof_pool_memory(lname) < rec.data_len) { - ofile = (char *)realloc_pool_memory(ofile, rec.data_len + 1); + + /* Is this the file we want? */ + if (bsr && !match_bsr(bsr, rec, &dev->VolHdr, &label)) { + rec->remainder = 0; + continue; } - *fname = 0; - *lname = 0; - - /* - * An Attributes record consists of: - * File_index - * Type (FT_types) - * Filename - * Attributes - * Link name (if file linked i.e. FT_LNK) - * - */ - sscanf(rec.data, "%ld %d %s", &record_file_index, &type, fname); - if (record_file_index != rec.FileIndex) - Emsg2(M_ABORT, 0, "Record header file index %ld not equal record index %ld\n", - rec.FileIndex, record_file_index); - ap = rec.data; - /* Skip to attributes */ - while (*ap++ != 0) - ; - /* Skip to Link name */ - if (type == FT_LNK) { - lp = ap; - while (*lp++ != 0) { - ; + if (is_partial_record(rec)) { + break; + } + + /* File Attributes stream */ + if (rec->Stream == STREAM_UNIX_ATTRIBUTES) { + char *ap, *lp, *fp; + + if (sizeof_pool_memory(fname) < rec->data_len) { + fname = realloc_pool_memory(fname, rec->data_len + 1); } - strcat(lname, lp); /* "save" link name */ - } else { + if (sizeof_pool_memory(lname) < rec->data_len) { + lname = realloc_pool_memory(lname, rec->data_len + 1); + } + *fname = 0; *lname = 0; - } + /* + * An Attributes record consists of: + * File_index + * Type (FT_types) + * Filename + * Attributes + * Link name (if file linked i.e. FT_LNK) + * + */ + sscanf(rec->data, "%ld %d", &record_file_index, &type); + if (record_file_index != rec->FileIndex) + Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", + rec->FileIndex, record_file_index); + ap = rec->data; + while (*ap++ != ' ') /* skip record file index */ + ; + while (*ap++ != ' ') /* skip type */ + ; + /* Save filename and position to attributes */ + fp = fname; + while (*ap != 0) { + *fp++ = *ap++; + } + *fp = *ap++; /* terminate filename & point to attribs */ - decode_stat(ap, &statp); -/* Dmsg1(000, "Restoring: %s\n", ofile); */ + /* Skip through attributes to link name */ + if (type == FT_LNK) { + lp = ap; + while (*lp++ != 0) { + ; + } + strcat(lname, lp); /* "save" link name */ + } else { + *lname = 0; + } - if (debug_level > 1) { - print_ls_output(fname, &statp); - } + decode_stat(ap, &statp); - /* Data stream and extracting */ - } else if (rec.Stream == STREAM_FILE_DATA) { + if (debug_level > 1) { + print_ls_output(fname, &statp); + } + + /* Data stream and extracting */ + } else if (rec->Stream == STREAM_FILE_DATA) { - } else if (rec.Stream != STREAM_MD5_SIGNATURE) { - Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec.Stream, rec.data); + } else if (rec->Stream != STREAM_MD5_SIGNATURE) { + Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data); + } } } @@ -351,6 +388,7 @@ static void do_scan(char *devname) free_pool_memory(lname); term_dev(dev); free_block(block); + free_record(rec); return; } diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index bf3bcc4875..4f21e2fdb6 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -52,557 +52,10 @@ #include "stored.h" /* pull in Storage Deamon headers */ /* Forward referenced functions */ -static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *label_blk, int release); -static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd); extern char my_name[]; extern int debug_level; - -/********************************************************************* - * Acquire device for reading. We permit (for the moment) - * only one reader. We read the Volume label from the block and - * leave the block pointers just after the label. - * - * Returns: 0 if failed for any reason - * 1 if successful - */ -int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) -{ - int stat; - - lock_device(dev); - if (dev->state & ST_READ || dev->num_writers > 0) { - Jmsg(jcr, M_FATAL, 0, _("Device %s is busy.\n"), dev_name(dev)); - unlock_device(dev); - return 0; - } - dev->state &= ~ST_LABEL; /* force reread of label */ - block_device(dev, BST_DOING_ACQUIRE); - unlock_device(dev); - stat = ready_dev_for_read(jcr, dev, block); - P(dev->mutex); - unblock_device(dev); - V(dev->mutex); - return stat; -} - -/* - * Acquire device for writing. We permit multiple writers. - * If this is the first one, we read the label. - * - * Returns: 0 if failed for any reason - * 1 if successful - */ -int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) -{ - int release = 0; - int do_mount = 0; - - lock_device(dev); - Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk"); - - - if (dev->state & ST_APPEND) { - /* - * Device already in append mode - * - * Check if we have the right Volume mounted - * OK if AnonVols and volume info OK - * OK if next volume matches current volume - * otherwise mount desired volume obtained from - * dir_find_next_appendable_volume - */ - strcpy(jcr->VolumeName, dev->VolHdr.VolName); - if (((dev->capabilities & CAP_ANONVOLS) && - !dir_get_volume_info(jcr)) || - (!dir_find_next_appendable_volume(jcr) || - strcmp(dev->VolHdr.VolName, jcr->VolumeName) != 0)) { /* wrong tape mounted */ - if (dev->num_writers != 0) { - Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing with another Volume.\n"), dev_name(dev)); - unlock_device(dev); - return 0; - } - /* Wrong tape mounted, release it, then fall through to get correct one */ - release = 1; - do_mount = 1; - } - } else { - /* Not already in append mode, so mount the device */ - if (dev->state & ST_READ) { - Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev)); - unlock_device(dev); - return 0; - } - ASSERT(dev->num_writers == 0); - do_mount = 1; - } - - if (do_mount) { - block_device(dev, BST_DOING_ACQUIRE); - unlock_device(dev); - if (!mount_next_volume(jcr, dev, block, release)) { - Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), - dev_name(dev)); - P(dev->mutex); - unblock_device(dev); - unlock_device(dev); - return 0; - } - P(dev->mutex); - unblock_device(dev); - } - - dev->num_writers++; - if (dev->num_writers > 1) { - Dmsg2(0, "Hey!!!! There are %d writers on device %s\n", dev->num_writers, - dev_name(dev)); - } - if (jcr->NumVolumes == 0) { - jcr->NumVolumes = 1; - } - attach_jcr_to_device(dev, jcr); /* attach jcr to device */ - unlock_device(dev); - return 1; /* got it */ -} - -/* - * This job is done, so release the device. From a Unix standpoint, - * the device remains open. - * - */ -int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) -{ - P(dev->mutex); - Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk"); - if (dev->state & ST_READ) { - dev->state &= ~ST_READ; /* clear read bit */ - if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) { - if (dev->capabilities & CAP_OFFLINEUNMOUNT) { - offline_dev(dev); - } - close_dev(dev); - } - /******FIXME**** send read volume usage statistics to director */ - - } else if (dev->num_writers > 0) { - dev->num_writers--; - Dmsg1(00, "There are %d writers in release_device\n", dev->num_writers); - if (dev->num_writers == 0) { - weof_dev(dev, 1); - Dmsg0(100, "dir_create_jobmedia_record. Release\n"); - dir_create_jobmedia_record(jcr); - dev->VolCatInfo.VolCatFiles++; /* increment number of files */ - /* Note! do volume update before close, which zaps VolCatInfo */ - Dmsg0(100, "dir_update_vol_info. Release\n"); - dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */ - - if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) { - if (dev->capabilities & CAP_OFFLINEUNMOUNT) { - offline_dev(dev); - } - close_dev(dev); - } - } else { - Dmsg0(100, "dir_create_jobmedia_record. Release\n"); - dir_create_jobmedia_record(jcr); - Dmsg0(100, "dir_update_vol_info. Release\n"); - dir_update_volume_info(jcr, &dev->VolCatInfo, 0); /* send Volume info to Director */ - } - } else { - Jmsg1(jcr, M_ERROR, 0, _("BAD ERROR: release_device %s not in use.\n"), dev_name(dev)); - } - detach_jcr_from_device(dev, jcr); - V(dev->mutex); - return 1; -} - - - -/* - * If release is set, we rewind the current volume, - * which we no longer want, and ask the user (console) - * to mount the next volume. - * - * Continue trying until we get it, and then ensure - * that we can write on it. - * - * This routine returns a 0 only if it is REALLY - * impossible to get the requested Volume. - */ -static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release) -{ - int recycle, ask, retry = 0, autochanger; - - Dmsg0(190, "Enter mount_next_volume()\n"); - -mount_next_vol: - if (retry++ > 5) { - Jmsg(jcr, M_FATAL, 0, _("Too many errors on device %s.\n"), dev_name(dev)); - return 0; - } - if (job_cancelled(jcr)) { - Jmsg(jcr, M_FATAL, 0, _("Job cancelled.\n")); - return 0; - } - recycle = ask = autochanger = 0; - if (release) { - Dmsg0(500, "mount_next_volume release=1\n"); - /* - * First erase all memory of the current volume - */ - dev->block_num = 0; - dev->file = 0; - dev->LastBlockNumWritten = 0; - memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); - memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); - dev->state &= ~ST_LABEL; /* label not yet read */ - - if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) { - if (dev->capabilities & CAP_OFFLINEUNMOUNT) { - offline_dev(dev); - } - close_dev(dev); - } - - /* If we have not closed the device, then at least rewind the tape */ - if (dev->state & ST_OPENED) { - if (dev->capabilities & CAP_OFFLINEUNMOUNT) { - offline_dev(dev); - } - if (!rewind_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - } - } - ask = 1; /* ask operator to mount tape */ - } else { - /* - * Get Director's idea of what tape we should have mounted. - */ - if (!dir_find_next_appendable_volume(jcr)) { - ask = 1; /* we must ask */ - } - } - release = 1; /* release if we "recurse" */ - - /* - * Get next volume and ready it for append - * This code ensures that the device is ready for - * writing. We start from the assumption that there - * may not be a tape mounted. - * - * If the device is a file, we create the output - * file. If it is a tape, we check the volume name - * and move the tape to the end of data. - * - * It assumes that the device is not already in use! - * - */ - - Dmsg0(100, "Enter ready_dev_for_append\n"); - - dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); - - jcr->VolFirstFile = jcr->JobFiles; /* first update of Vol FileIndex */ - for ( ;; ) { - int slot = jcr->VolCatInfo.Slot; - - /* - * Handle autoloaders here. If we cannot autoload it, we - * will fall through to ask the sysop. - */ - if (dev->capabilities && CAP_AUTOCHANGER && slot <= 0) { - if (dir_find_next_appendable_volume(jcr)) { - slot = jcr->VolCatInfo.Slot; - } - } - Dmsg1(100, "Want changer slot=%d\n", slot); - - if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) { - uint32_t timeout = jcr->device->max_changer_wait; - POOLMEM *changer, *results; - int status, loaded; - - results = get_pool_memory(PM_MESSAGE); - changer = get_pool_memory(PM_FNAME); - /* Find out what is loaded */ - changer = edit_device_codes(jcr, changer, jcr->device->changer_command, - "loaded"); - status = run_program(changer, timeout, results); - if (status == 0) { - loaded = atoi(results); - } else { - loaded = -1; /* force unload */ - } - Dmsg1(100, "loaded=%s\n", results); - - /* If bad status or tape we want is not loaded, load it. */ - if (status != 0 || loaded != slot) { - if (dev->capabilities & CAP_OFFLINEUNMOUNT) { - offline_dev(dev); - } - /* We are going to load a new tape, so close the device */ - force_close_dev(dev); - if (loaded != 0) { /* must unload drive */ - Dmsg0(100, "Doing changer unload.\n"); - changer = edit_device_codes(jcr, changer, - jcr->device->changer_command, "unload"); - status = run_program(changer, timeout, NULL); - Dmsg1(100, "unload status=%d\n", status); - } - /* - * Load the desired cassette - */ - Dmsg1(100, "Doing changer load slot %d\n", slot); - changer = edit_device_codes(jcr, changer, - jcr->device->changer_command, "load"); - status = run_program(changer, timeout, NULL); - Dmsg2(100, "load slot %d status=%d\n", slot, status); - } - free_pool_memory(changer); - free_pool_memory(results); - Dmsg1(100, "After changer, status=%d\n", status); - if (status == 0) { /* did we succeed? */ - ask = 0; /* yes, got vol, no need to ask sysop */ - autochanger = 1; /* tape loaded by changer */ - } - } - - - if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) { - return 0; /* error return */ - } - Dmsg1(200, "want vol=%s\n", jcr->VolumeName); - - /* Open device */ - for ( ; !(dev->state & ST_OPENED); ) { - if (open_dev(dev, jcr->VolCatInfo.VolCatName, READ_WRITE) < 0) { - if (dev->dev_errno == EAGAIN || dev->dev_errno == EBUSY) { - sleep(30); - } - Jmsg2(jcr, M_FATAL, 0, _("Unable to open device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - return 0; - } - } - - /* - * Now make sure we have the right tape mounted - */ -read_volume: - switch (read_dev_volume_label(jcr, dev, block)) { - case VOL_OK: - Dmsg1(500, "Vol OK name=%s\n", jcr->VolumeName); - memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo)); - if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) { - recycle = 1; - } - break; /* got it */ - case VOL_NAME_ERROR: - Dmsg1(500, "Vol NAME Error Name=%s\n", jcr->VolumeName); - /* Check if we can accept this as an anonymous volume */ - strcpy(jcr->VolumeName, dev->VolHdr.VolName); - if (!dev->capabilities & CAP_ANONVOLS || !dir_get_volume_info(jcr)) { - goto mount_next_vol; - } - Dmsg1(200, "want new name=%s\n", jcr->VolumeName); - memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo)); - break; - - case VOL_NO_LABEL: - case VOL_IO_ERROR: - Dmsg1(500, "Vol NO_LABEL or IO_ERROR name=%s\n", jcr->VolumeName); - /* If permitted, create a label */ - if (dev->capabilities & CAP_LABEL) { - Dmsg0(190, "Create volume label\n"); - if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName, - jcr->pool_name)) { - goto mount_next_vol; - } - Jmsg(jcr, M_INFO, 0, _("Created Volume label %s on device %s.\n"), - jcr->VolumeName, dev_name(dev)); - goto read_volume; /* read label we just wrote */ - } - /* NOTE! Fall-through wanted. */ - default: - /* Send error message */ - Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); - if (autochanger) { - Jmsg(jcr, M_ERROR, 0, _("Autochanger Volume %s not found in slot %d.\n\ - Setting slot to zero in catalog.\n"), - jcr->VolumeName, jcr->VolCatInfo.Slot); - jcr->VolCatInfo.Slot = 0; /* invalidate slot */ - dir_update_volume_info(jcr, &jcr->VolCatInfo, 1); /* set slot */ - } - goto mount_next_vol; - } - break; - } - - /* - * See if we have a fresh tape or tape with data. - * - * Note, if the LabelType is PRE_LABEL, it was labeled - * but never written. If so, rewrite the label but set as - * VOL_LABEL. We rewind and return the label (reconstructed) - * in the block so that in the case of a new tape, data can - * be appended just after the block label. If we are writing - * an second volume, the calling routine will write the label - * before writing the overflow block. - * - * If the tape is marked as Recycle, we rewrite the label. - */ - if (dev->VolHdr.LabelType == PRE_LABEL || recycle) { - Dmsg1(190, "ready_for_append found freshly labeled volume. dev=%x\n", dev); - dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */ - write_volume_label_to_block(jcr, dev, block); - /* - * Write the block now to ensure we have write permission. - * It is better to find out now rather than later. - */ - dev->VolCatInfo.VolCatBytes = 0; - if (!rewind_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - } - if (recycle) { - if (!truncate_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - } - } - if (!write_block_to_dev(dev, block)) { - Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - goto mount_next_vol; - } - if (!rewind_dev(dev)) { - Jmsg2(jcr, M_ERROR, 0, _("Unable to rewind device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - goto mount_next_vol; - } - /* Recreate a correct volume label and return it in the block */ - write_volume_label_to_block(jcr, dev, block); - dev->VolCatInfo.VolCatJobs = 1; - dev->VolCatInfo.VolCatFiles = 1; - dev->VolCatInfo.VolCatErrors = 0; - dev->VolCatInfo.VolCatBlocks = 1; - if (recycle) { - dev->VolCatInfo.VolCatMounts++; - dev->VolCatInfo.VolCatRecycles++; - } else { - dev->VolCatInfo.VolCatMounts = 1; - dev->VolCatInfo.VolCatRecycles = 0; - dev->VolCatInfo.VolCatWrites = 1; - dev->VolCatInfo.VolCatReads = 1; - } - strcpy(dev->VolCatInfo.VolCatStatus, "Append"); - Dmsg0(100, "dir_update_vol_info. Set Append\n"); - dir_update_volume_info(jcr, &dev->VolCatInfo, 1); /* indicate doing relabel */ - if (recycle) { - Jmsg(jcr, M_INFO, 0, _("Recycled volume %s on device %s, all previous data lost.\n"), - jcr->VolumeName, dev_name(dev)); - } else { - Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume %s on device %s\n"), - jcr->VolumeName, dev_name(dev)); - } - - } else { - /* - * OK, at this point, we have a valid Bacula label, but - * we need to position to the end of the volume, since we are - * just now putting it into append mode. - */ - Dmsg0(200, "Device previously written, moving to end of data\n"); - Jmsg(jcr, M_INFO, 0, _("Volume %s previously written, moving to end of data.\n"), - jcr->VolumeName); - if (!eod_dev(dev)) { - Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - Jmsg(jcr, M_INFO, 0, _("Marking Volume %s in Error in Catalog.\n"), - jcr->VolumeName); - strcpy(dev->VolCatInfo.VolCatStatus, "Error"); - Dmsg0(100, "dir_update_vol_info. Set Error.\n"); - dir_update_volume_info(jcr, &dev->VolCatInfo, 0); - goto mount_next_vol; - } - /* *****FIXME**** we should do some checking for files too */ - if (dev_is_tape(dev)) { - Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume at file=%d.\n"), dev_file(dev)); - /* - * Check if we are positioned on the tape at the same place - * that the database says we should be. - */ - if (dev->VolCatInfo.VolCatFiles != dev_file(dev) + 1) { - /* ****FIXME**** this should refuse to write on tape */ - Jmsg(jcr, M_ERROR, 0, _("Hey! Num files mismatch! Volume=%d Catalog=%d\n"), - dev_file(dev)+1, dev->VolCatInfo.VolCatFiles); - } - } - /* Update Volume Info -- will be written at end of Job */ - dev->VolCatInfo.VolCatMounts++; /* Update mounts */ - dev->VolCatInfo.VolCatJobs++; - /* Return an empty block */ - empty_block(block); /* we used it for reading so set for write */ - } - dev->state |= ST_APPEND; - Dmsg0(100, "Normal return from read_dev_for_append\n"); - return 1; -} - -/* - * This routine ensures that the device is ready for - * reading. If it is a file, it opens it. - * If it is a tape, it checks the volume name - * - * Returns 0 on failure - * Returns 1 on success - */ -int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) -{ - if (!(dev->state & ST_OPENED)) { - Dmsg1(120, "bstored: open vol=%s\n", jcr->VolumeName); - if (open_dev(dev, jcr->VolumeName, READ_ONLY) < 0) { - Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"), - dev_name(dev), jcr->VolumeName, strerror_dev(dev)); - return 0; - } - Dmsg1(129, "open_dev %s OK\n", dev_name(dev)); - } - - for (;;) { - if (job_cancelled(jcr)) { - Mmsg0(&dev->errmsg, _("Job cancelled.\n")); - return 0; - } - if (!rewind_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - } - switch (read_dev_volume_label(jcr, dev, block)) { - case VOL_OK: - break; /* got it */ - default: - /* Send error message generated by read_dev_volume_label() */ - Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); - if (!rewind_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), - dev_name(dev), strerror_dev(dev)); - } - /* Mount a specific volume and no other */ - if (!dir_ask_sysop_to_mount_volume(jcr, dev)) { - return 0; /* error return */ - } - continue; /* try reading again */ - } - break; - } - - dev->state |= ST_READ; - return 1; -} - /* * This is the dreaded moment. We either have an end of * medium condition or worse, and error condition. @@ -668,7 +121,7 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* Unlock, but leave BLOCKED */ unlock_device(dev); - if (!mount_next_volume(jcr, dev, label_blk, 1)) { + if (!mount_next_write_volume(jcr, dev, label_blk, 1)) { P(dev->mutex); unblock_device(dev); return 0; /* device locked */ @@ -682,7 +135,7 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* * If this is a new tape, the label_blk will contain the * label, so write it now. If this is a previously - * used tape, mount_next_volume() will return an + * used tape, mount_next_write_volume() will return an * empty label_blk, and nothing will be written. */ Dmsg0(190, "write label block to dev\n"); @@ -827,83 +280,3 @@ void unblock_device(DEVICE *dev) pthread_cond_broadcast(&dev->wait); /* wake them up */ } } - - - -/* - * Edit codes into ChangerCommand - * %% = % - * %a = archive device name - * %c = changer device name - * %f = Client's name - * %j = Job name - * %o = command - * %s = Slot base 0 - * %S = Slot base 1 - * %v = Volume name - * - * - * omsg = edited output message - * imsg = input string containing edit codes (%x) - * cmd = command string (load, unload, ...) - * - */ -static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) -{ - char *p; - const char *str; - char add[20]; - - *omsg = 0; - Dmsg1(200, "edit_device_codes: %s\n", imsg); - for (p=imsg; *p; p++) { - if (*p == '%') { - switch (*++p) { - case '%': - str = "%"; - break; - case 'a': - str = jcr->device->dev->dev_name; - break; - case 'c': - str = NPRT(jcr->device->changer_name); - break; - case 'o': - str = NPRT(cmd); - break; - case 's': - sprintf(add, "%d", jcr->VolCatInfo.Slot - 1); - str = add; - break; - case 'S': - sprintf(add, "%d", jcr->VolCatInfo.Slot); - str = add; - break; - case 'j': /* Job name */ - str = jcr->Job; - break; - case 'v': - str = NPRT(jcr->VolumeName); - break; - case 'f': - str = NPRT(jcr->client_name); - break; - - default: - add[0] = '%'; - add[1] = *p; - add[2] = 0; - str = add; - break; - } - } else { - add[0] = *p; - add[1] = 0; - str = add; - } - Dmsg1(200, "add_str %s\n", str); - pm_strcat(&omsg, (char *)str); - Dmsg1(200, "omsg=%s\n", omsg); - } - return omsg; -} diff --git a/bacula/src/stored/fd_cmds.c b/bacula/src/stored/fd_cmds.c index 91714180ab..dc18e70998 100644 --- a/bacula/src/stored/fd_cmds.c +++ b/bacula/src/stored/fd_cmds.c @@ -111,6 +111,8 @@ void run_job(JCR *jcr) char ec1[30]; + fd->jcr = (void *)jcr; + dir->jcr = (void *)jcr; Dmsg1(120, "Start run Job=%s\n", jcr->Job); bnet_fsend(dir, Job_start, jcr->Job); time(&jcr->start_time); diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index 45412246b0..f32535f0d9 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -38,7 +38,7 @@ static int use_device_cmd(JCR *jcr); /* Requests from the Director daemon */ static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s \ -type=%d level=%d FileSet=%127s Allow="; +type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d\n"; static char use_device[] = "use device=%s media_type=%s pool_name=%s pool_type=%s\n"; /* Responses sent to Director daemon */ @@ -66,7 +66,7 @@ int job_cmd(JCR *jcr) char auth_key[100]; BSOCK *dir = jcr->dir_bsock; POOLMEM *job_name, *client_name, *job, *fileset_name; - int JobType, level; + int JobType, level, spool_attributes, no_attributes; struct timeval tv; struct timezone tz; struct timespec timeout; @@ -81,7 +81,8 @@ int job_cmd(JCR *jcr) client_name = get_memory(dir->msglen); fileset_name = get_memory(dir->msglen); if (sscanf(dir->msg, jobcmd, &JobId, job, job_name, client_name, - &JobType, &level, fileset_name) != 7) { + &JobType, &level, fileset_name, &no_attributes, + &spool_attributes) != 9) { bnet_fsend(dir, BAD_job, dir->msg); Emsg1(M_FATAL, 0, _("Bad Job Command from Director: %s\n"), dir->msg); free_memory(job); @@ -106,6 +107,8 @@ int job_cmd(JCR *jcr) strcpy(jcr->fileset_name, fileset_name); jcr->JobType = JobType; jcr->JobLevel = level; + jcr->no_attributes = no_attributes; + jcr->spool_attributes = spool_attributes; free_memory(job); free_memory(job_name); free_memory(client_name); @@ -192,11 +195,12 @@ void handle_filed_connection(BSOCK *fd, char *job_name) JCR *jcr; if (!(jcr=get_jcr_by_full_name(job_name))) { - Emsg1(M_FATAL, 0, _("Job name not found: %s\n"), job_name); + Jmsg1(NULL, M_FATAL, 0, _("Job name not found: %s\n"), job_name); return; } jcr->file_bsock = fd; + jcr->file_bsock->jcr = (void *)jcr; Dmsg1(110, "Found Job %s\n", job_name); diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 09c095285d..14c15b7f09 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -481,9 +481,14 @@ int write_session_label(JCR *jcr, DEV_BLOCK *block, int label) create_session_label(jcr, rec, label); rec->FileIndex = label; - while (!write_record_to_block(block, rec)) { - Dmsg2(190, "!write_record data_len=%d rem=%d\n", rec->data_len, - rec->remainder); + /* + * We guarantee that the session record can totally fit + * into a block. If not, write the block, and put it in + * the next block. Having the sesssion record totally in + * one block makes reading them much easier (no need to + * read the next block). + */ + if (!can_write_record_to_block(block, rec)) { if (!write_block_to_device(jcr, dev, block)) { Dmsg0(90, "Got session label write_block_to_dev error.\n"); Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"), @@ -492,6 +497,7 @@ int write_session_label(JCR *jcr, DEV_BLOCK *block, int label) return 0; } } + write_record_to_block(block, rec); Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n\ remainder=%d\n", jcr->JobId, diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c new file mode 100644 index 0000000000..fea18a03c1 --- /dev/null +++ b/bacula/src/stored/mount.c @@ -0,0 +1,475 @@ +/* + * + * Routines for handling mounting tapes for reading and for + * writing. + * + * Kern Sibbald, August MMII + * + * Version $Id$ + */ +/* + Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + + 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" /* pull in global headers */ +#include "stored.h" /* pull in Storage Deamon headers */ + +/* Forward referenced functions */ +static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd); + + +/* + * If release is set, we rewind the current volume, + * which we no longer want, and ask the user (console) + * to mount the next volume. + * + * Continue trying until we get it, and then ensure + * that we can write on it. + * + * This routine returns a 0 only if it is REALLY + * impossible to get the requested Volume. + */ +int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release) +{ + int recycle, ask, retry = 0, autochanger; + + Dmsg0(190, "Enter mount_next_volume()\n"); + +mount_next_vol: + if (retry++ > 5) { + Jmsg(jcr, M_FATAL, 0, _("Too many errors on device %s.\n"), dev_name(dev)); + return 0; + } + if (job_cancelled(jcr)) { + Jmsg(jcr, M_FATAL, 0, _("Job cancelled.\n")); + return 0; + } + recycle = ask = autochanger = 0; + if (release) { + Dmsg0(500, "mount_next_volume release=1\n"); + /* + * First erase all memory of the current volume + */ + dev->block_num = 0; + dev->file = 0; + dev->LastBlockNumWritten = 0; + memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); + memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); + dev->state &= ~ST_LABEL; /* label not yet read */ + + if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) { + if (dev->capabilities & CAP_OFFLINEUNMOUNT) { + offline_dev(dev); + } + close_dev(dev); + } + + /* If we have not closed the device, then at least rewind the tape */ + if (dev->state & ST_OPENED) { + if (dev->capabilities & CAP_OFFLINEUNMOUNT) { + offline_dev(dev); + } + if (!rewind_dev(dev)) { + Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + } + } + ask = 1; /* ask operator to mount tape */ + } else { + /* + * Get Director's idea of what tape we should have mounted. + */ + if (!dir_find_next_appendable_volume(jcr)) { + ask = 1; /* we must ask */ + } + } + release = 1; /* release if we "recurse" */ + + /* + * Get next volume and ready it for append + * This code ensures that the device is ready for + * writing. We start from the assumption that there + * may not be a tape mounted. + * + * If the device is a file, we create the output + * file. If it is a tape, we check the volume name + * and move the tape to the end of data. + * + * It assumes that the device is not already in use! + * + */ + + Dmsg0(100, "Enter ready_dev_for_append\n"); + + dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); + + jcr->VolFirstFile = jcr->JobFiles; /* first update of Vol FileIndex */ + for ( ;; ) { + int slot = jcr->VolCatInfo.Slot; + + /* + * Handle autoloaders here. If we cannot autoload it, we + * will fall through to ask the sysop. + */ + if (dev->capabilities && CAP_AUTOCHANGER && slot <= 0) { + if (dir_find_next_appendable_volume(jcr)) { + slot = jcr->VolCatInfo.Slot; + } + } + Dmsg1(100, "Want changer slot=%d\n", slot); + + if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) { + uint32_t timeout = jcr->device->max_changer_wait; + POOLMEM *changer, *results; + int status, loaded; + + results = get_pool_memory(PM_MESSAGE); + changer = get_pool_memory(PM_FNAME); + /* Find out what is loaded */ + changer = edit_device_codes(jcr, changer, jcr->device->changer_command, + "loaded"); + status = run_program(changer, timeout, results); + if (status == 0) { + loaded = atoi(results); + } else { + loaded = -1; /* force unload */ + } + Dmsg1(100, "loaded=%s\n", results); + + /* If bad status or tape we want is not loaded, load it. */ + if (status != 0 || loaded != slot) { + if (dev->capabilities & CAP_OFFLINEUNMOUNT) { + offline_dev(dev); + } + /* We are going to load a new tape, so close the device */ + force_close_dev(dev); + if (loaded != 0) { /* must unload drive */ + Dmsg0(100, "Doing changer unload.\n"); + changer = edit_device_codes(jcr, changer, + jcr->device->changer_command, "unload"); + status = run_program(changer, timeout, NULL); + Dmsg1(100, "unload status=%d\n", status); + } + /* + * Load the desired cassette + */ + Dmsg1(100, "Doing changer load slot %d\n", slot); + changer = edit_device_codes(jcr, changer, + jcr->device->changer_command, "load"); + status = run_program(changer, timeout, NULL); + Dmsg2(100, "load slot %d status=%d\n", slot, status); + } + free_pool_memory(changer); + free_pool_memory(results); + Dmsg1(100, "After changer, status=%d\n", status); + if (status == 0) { /* did we succeed? */ + ask = 0; /* yes, got vol, no need to ask sysop */ + autochanger = 1; /* tape loaded by changer */ + } + } + + + if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) { + return 0; /* error return */ + } + Dmsg1(200, "want vol=%s\n", jcr->VolumeName); + + /* Open device */ + for ( ; !(dev->state & ST_OPENED); ) { + if (open_dev(dev, jcr->VolCatInfo.VolCatName, READ_WRITE) < 0) { + if (dev->dev_errno == EAGAIN || dev->dev_errno == EBUSY) { + sleep(30); + } + Jmsg2(jcr, M_FATAL, 0, _("Unable to open device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + return 0; + } + } + + /* + * Now make sure we have the right tape mounted + */ +read_volume: + switch (read_dev_volume_label(jcr, dev, block)) { + case VOL_OK: + Dmsg1(500, "Vol OK name=%s\n", jcr->VolumeName); + memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo)); + if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) { + recycle = 1; + } + break; /* got it */ + case VOL_NAME_ERROR: + Dmsg1(500, "Vol NAME Error Name=%s\n", jcr->VolumeName); + /* Check if we can accept this as an anonymous volume */ + strcpy(jcr->VolumeName, dev->VolHdr.VolName); + if (!dev->capabilities & CAP_ANONVOLS || !dir_get_volume_info(jcr)) { + goto mount_next_vol; + } + Dmsg1(200, "want new name=%s\n", jcr->VolumeName); + memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo)); + break; + + case VOL_NO_LABEL: + case VOL_IO_ERROR: + Dmsg1(500, "Vol NO_LABEL or IO_ERROR name=%s\n", jcr->VolumeName); + /* If permitted, create a label */ + if (dev->capabilities & CAP_LABEL) { + Dmsg0(190, "Create volume label\n"); + if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName, + jcr->pool_name)) { + goto mount_next_vol; + } + Jmsg(jcr, M_INFO, 0, _("Created Volume label %s on device %s.\n"), + jcr->VolumeName, dev_name(dev)); + goto read_volume; /* read label we just wrote */ + } + /* NOTE! Fall-through wanted. */ + default: + /* Send error message */ + Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + if (autochanger) { + Jmsg(jcr, M_ERROR, 0, _("Autochanger Volume %s not found in slot %d.\n\ + Setting slot to zero in catalog.\n"), + jcr->VolumeName, jcr->VolCatInfo.Slot); + jcr->VolCatInfo.Slot = 0; /* invalidate slot */ + dir_update_volume_info(jcr, &jcr->VolCatInfo, 1); /* set slot */ + } + goto mount_next_vol; + } + break; + } + + /* + * See if we have a fresh tape or tape with data. + * + * Note, if the LabelType is PRE_LABEL, it was labeled + * but never written. If so, rewrite the label but set as + * VOL_LABEL. We rewind and return the label (reconstructed) + * in the block so that in the case of a new tape, data can + * be appended just after the block label. If we are writing + * an second volume, the calling routine will write the label + * before writing the overflow block. + * + * If the tape is marked as Recycle, we rewrite the label. + */ + if (dev->VolHdr.LabelType == PRE_LABEL || recycle) { + Dmsg1(190, "ready_for_append found freshly labeled volume. dev=%x\n", dev); + dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */ + write_volume_label_to_block(jcr, dev, block); + /* + * Write the block now to ensure we have write permission. + * It is better to find out now rather than later. + */ + dev->VolCatInfo.VolCatBytes = 0; + if (!rewind_dev(dev)) { + Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + } + if (recycle) { + if (!truncate_dev(dev)) { + Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + } + } + if (!write_block_to_dev(dev, block)) { + Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + goto mount_next_vol; + } + if (!rewind_dev(dev)) { + Jmsg2(jcr, M_ERROR, 0, _("Unable to rewind device %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + goto mount_next_vol; + } + /* Recreate a correct volume label and return it in the block */ + write_volume_label_to_block(jcr, dev, block); + dev->VolCatInfo.VolCatJobs = 1; + dev->VolCatInfo.VolCatFiles = 1; + dev->VolCatInfo.VolCatErrors = 0; + dev->VolCatInfo.VolCatBlocks = 1; + if (recycle) { + dev->VolCatInfo.VolCatMounts++; + dev->VolCatInfo.VolCatRecycles++; + } else { + dev->VolCatInfo.VolCatMounts = 1; + dev->VolCatInfo.VolCatRecycles = 0; + dev->VolCatInfo.VolCatWrites = 1; + dev->VolCatInfo.VolCatReads = 1; + } + strcpy(dev->VolCatInfo.VolCatStatus, "Append"); + Dmsg0(100, "dir_update_vol_info. Set Append\n"); + dir_update_volume_info(jcr, &dev->VolCatInfo, 1); /* indicate doing relabel */ + if (recycle) { + Jmsg(jcr, M_INFO, 0, _("Recycled volume %s on device %s, all previous data lost.\n"), + jcr->VolumeName, dev_name(dev)); + } else { + Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume %s on device %s\n"), + jcr->VolumeName, dev_name(dev)); + } + + } else { + /* + * OK, at this point, we have a valid Bacula label, but + * we need to position to the end of the volume, since we are + * just now putting it into append mode. + */ + Dmsg0(200, "Device previously written, moving to end of data\n"); + Jmsg(jcr, M_INFO, 0, _("Volume %s previously written, moving to end of data.\n"), + jcr->VolumeName); + if (!eod_dev(dev)) { + Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + Jmsg(jcr, M_INFO, 0, _("Marking Volume %s in Error in Catalog.\n"), + jcr->VolumeName); + strcpy(dev->VolCatInfo.VolCatStatus, "Error"); + Dmsg0(100, "dir_update_vol_info. Set Error.\n"); + dir_update_volume_info(jcr, &dev->VolCatInfo, 0); + goto mount_next_vol; + } + /* *****FIXME**** we should do some checking for files too */ + if (dev_is_tape(dev)) { + Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume at file=%d.\n"), dev_file(dev)); + /* + * Check if we are positioned on the tape at the same place + * that the database says we should be. + */ + if (dev->VolCatInfo.VolCatFiles != dev_file(dev) + 1) { + /* ****FIXME**** this should refuse to write on tape */ + Jmsg(jcr, M_ERROR, 0, _("Hey! Num files mismatch! Volume=%d Catalog=%d\n"), + dev_file(dev)+1, dev->VolCatInfo.VolCatFiles); + } + } + /* Update Volume Info -- will be written at end of Job */ + dev->VolCatInfo.VolCatMounts++; /* Update mounts */ + dev->VolCatInfo.VolCatJobs++; + /* Return an empty block */ + empty_block(block); /* we used it for reading so set for write */ + } + dev->state |= ST_APPEND; + Dmsg0(100, "Normal return from read_dev_for_append\n"); + return 1; +} + +int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +{ + Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume); + /* + * End Of Tape -- mount next Volume (if another specified) + */ + if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) { + VOL_LIST *vol = jcr->VolList; + /* Find next Volume */ + jcr->CurVolume++; + for (int i=1; iCurVolume; i++) { + vol = vol->next; + } + strcpy(jcr->VolumeName, vol->VolumeName); + Dmsg1(400, "There is another volume %s.\n", jcr->VolumeName); + + close_dev(dev); + dev->state &= ~ST_READ; + if (!acquire_device_for_read(jcr, dev, block)) { + Emsg2(M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), + jcr->VolumeName); + return 0; + } + return 1; /* next volume mounted */ + } + Dmsg0(90, "End of Device reached.\n"); + return 0; +} + + +/* + * Edit codes into ChangerCommand + * %% = % + * %a = archive device name + * %c = changer device name + * %f = Client's name + * %j = Job name + * %o = command + * %s = Slot base 0 + * %S = Slot base 1 + * %v = Volume name + * + * + * omsg = edited output message + * imsg = input string containing edit codes (%x) + * cmd = command string (load, unload, ...) + * + */ +static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) +{ + char *p; + const char *str; + char add[20]; + + *omsg = 0; + Dmsg1(200, "edit_device_codes: %s\n", imsg); + for (p=imsg; *p; p++) { + if (*p == '%') { + switch (*++p) { + case '%': + str = "%"; + break; + case 'a': + str = jcr->device->dev->dev_name; + break; + case 'c': + str = NPRT(jcr->device->changer_name); + break; + case 'o': + str = NPRT(cmd); + break; + case 's': + sprintf(add, "%d", jcr->VolCatInfo.Slot - 1); + str = add; + break; + case 'S': + sprintf(add, "%d", jcr->VolCatInfo.Slot); + str = add; + break; + case 'j': /* Job name */ + str = jcr->Job; + break; + case 'v': + str = NPRT(jcr->VolumeName); + break; + case 'f': + str = NPRT(jcr->client_name); + break; + + default: + add[0] = '%'; + add[1] = *p; + add[2] = 0; + str = add; + break; + } + } else { + add[0] = *p; + add[1] = 0; + str = add; + } + Dmsg1(200, "add_str %s\n", str); + pm_strcat(&omsg, (char *)str); + Dmsg1(200, "omsg=%s\n", omsg); + } + return omsg; +} diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 31c4415116..62872c2005 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -27,6 +27,12 @@ /* From stored.c */ uint32_t new_VolSessionId(); +/* From acquire.c */ +int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); + /* From askdir.c */ int dir_get_volume_info(JCR *jcr); int dir_find_next_appendable_volume(JCR *jcr); @@ -91,10 +97,6 @@ int dev_is_tape(DEVICE *dev); /* From device.c */ int open_device(DEVICE *dev); -int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); void block_device(DEVICE *dev, int state); void unblock_device(DEVICE *dev); void lock_device(DEVICE *dev); @@ -131,6 +133,11 @@ int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec); int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sesrec); +/* From mount.c */ +int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release); +int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); + + /* From parse_bsr.c */ extern BSR *parse_bsr(JCR *jcr, char *lf); extern void dump_bsr(BSR *bsr); @@ -144,8 +151,7 @@ extern void create_vol_list(JCR *jcr); char *FI_to_ascii(int fi); char *stream_to_ascii(int stream); int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); +int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); -int new_read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); DEV_RECORD *new_record(); void free_record(DEV_RECORD *rec); -int read_record(DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record); diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index 9821c97843..f1137ac64f 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -55,7 +55,7 @@ int do_read_data(JCR *jcr) BSOCK *fd_sock = jcr->file_bsock; int ok = TRUE; DEVICE *dev; - DEV_RECORD rec; + DEV_RECORD *rec; DEV_BLOCK *block; POOLMEM *hdr; SESSION_LABEL sessrec; /* session record */ @@ -80,6 +80,7 @@ int do_read_data(JCR *jcr) block = new_block(dev); + create_vol_list(jcr); Dmsg1(20, "Found %d volumes names to restore.\n", jcr->NumVolumes); @@ -93,8 +94,8 @@ int do_read_data(JCR *jcr) return 0; } - memset(&rec, 0, sizeof(rec)); - rec.data = ds->msg; /* use socket message buffer */ + rec = new_record(); + rec->data = ds->msg; /* use socket message buffer */ hdr = get_pool_memory(PM_MESSAGE); /* @@ -102,138 +103,117 @@ int do_read_data(JCR *jcr) * matched. */ for ( ;ok; ) { - DEV_RECORD *record; /* for reading label of multi-volumes */ - if (job_cancelled(jcr)) { ok = FALSE; break; } /* Read Record */ - Dmsg1(500, "Main read_record. rem=%d\n", rec.remainder); - if (!read_record(dev, block, &rec)) { - Dmsg1(500, "Main read record failed. rem=%d\n", rec.remainder); + Dmsg1(500, "Main read_record. rem=%d\n", rec->remainder); + if (!read_block_from_device(dev, block)) { + Dmsg1(500, "Main read record failed. rem=%d\n", rec->remainder); if (dev->state & ST_EOT) { - if (rec.remainder) { + if (rec->remainder) { Dmsg0(500, "Not end of record.\n"); } - Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume); - /* - * End Of Tape -- mount next Volume (if another specified) - */ - if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) { - VOL_LIST *vol = jcr->VolList; - close_dev(dev); - jcr->CurVolume++; - for (int i=1; iCurVolume; i++) { - vol = vol->next; - } - strcpy(jcr->VolumeName, vol->VolumeName); - Dmsg1(100, "There is another volume %s.\n", jcr->VolumeName); - dev->state &= ~ST_READ; - if (!acquire_device_for_read(jcr, dev, block)) { - Jmsg(jcr, M_FATAL, 0, _("Cannot open Dev=%s, Vol=%s\n"), dev_name(dev), jcr->VolumeName); - ok = FALSE; - break; - } - record = new_record(); - Dmsg1(500, "read record after new tape. rem=%d\n", record->remainder); - read_record(dev, block, record); /* read vol label */ - dump_label_record(dev, record, 0); - free_record(record); - continue; + if (!mount_next_read_volume(jcr, dev, block)) { + break; } - Dmsg0(90, "End of Device reached.\n"); - break; /* End of Tape */ + continue; } if (dev->state & ST_EOF) { Dmsg0(90, "Got End of File. Trying again ...\n"); continue; /* End of File */ } - - Jmsg2(jcr, M_FATAL, 0, _("Read error on Record Header %s ERR=%s\n"), dev_name(dev), strerror(errno)); - ok = FALSE; - break; + if (dev->state & ST_SHORT) { + continue; + } } - /* Some sort of label? */ - if (rec.FileIndex < 0) { - char *rtype; - memset(&sessrec, 0, sizeof(sessrec)); - switch (rec.FileIndex) { - case PRE_LABEL: - rtype = "Fresh Volume Label"; - break; - case VOL_LABEL: - rtype = "Volume Label"; - unser_volume_label(dev, &rec); - break; - case SOS_LABEL: - rtype = "Begin Session"; - unser_session_label(&sessrec, &rec); - break; - case EOS_LABEL: - rtype = "End Session"; - break; - case EOM_LABEL: - rtype = "End of Media"; - break; - default: - rtype = "Unknown"; - break; - } - if (debug_level > 0) { - printf("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", - rtype, rec.VolSessionId, rec.VolSessionTime, rec.Stream, rec.data_len); - } + for (rec->state=0; !is_block_empty(rec); ) { - Dmsg1(40, "Got label = %d\n", rec.FileIndex); - if (rec.FileIndex == EOM_LABEL) { /* end of tape? */ - Dmsg0(40, "Get EOM LABEL\n"); - break; /* yes, get out */ - } - continue; /* ignore other labels */ - } /* end if label record */ + /* Some sort of label? */ + if (rec->FileIndex < 0) { + char *rtype; + memset(&sessrec, 0, sizeof(sessrec)); + switch (rec->FileIndex) { + case PRE_LABEL: + rtype = "Fresh Volume Label"; + break; + case VOL_LABEL: + rtype = "Volume Label"; + unser_volume_label(dev, rec); + break; + case SOS_LABEL: + rtype = "Begin Session"; + unser_session_label(&sessrec, rec); + break; + case EOS_LABEL: + rtype = "End Session"; + break; + case EOM_LABEL: + rtype = "End of Media"; + break; + default: + rtype = "Unknown"; + break; + } + Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", + rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); - if (jcr->bsr) { - /* Match BSR against current record */ - if (!match_bsr(jcr->bsr, &rec, &dev->VolHdr, &sessrec)) { - Dmsg0(50, "BSR rejected record\n"); - continue; + Dmsg1(40, "Got label = %d\n", rec->FileIndex); + if (rec->FileIndex == EOM_LABEL) { /* end of tape? */ + Dmsg0(40, "Get EOM LABEL\n"); + break; /* yes, get out */ + } + continue; /* ignore other labels */ + } /* end if label record */ + + if (jcr->bsr) { + /* Match BSR against current record */ + if (!match_bsr(jcr->bsr, rec, &dev->VolHdr, &sessrec)) { + Dmsg0(50, "BSR rejected record\n"); + rec->remainder = 0; + continue; + } + } else { + /* Old way, deprecated */ + if (rec->VolSessionId != jcr->read_VolSessionId || + rec->VolSessionTime != jcr->read_VolSessionTime) { + Dmsg0(50, "Ignore record ids not equal\n"); + rec->remainder = 0; + continue; /* ignore */ + } } - } else { - /* Old way, deprecated */ - if (rec.VolSessionId != jcr->read_VolSessionId || - rec.VolSessionTime != jcr->read_VolSessionTime) { - Dmsg0(50, "Ignore record ids not equal\n"); - continue; /* ignore */ + if (is_partial_record(rec)) { + break; + } + + /* Generate Header parameters and send to File daemon + * Note, we build header in hdr buffer to avoid wiping + * out the data record + */ + ds->msg = hdr; + if (!bnet_fsend(ds, rec_header, rec->VolSessionId, rec->VolSessionTime, + rec->FileIndex, rec->Stream, rec->data_len)) { + Dmsg1(30, ">filed: Error Hdr=%s\n", ds->msg); + ds->msg = rec->data; + ok = FALSE; + break; + } else { + Dmsg1(30, ">filed: Hdr=%s\n", ds->msg); } - } - - /* Generate Header parameters and send to File daemon - * Note, we build header in hdr buffer to avoid wiping - * out the data record - */ - ds->msg = hdr; - if (!bnet_fsend(ds, rec_header, rec.VolSessionId, rec.VolSessionTime, - rec.FileIndex, rec.Stream, rec.data_len)) { - Dmsg1(30, ">filed: Error Hdr=%s\n", ds->msg); - ds->msg = rec.data; - ok = FALSE; - break; - } else { - Dmsg1(30, ">filed: Hdr=%s\n", ds->msg); - } - ds->msg = rec.data; /* restore data record address */ + ds->msg = rec->data; /* restore data record address */ - /* Send data record to File daemon */ - ds->msglen = rec.data_len; - Dmsg1(40, ">filed: send %d bytes data.\n", ds->msglen); - if (!bnet_send(ds)) { - Dmsg0(0, "Error sending to FD\n"); - Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"), - bnet_strerror(ds)); - ok = FALSE; + /* Send data record to File daemon */ + ds->msglen = rec->data_len; + Dmsg1(40, ">filed: send %d bytes data.\n", ds->msglen); + if (!bnet_send(ds)) { + Dmsg0(0, "Error sending to FD\n"); + Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"), + bnet_strerror(ds)); + ok = FALSE; + } } } /* Send end of data to FD */ @@ -244,6 +224,7 @@ int do_read_data(JCR *jcr) } free_pool_memory(hdr); free_block(block); + free_record(rec); free_vol_list(jcr); Dmsg0(30, "Done reading.\n"); return ok ? 1 : 0; diff --git a/bacula/src/stored/record.c b/bacula/src/stored/record.c index 25fc1ad3d8..2183f49817 100644 --- a/bacula/src/stored/record.c +++ b/bacula/src/stored/record.c @@ -113,34 +113,6 @@ void free_record(DEV_RECORD *rec) Dmsg0(150, "Leave free_record.\n"); } -/* - * Read a record from a block - * if necessary, read the block from the device without locking - * if necessary, handle getting a new Volume - * - * Returns: 0 on failure - * 1 on success - */ -int read_record(DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *record) -{ - Dmsg2(90, "read_record() dev=%x state=%x\n", dev, dev->state); - - while (!read_record_from_block(block, record)) { - Dmsg2(90, "!read_record_from_block data_len=%d rem=%d\n", record->data_len, - record->remainder); - if (!read_block_from_dev(dev, block)) { - Dmsg0(200, "===== Got read block I/O error ======\n"); - return 0; - } - } - Dmsg4(90, "read_record FI=%s SessId=%d Strm=%s len=%d\n", - FI_to_ascii(record->FileIndex), record->VolSessionId, - stream_to_ascii(record->Stream), record->data_len); - record->File = dev->file; - record->Block = dev->block_num; - return 1; -} - /* * Write a Record to the block @@ -284,129 +256,33 @@ rem=%d remainder=%d\n", /* - * Read a Record from the block - * Returns: 0 on failure - * 1 on success + * Test if we can write whole record to the block + * + * Returns: 0 on failure + * 1 on success (all bytes can be written) */ -int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) +int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec) { - ser_declare; uint32_t remlen; - uint32_t VolSessionId; - uint32_t VolSessionTime; - int32_t FileIndex; - int32_t Stream; - uint32_t data_bytes; - - remlen = block->binbuf; - - /* Clear state flags */ - rec->state = 0; - - /* - * Get the header. There is always a full header, - * otherwise we find it in the next block. - */ - if (remlen >= RECHDR_LENGTH) { - Dmsg3(90, "read_record_block: remlen=%d data_len=%d rem=%d\n", - remlen, rec->data_len, rec->remainder); - unser_begin(block->bufp, RECHDR_LENGTH); - unser_uint32(VolSessionId); - unser_uint32(VolSessionTime); - unser_int32(FileIndex); - unser_int32(Stream); - unser_uint32(data_bytes); - - ASSERT(unser_length(block->bufp) == RECHDR_LENGTH); - block->bufp += RECHDR_LENGTH; - block->binbuf -= RECHDR_LENGTH; - remlen -= RECHDR_LENGTH; - - /* - * if Stream is negative, it means that this is a continuation - * of a previous partially written record. - */ - if (Stream < 0) { /* continuation record? */ - Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n", - rec->remainder); - rec->state |= REC_CONTINUATION; - if (!rec->remainder) { /* if we didn't read previously */ - rec->data_len = 0; /* return data as if no continuation */ - } else if (rec->VolSessionId != VolSessionId || - rec->VolSessionTime != VolSessionTime || - rec->Stream != -Stream) { - rec->state |= REC_NO_MATCH; - return 0; /* This is from some other Session */ - } - rec->Stream = -Stream; /* set correct Stream */ - } else { /* Regular record */ - rec->Stream = Stream; - rec->data_len = 0; /* transfer to beginning of data */ + remlen = block->buf_len - block->binbuf; + if (rec->remainder == 0) { + if (remlen >= RECHDR_LENGTH) { + remlen -= RECHDR_LENGTH; + rec->remainder = rec->data_len; + } else { + return 0; } - rec->VolSessionId = VolSessionId; - rec->VolSessionTime = VolSessionTime; - rec->FileIndex = FileIndex; - - Dmsg6(90, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%d\n\ -remlen=%d data_len=%d\n", - FI_to_ascii(rec->FileIndex), rec->VolSessionId, - stream_to_ascii(rec->Stream), data_bytes, remlen, rec->data_len); } else { - /* - * No more records in this block because the number - * of remaining bytes are less than a record header - * length, so return empty handed, but indicate that - * he must read again. By returning, we allow the - * higher level routine to fetch the next block and - * then reread. - */ - Dmsg0(90, "read_record_block: nothing\n"); - if (!rec->remainder) { - rec->remainder = 1; /* set to expect continuation */ - rec->data_len = 0; /* no data transferred */ - } - rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY); return 0; } - - ASSERT(data_bytes < MAX_BLOCK_LENGTH); /* temp sanity check */ - - rec->data = check_pool_memory_size(rec->data, rec->data_len+data_bytes); - - /* - * At this point, we have read the header, now we - * must transfer as much of the data record as - * possible taking into account: 1. A partial - * data record may have previously been transferred, - * 2. The current block may not contain the whole data - * record. - */ - if (remlen >= data_bytes) { - /* Got whole record */ - memcpy(rec->data+rec->data_len, block->bufp, data_bytes); - block->bufp += data_bytes; - block->binbuf -= data_bytes; - rec->data_len += data_bytes; - } else { - /* Partial record */ - memcpy(rec->data+rec->data_len, block->bufp, remlen); - block->bufp += remlen; - block->binbuf -= remlen; - rec->data_len += remlen; - rec->remainder = 1; /* partial record transferred */ - Dmsg1(90, "read_record_block: partial xfered=%d\n", rec->data_len); - rec->state |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY); - /********FIXME********* this should return 1 */ + if (rec->remainder > 0 && remlen < rec->remainder) { return 0; } - rec->remainder = 0; - Dmsg4(90, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n", - FI_to_ascii(rec->FileIndex), rec->VolSessionId, - stream_to_ascii(rec->Stream), rec->data_len); - return 1; /* transferred full record */ + return 1; } + /* * Read a Record from the block * Returns: 0 if nothing read or if the continuation record does not match. @@ -415,7 +291,7 @@ remlen=%d data_len=%d\n", * routine may have to be called again with a new * block if the entire record was not read. */ -int new_read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) +int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) { ser_declare; uint32_t remlen; diff --git a/bacula/src/tools/dbcheck.c b/bacula/src/tools/dbcheck.c index 944549a2e4..eafcc748bc 100644 --- a/bacula/src/tools/dbcheck.c +++ b/bacula/src/tools/dbcheck.c @@ -155,7 +155,7 @@ int main (int argc, char *argv[]) } /* Open database */ - db = db_init_database(db_name, user, password); + db = db_init_database(NULL, db_name, user, password); if (!db_open_database(db)) { Emsg1(M_FATAL, 0, "%s", db_strerror(db)); } -- 2.39.5