]> git.sur5r.net Git - bacula/bacula/commitdiff
Add jcr to BSOCK and BDB SpoolAttr NoAttributs finish up multiple simultaneous jobs...
authorKern Sibbald <kern@sibbald.com>
Fri, 23 Aug 2002 20:49:22 +0000 (20:49 +0000)
committerKern Sibbald <kern@sibbald.com>
Fri, 23 Aug 2002 20:49:22 +0000 (20:49 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@119 91ce42f0-d328-0410-95d8-f526ca767f89

34 files changed:
bacula/src/cats/bdb.c
bacula/src/cats/cats.h
bacula/src/cats/mysql.c
bacula/src/cats/protos.h
bacula/src/cats/sql_create.c
bacula/src/cats/sqlite.c
bacula/src/console/console.c
bacula/src/dird/dird.c
bacula/src/dird/dird_conf.c
bacula/src/dird/dird_conf.h
bacula/src/dird/job.c
bacula/src/dird/msgchan.c
bacula/src/dird/ua_cmds.c
bacula/src/filed/job.c
bacula/src/lib/bnet.c
bacula/src/lib/bnet_server.c
bacula/src/lib/bsock.h
bacula/src/lib/message.c
bacula/src/lib/protos.h
bacula/src/stored/Makefile.in
bacula/src/stored/acquire.c [new file with mode: 0644]
bacula/src/stored/append.c
bacula/src/stored/bextract.c
bacula/src/stored/bls.c
bacula/src/stored/bscan.c
bacula/src/stored/device.c
bacula/src/stored/fd_cmds.c
bacula/src/stored/job.c
bacula/src/stored/label.c
bacula/src/stored/mount.c [new file with mode: 0644]
bacula/src/stored/protos.h
bacula/src/stored/read.c
bacula/src/stored/record.c
bacula/src/tools/dbcheck.c

index ae1819abf41061033e31f8d837d24b69b33a5b8a..dea6aff1270f77ce4c6194184a375c7b9e9efe7a 100644 (file)
@@ -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;
 }
index 4fc6c7d3ef15594d491e5b7d00590876417279f9..7944051bf00b593b2fa145fcc0a15c480ccfdd69 100644 (file)
@@ -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 */
index 5ad818e7b06d4642c7a968d9586b1b5878380c4c..89539ccc646da6bc755038b4cd2d9f5709ddf2a5 100644 (file)
@@ -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;
 }
index 66f2c72989741919fd3ddd812238494eb163f9a2..ab1fb39c187a9883a6ba0aff52e2960714a14e7b 100644 (file)
@@ -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 */
index 7674ec14a3ca643dedb59111130a2950af6daa32..033d5451f0db6ccdcfbc2918bf54203f2ba38b10 100644 (file)
@@ -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);
index ee9022d809e1a63a7bfb5cb7b271b96c9bca80d5..4628f698c8bd4dc82580f6d8b0b3e22a59953393 100644 (file)
@@ -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;
 }
index 616cbaf980a124c7104162157446d0472a8796cb..49b8beb2f14b2f856975d82d6d5564fb6dcd619f 100644 (file)
@@ -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();
index d89099596de4806062bda5771674f464958ac53b..09a6080fad373e93741a42ef152053c9d93cbce7 100644 (file)
@@ -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;
         }
index dd00ff9c18a58ef50bd8872096e1145d84eae268..79b910fd70bf58a93352008e78730e52d2ba8660 100644 (file)
@@ -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} 
 };
 
index 7c3e6d0284b867d85c40676658459b247e94ff27..2689d89b0e7a80aca3d4b722262ba604dc255442 100644 (file)
 /*
  * 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 */
index e5b22303c1ae82090bfcf8781cafc07c64ff238a..1ed219546f48883fda36a939b8cf40c4b5368641 100644 (file)
@@ -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));
index 9f813eff60c2374735355402721a01de064c7cdc..d3a88d7e71dacf4f94eb820a688e7bf7ac0185fc 100644 (file)
@@ -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;
index 4c48d64cfed4a0f2617181a31cc48345ee623dc7..bbfcc73a6f0efc40a84ecbb93f9701702ca7d5c1 100644 (file)
@@ -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"), 
index 937831421d7314b85a2cccb11ba4c89c7b4152b4..2c8e98111cece40ca321b88c475911f1d7dffefc 100644 (file)
@@ -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 */
 
index b63ce599919edc7e39fb1c27a2f39124a92d9cdb..670bdd4d5acbceba88058831f36f9701c6033662 100644 (file)
@@ -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;
 }
 
index 72544637136ad879b8ff6a675b13b39765fb3b42..1c2150226e9765a5e714e50159b85941e77048e9 100644 (file)
@@ -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));
       }
    }
 }   
index d347a6bff015e8842cf32337d235549c8931fae9..54d1ed3d5c80e6ac8a54e2d0ec97aff021521001 100644 (file)
@@ -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() */
index 93019a31c63190005f322a962b11dd56a60ccefa..003b76a0a451c01e7e20b0900a7df3b3305e9192 100755 (executable)
@@ -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);
index ca9266cc2f0dec4b44d729e5239a559e98294b40..746ee9761b889133da328d0e18ee62b6ffd0f4ab 100644 (file)
  */
 
 /* 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 */
index 07a58ba8132fce3a3c7c6801684eb1186d1eac60..f1a5be9ee2dbd7ae5b80d816a5bcf13245d62d8e 100644 (file)
@@ -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 (file)
index 0000000..0433fbd
--- /dev/null
@@ -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; 
+}
index 20b6bfedaa63c366e577913b8f2c55a8851059c3..e1c8efd396a4edcd00fe95d25e0b16676cbd66fd 100644 (file)
@@ -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);
index f286a7c62d2b2eb3d1b97d22c936c0d257eee474..d6b8de960586ae1296b4a2f24fb7a91e45e6d580 100644 (file)
@@ -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; i<jcr->CurVolume; 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;
 }
 
index 6b59140e7528093145ba9837f399a243d4675a72..011e8495883edeec83cb2ef589967cd7a95e5a47 100644 (file)
@@ -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;
index 6c7720e41faf193daa506e724462ef02f56348b9..c5edb803cfb77889e313831b2ccd5229fc731c56 100644 (file)
@@ -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;
 }
 
index bf3bcc48753e934148049d0fb2dd853e7ad742e3..4f21e2fdb6fce3fed3542946bf5402f339b6d509 100644 (file)
 #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;
-}
index 91714180ab2076fc510a6cea8ba58f6bc8bbd660..dc18e709988e1917d4590f8160f619f12d8e75d0 100644 (file)
@@ -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);
index 45412246b0db4961c4e1e5100f334e9d7100b3a7..f32535f0d9d2c27ef213f07ed5d3553d1f3d7970 100644 (file)
@@ -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);
 
index 09c095285d68f6c1866ff980a5395ae59f513741..14c15b7f09ed81124a4958ba471a2e5ba3b07d4d 100644 (file)
@@ -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 (file)
index 0000000..fea18a0
--- /dev/null
@@ -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; i<jcr->CurVolume; 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;
+}
index 31c44151167f2cbc36d46acd1120b8d9ca9e003e..62872c20057b1a55e8a4bfba7456149d016037c8 100644 (file)
 /* 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);
index 9821c9784306038d75629cc53b2a84d8b8c7cd03..f1137ac64fd0b1eca88f43d97e391cd9ab46e8fe 100644 (file)
@@ -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; i<jcr->CurVolume; 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;
index 25fc1ad3d8807966677fecca667ea1dd42a93ccc..2183f49817119d763a31978456ad5a7c7c04d2db 100644 (file)
@@ -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;
index 944549a2e4366050f683473d5b3060dc19e4eac0..eafcc748bce78ce7783ab218196d2ed620257cd3 100644 (file)
@@ -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));
    }