]> git.sur5r.net Git - bacula/bacula/commitdiff
Start of Recycle Code
authorKern Sibbald <kern@sibbald.com>
Thu, 25 Apr 2002 20:35:41 +0000 (20:35 +0000)
committerKern Sibbald <kern@sibbald.com>
Thu, 25 Apr 2002 20:35:41 +0000 (20:35 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6 91ce42f0-d328-0410-95d8-f526ca767f89

19 files changed:
bacula/Makefile.in
bacula/src/cats/make_mysql_tables.in
bacula/src/cats/sql_delete.c
bacula/src/console/console.c
bacula/src/console/console_conf.c
bacula/src/console/console_conf.h
bacula/src/dird/catreq.c
bacula/src/dird/run_conf.c
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_server.c
bacula/src/dird/verify.c
bacula/src/lib/parse_conf.c
bacula/src/lib/protos.h
bacula/src/lib/util.c
bacula/src/stored/askdir.c
bacula/src/stored/dev.h
bacula/src/stored/device.c
bacula/src/stored/dircmd.c
bacula/src/version.h

index 2796af378caccb43d40a3f7ad5d30f03381e276f..4c7c500dd693613eb52c02af2b7af87b0affaca9 100755 (executable)
@@ -32,7 +32,10 @@ MKDIR = $(srcdir)/autoconf/mkinstalldirs
 
 all: Makefile
        @for I in ${subdirs}; \
-         do (cd $$I; echo "==>Entering directory `pwd`"; $(MAKE) $@ || exit 1); done
+         do (cd $$I; echo "==>Entering directory `pwd`"; \
+             $(MAKE) $@ || (echo ""; echo ""; echo "   ====== Error in `pwd` ======"; \
+                           echo ""; echo "";)); \
+       done
 
 depend:
        @for I in ${subdirs}; \
@@ -40,7 +43,10 @@ depend:
        
 bacula-fd: Makefile       
        @for I in ${FDsubdirs}; \
-         do (cd $$I; echo "==>Entering directory `pwd`"; $(MAKE) all || exit 1); done
+         do (cd $$I; echo "==>Entering directory `pwd`"; \
+             $(MAKE) all || (echo ""; echo ""; echo "   ====== Error in `pwd` ======"; \
+                           echo ""; echo "";)); \
+       done
 
 #-------------------------------------------------------------------------
 configure: autoconf/configure.in autoconf/aclocal.m4 autoconf/acconfig.h autoconf/config.h.in
index 0ffb178ac50e138ffbea7c9fd9cf9eaa4854871c..0cf996e15f29efca86711ddff802a9c49bd7e4df 100644 (file)
@@ -102,7 +102,7 @@ CREATE TABLE Media (
    VolWrites INTEGER UNSIGNED NOT NULL,
    VolMaxBytes BIGINT UNSIGNED NOT NULL,
    VolCapacityBytes BIGINT UNSIGNED NOT NULL,
-   VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 
+   VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 'Purged',
     'Read-Only', 'Disabled', 'Error', 'Busy') NOT NULL,
    Recycle ENUM('No', 'Yes') NOT NULL,
    PRIMARY KEY(MediaId),
index 5fd896af9f7c4360f228f73af7b5c15c372b4d90..d8c7fdfbd7a81adab323e7f7f1ae947d35f7eafd 100644 (file)
@@ -109,24 +109,117 @@ db_delete_pool_record(B_DB *mdb, POOL_DBR *pr)
    return 1;
 }
 
+#define MAX_DEL_LIST_LEN 1000000
 
-/* Delete Media record */
-int db_delete_media_record(B_DB *mdb, MEDIA_DBR *mr)
+struct s_del_ctx {
+   uint32_t *JobId; 
+   int num_ids;                      /* ids stored */
+   int max_ids;                      /* size of array */
+   int num_del;                      /* number deleted */
+   int tot_ids;                      /* total to process */
+};
+
+/*
+ * Called here to make in memory list of JobIds to be
+ *  deleted. The in memory list will then be transversed
+ *  to issue the SQL DELETE commands.  Note, the list
+ *  is allowed to get to MAX_DEL_LIST_LEN to limit the
+ *  maximum malloc'ed memory.
+ */
+static int delete_handler(void *ctx, int num_fields, char **row)
 {
+   struct s_del_ctx *del = (struct s_del_ctx *)ctx;
 
-   P(mdb->mutex);
-   if (mr->MediaId == 0) {
-      Mmsg(&mdb->cmd, "DELETE FROM Media WHERE VolumeName=\"%s\"", 
-          mr->VolumeName);
-   } else {
-      Mmsg(&mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", 
-          mr->MediaId);
+   if (del->num_ids == MAX_DEL_LIST_LEN) {  
+      return 1;
+   }
+   if (del->num_ids == del->max_ids) {
+      del->max_ids = (del->max_ids * 3) / 2;
+      del->JobId = (uint32_t *)brealloc(del->JobId, sizeof(uint32_t) *
+        del->max_ids);
    }
+   del->JobId[del->num_ids++] = (uint32_t)strtod(row[0], NULL);
+   return 0;
+}
 
-   mr->MediaId = DELETE_DB(mdb, mdb->cmd);
 
-   V(mdb->mutex);
+/* 
+ * This routine will purge (delete) all records 
+ * associated with a particular Volume. It will
+ * not delete the media record itself.
+ */
+static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
+{
+   char *query = (char *)get_pool_memory(PM_MESSAGE);
+   struct s_del_ctx del;
+   int i;
+
+   del.num_ids = 0;
+   del.tot_ids = 0;
+   del.num_del = 0;
+   del.max_ids = 0;
+   Mmsg(&mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId);
+   del.max_ids = mr->VolJobs;
+   if (del.max_ids < 100) {
+      del.max_ids = 100;
+   } else if (del.max_ids > MAX_DEL_LIST_LEN) {
+      del.max_ids = MAX_DEL_LIST_LEN;
+   }
+   del.JobId = (uint32_t *)malloc(sizeof(uint32_t) * del.max_ids);
+   db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del);
+
+   for (i=0; i < del.num_ids; i++) {
+      Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
+      Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(mdb, query, NULL, (void *)NULL);
+      Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(mdb, query, NULL, (void *)NULL);
+      Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(mdb, query, NULL, (void *)NULL);
+   }
+   free(del.JobId);
+   free_pool_memory(query);
    return 1;
 }
 
+/* Delete Media record and all records that
+ * are associated with it.
+ */
+int db_delete_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+   if (mr->MediaId == 0 && !db_get_media_record(mdb, mr)) {
+      return 0;
+   } 
+   /* Delete associated records */
+   do_media_purge(mdb, mr);
+
+   Mmsg(&mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
+   db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL);
+   return 1;
+}
+
+/*
+ * Purge all records associated with a 
+ * media record. This does not delete the
+ * media record itself. But the media status
+ * is changed to "Purged".
+ */
+int db_purge_media_record(B_DB *mdb, MEDIA_DBR *mr)
+{
+   if (mr->MediaId == 0 && !db_get_media_record(mdb, mr)) {
+      return 0;
+   } 
+   /* Delete associated records */
+   do_media_purge(mdb, mr);
+
+   /* Mark Volume as purged */
+   strcpy(mr->VolStatus, "Purged");
+   if (!db_update_media_record(mdb, mr)) {
+      return 0;
+   }
+
+   return 1;
+}
+
+
 #endif /* HAVE_MYSQL || HAVE_SQLITE */
index 8929df66bd90be3e0e1d06968b8277517779d871..0fac356507b79f3a3be79b8eb70b32f9a9c146c1 100644 (file)
@@ -49,6 +49,8 @@ int get_cmd(char *prompt, BSOCK *sock, int sec);
 static char *configfile = NULL;
 static BSOCK *UA_sock = NULL;
 static DIRRES *dir; 
+static FILE *output = stdout;
+
 
 #define CONFIG_FILE "./console.conf"   /* default configuration file */
 
@@ -147,7 +149,7 @@ int main(int argc, char *argv[])
    }
    UnlockRes();
    if (ndir == 0) {
-      Emsg1(M_ABORT, 0, "No director resource defined in %s\n\
+      Emsg1(M_ABORT, 0, "No Director resource defined in %s\n\
 Without that I don't how to speak to the Director :-(\n", configfile);
    }
 
@@ -161,11 +163,11 @@ Without that I don't how to speak to the Director :-(\n", configfile);
    if (ndir > 1) {
       UA_sock = init_bsock(0, "", "", 0);
 try_again:
-      printf("Available Directors:\n");
+      fprintf(output, "Available Directors:\n");
       LockRes();
       ndir = 0;
       for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
-         printf("%d  %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address,
+         fprintf(output, "%d  %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address,
            dir->DIRport);
       }
       UnlockRes();
@@ -174,7 +176,7 @@ try_again:
       }
       item = atoi(UA_sock->msg);
       if (item < 0 || item > ndir) {
-         printf("You must enter a number between 1 and %d\n", ndir);
+         fprintf(output, "You must enter a number between 1 and %d\n", ndir);
         goto try_again;
       }
       LockRes();
@@ -200,7 +202,7 @@ try_again:
    }
    jcr.dir_bsock = UA_sock;
    if (!authenticate_director(&jcr, dir)) {
-      printf("ERR: %s", UA_sock->msg);
+      fprintf(stderr, "ERR: %s", UA_sock->msg);
       terminate_console(0);
       return 1;
    }
@@ -334,8 +336,8 @@ wait_for_data(int fd, int sec)
 int 
 get_cmd(char *prompt, BSOCK *sock, int sec)
 {
-   fprintf(stdout, prompt);
-   fflush(stdout);
+   fprintf(output, prompt);
+   fflush(output);
    switch (wait_for_data(fileno(stdin), sec)) {
       case 0:
         return 0;                    /* timeout */
index fc5284ce70f9bcbd13c54a8119095368c44a64ae..555a08bfbbad61b9357d968717546cbbe1244aa8 100644 (file)
@@ -64,6 +64,18 @@ int  res_all_size = sizeof(res_all);
  * resource with the routine to process the record 
  * information.
  */ 
+
+/*  Console "globals" */
+static struct res_items cons_items[] = {
+   {"name",        store_name,     ITEM(res_cons.hdr.name), 0, ITEM_REQUIRED, 0},
+   {"description", store_str,      ITEM(res_cons.hdr.desc), 0, 0, 0},
+   {"rcfile",      store_dir,      ITEM(res_cons.rc_file), 0, 0, 0},
+   {"historyfile", store_dir,      ITEM(res_cons.hist_file), 0, 0, 0},
+   {NULL, NULL, NULL, 0, 0, 0} 
+};
+
+
+/*  Director's that we can contact */
 static struct res_items dir_items[] = {
    {"name",        store_name,     ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
    {"description", store_str,      ITEM(res_dir.hdr.desc), 0, 0, 0},
@@ -78,6 +90,7 @@ static struct res_items dir_items[] = {
  * It must have one item for each of the resources.
  */
 struct s_res resources[] = {
+   {"console",       cons_items,  R_CONSOLE,   NULL},
    {"director",      dir_items,   R_DIRECTOR,  NULL},
    {NULL,           NULL,        0,           NULL}
 };
@@ -98,6 +111,10 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ...
       recurse = 0;
    }
    switch (type) {
+      case R_CONSOLE:
+         printf("Console: name=%s rcfile=%s histfile=%s\n", reshdr->name,
+               res->res_cons.rc_file, res->res_cons.hist_file);
+        break;
       case R_DIRECTOR:
          printf("Director: name=%s address=%s DIRport=%d\n", reshdr->name, 
                 res->res_dir.address, res->res_dir.DIRport);
@@ -136,6 +153,13 @@ void free_resource(int type)
       free(res->res_dir.hdr.desc);
 
    switch (type) {
+      case R_CONSOLE:
+        if (res->res_cons.rc_file) {
+           free(res->res_cons.rc_file);
+        }
+        if (res->res_cons.hist_file) {
+           free(res->res_cons.hist_file);
+        }
       case R_DIRECTOR:
         if (res->res_dir.address)
            free(res->res_dir.address);
@@ -181,6 +205,7 @@ void save_resource(int type, struct res_items *items, int pass)
    if (pass == 2) {
       switch (type) {
         /* Resources not containing a resource */
+        case R_CONSOLE:
         case R_DIRECTOR:
            break;
 
@@ -204,6 +229,9 @@ void save_resource(int type, struct res_items *items, int pass)
    }
 
    switch (type) {
+      case R_CONSOLE:
+        size = sizeof(CONSRES);
+        break;
       case R_DIRECTOR:
         size = sizeof(DIRRES);
         break;
index 04fdc7b85f54eb220da26b3b3100d34a032a1ca8..89b345b8062d953ebf02e52a439da8fe3bd74ec0 100644 (file)
@@ -7,28 +7,39 @@
 /*
  * Resource codes -- they must be sequential for indexing   
  */
-#define R_FIRST                       1001
+#define R_FIRST                      1001
 
-#define R_DIRECTOR                    1001
+#define R_CONSOLE                    1001
+#define R_DIRECTOR                   1002
 
-#define R_LAST                        R_DIRECTOR
+#define R_LAST                       R_DIRECTOR
 
 /*
  * 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
 
 
 /* Definition of the contents of each Resource */
+
+/* Console "globals" */
+struct s_res_cons {
+   RES  hdr;
+   char *rc_file;                    /* startup file */
+   char *hist_file;                  /* command history file */
+};
+typedef struct s_res_cons CONSRES;
+
+/* Director */
 struct s_res_dir {
-   RES   hdr;
-   int   DIRport;                     /* UA server port */
-   char *address;                     /* UA server address */
-   char *password;                    /* UA server password */
+   RES  hdr;
+   int  DIRport;                     /* UA server port */
+   char *address;                    /* UA server address */
+   char *password;                   /* UA server password */
 };
 typedef struct s_res_dir DIRRES;
 
@@ -37,7 +48,8 @@ typedef struct s_res_dir DIRRES;
  * resource structure definitions.
  */
 union u_res {
-   struct s_res_dir     res_dir;
+   struct s_res_dir    res_dir;
+   struct s_res_cons   res_cons;
    RES hdr;
 };
 
index f4e82ce0f5db1912e5c927fc1ba464a8739ef1de..d13d23c446f31fa23cfe0846cc9ba4dbdd237186 100644 (file)
@@ -41,7 +41,7 @@
 
 /* Requests from the Storage daemon */
 static char Find_media[] = "CatReq Job=%127s FindMedia=%d\n";
-static char Find_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s\n";
+static char Get_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s\n";
 
 static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s\
  VolJobs=%d VolFiles=%d VolBlocks=%d VolBytes=%" lld " VolMounts=%d\
@@ -52,7 +52,7 @@ static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s\
 /* Responses  sent to Storage daemon */
 static char OK_media[] = "1000 OK VolName=%s VolJobs=%d VolFiles=%d\
  VolBlocks=%d VolBytes=%" lld " VolMounts=%d VolErrors=%d VolWrites=%d\
- VolMaxBytes=%" lld " VolCapacityBytes=%" lld "\n";
+ VolMaxBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%s\n";
 
 static char OK_update[] = "1000 OK UpdateMedia\n";
 
@@ -88,11 +88,19 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
         jcr->MediaId = mr.MediaId;
          Dmsg1(20, "Find_next_vol MediaId=%d\n", jcr->MediaId);
         strcpy(jcr->VolumeName, mr.VolumeName);
-
         ok = TRUE;
       } else {
-        /* See if we can create a new Volume */
-        ok = newVolume(jcr);
+        /* Well, try finding recycled tapes */
+         strcpy(mr.VolStatus, "Recycle");
+        if (db_find_next_volume(jcr->db, index, &mr)) {
+           jcr->MediaId = mr.MediaId;
+            Dmsg1(20, "Find_next_vol MediaId=%d\n", jcr->MediaId);
+           strcpy(jcr->VolumeName, mr.VolumeName);
+           ok = TRUE;
+        } else {
+           /* See if we can create a new Volume */
+           ok = newVolume(jcr);
+        }
       }
       /*
        * Send Find Media response to Storage daemon 
@@ -101,7 +109,8 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
         bash_spaces(mr.VolumeName);
         bnet_fsend(bs, OK_media, mr.VolumeName, mr.VolJobs,
            mr.VolFiles, mr.VolBlocks, mr.VolBytes, mr.VolMounts, mr.VolErrors,
-           mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes);
+           mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes,
+           mr.VolStatus);
       } else {
          bnet_fsend(bs, "1999 No Media\n");
       }
@@ -109,7 +118,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
    /* 
     * Request to find specific volume information
     */
-   } else if (sscanf(bs->msg, Find_Vol_Info, &Job, &mr.VolumeName) == 2) {
+   } else if (sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName) == 2) {
       Dmsg1(120, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName);
       /*
        * Find the Volume
@@ -120,10 +129,12 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
          Dmsg1(20, "VolumeInfo MediaId=%d\n", jcr->MediaId);
         strcpy(jcr->VolumeName, mr.VolumeName);
         /* 
-         * Make sure this volume is suitable for this job
+         * Make sure this volume is suitable for this job, i.e.
+         *  it is either Append or Recycle and Media Type matches.
          */
         if (mr.PoolId == jcr->PoolId && 
-             strcmp(mr.VolStatus, "Append") == 0 &&
+             (strcmp(mr.VolStatus, "Append") == 0 ||
+              strcmp(mr.VolStatus, "Recycle") == 0) &&
             strcmp(mr.MediaType, jcr->store->media_type) == 0) {
            /*
             * Send Find Media response to Storage daemon 
@@ -131,7 +142,8 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
            bash_spaces(mr.VolumeName);
            bnet_fsend(bs, OK_media, mr.VolumeName, mr.VolJobs,
               mr.VolFiles, mr.VolBlocks, mr.VolBytes, mr.VolMounts, mr.VolErrors,
-              mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes);
+              mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes,
+              mr.VolStatus);
         } else { 
             Dmsg4(000, "get_media_record PoolId=%d wanted %d, Status=%s, \
 MediaType=%s\n", mr.PoolId, jcr->PoolId, mr.VolStatus, mr.MediaType);
index c58a713f5da19c12b23760bd14def279595b4e71..21b69f894496a9d7ff4fab881f1c52bbb5fb2235 100644 (file)
@@ -176,7 +176,7 @@ void store_run(LEX *lc, struct res_items *item, int index, int pass)
    } else {
       lcase(lc->str);
       for (i=0; joblevels[i].level_name; i++) {
-        if (strcmp(lc->str, joblevels[i].level_name) == 0) {
+        if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
            lrun.level = joblevels[i].level;
            lrun.job_class = joblevels[i].job_class;
            i = 0;
index d14de4a0fee02fa9287f4787abf91f0cc93624fd..4ecc17a4bcfbdb1aa0a6a905c4734a46146b75f7 100644 (file)
@@ -954,6 +954,9 @@ static int delete_media(UAContext *ua)
    }
    mr.MediaId = 0;
    strcpy(mr.VolumeName, ua->cmd);
+   bsendmsg(ua, _("\nThis command will delete volume %s\n"
+      "and all Jobs saved on that volume from the Catalog\n"));
+
    if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
       return 1;
    }
@@ -1065,7 +1068,7 @@ gotVol:
    bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s"), 
       dev_name, mr.VolumeName, pr.Name, mr.MediaType);
    bsendmsg(ua, "Sending label command ...\n");
-   while (bnet_recv(sd) > 0) {
+   while (bget_msg(sd, 0) > 0) {
       bsendmsg(ua, "%s", sd->msg);
       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
         ok = TRUE;
@@ -1253,6 +1256,7 @@ int open_db(UAContext *ua)
       close_db(ua);
       return 0;
    }
+   ua->jcr->db = ua->db;
    Dmsg1(50, "DB %s opened\n", ua->catalog->db_name);
    return 1;
 }
@@ -1263,4 +1267,5 @@ void close_db(UAContext *ua)
       db_close_database(ua->db);
    }
    ua->db = NULL;
+   ua->jcr->db = NULL;
 }
index 1ce7260392fc3e77558ff54b3b4735d66caef195..606ea60ec449d95bded612ff9273963839954ce0 100644 (file)
@@ -33,7 +33,6 @@
 extern void run_job(JCR *jcr);
 
 /* Imported variables */
-extern struct s_jl joblevels[];
 extern int r_first;
 extern int r_last;
 extern struct s_res resources[];
@@ -155,11 +154,12 @@ getout:
       ua.UA_sock = NULL;
    }
 
+   close_db(&ua);                    /* do this before freeing JCR */
+
    if (ua.jcr) {
       free_jcr(ua.jcr);
       ua.jcr = NULL;
    }
-   close_db(&ua);
    if (ua.prompt) {
       free(ua.prompt);
    }
index 4f216a3299bb371754dac70898f7c9a317cd96e9..aa6e1a351feef77c6666bb3af0e15b41afe4d9b2 100644 (file)
@@ -325,6 +325,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, int last_full_id)
    struct stat statc;                /* catalog stat */
    int stat = JS_Terminated;
    char buf[MAXSTRING];
+   char *fname = (char *)get_pool_memory(PM_MESSAGE);
 
    memset(&fdbr, 0, sizeof(FILE_DBR));
    fd = jcr->file_bsock;
@@ -341,9 +342,11 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, int last_full_id)
        char Opts_MD5[MAXSTRING];       /* Verify Opts or MD5 signature */
        int do_MD5;
 
+       fname = (char *)check_pool_memory_size(fname, fd->msglen);
+       jcr->fname = (char *)check_pool_memory_size(fname, fd->msglen);
        Dmsg1(50, "Atts+MD5=%s\n", fd->msg);
-       if ((len = sscanf(fd->msg, "%ld %d %s %s", &file_index, &stream, 
-            Opts_MD5, jcr->fname)) != 4) {
+       if ((len = sscanf(fd->msg, "%ld %d %100s %s", &file_index, &stream, 
+            Opts_MD5, fname)) != 4) {
           Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 4 fields got %d\n\
 msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
          jcr->JobStatus = JS_ErrorTerminated;
@@ -359,6 +362,7 @@ msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
          decode_stat(attr, &statf);  /* decode file stat packet */
          do_MD5 = FALSE;
          jcr->fn_printed = FALSE;
+         strcpy(jcr->fname, fname);  /* move filename into JCR */
 
           Dmsg2(11, "dird<filed: stream=%d %s\n", stream, jcr->fname);
           Dmsg1(20, "dird<filed: attr=%s\n", attr);
@@ -490,7 +494,6 @@ msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
          } else if (do_MD5) {
             db_escape_string(buf, Opts_MD5, strlen(Opts_MD5));
             if (strcmp(buf, fdbr.MD5) != 0) {
-               /***FIXME**** fname may not be valid */
                prt_fname(jcr);
                if (debug_level >= 10) {
                    Jmsg(jcr, M_INFO, 0, _("      MD5 not same. File=%s Cat=%s\n"), buf, fdbr.MD5);
@@ -521,6 +524,7 @@ msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
 "AND File.FileIndex!=%d AND File.PathId=Path.PathId "
 "AND File.FilenameId=Filename.FilenameId", 
       last_full_id, jcr->JobId);
+   /* missing_handler is called for each file found */
    db_sql_query(jcr->db, buf, missing_handler, (void *)jcr);
    if (jcr->fn_printed) {
       stat = JS_Differences;
index 5017929f473150cd0d2cc504902aabbad2c8cbc7..009ab8cd81422be3a3de071b5a9dfd9f0649f577 100755 (executable)
@@ -457,11 +457,11 @@ void store_int(LEX *lc, struct res_items *item, int index, int pass)
    int token;
 
    token = lex_get_token(lc);
-   if (token != T_NUMBER) {
+   if (token != T_NUMBER || !is_a_number(lc->str)) {
       scan_err1(lc, "expected an integer number, got: %s", lc->str);
    } else {
       errno = 0;
-      *(int *)(item->value) = strtol(lc->str, NULL, 0);
+      *(int *)(item->value) = (int)strtod(lc->str, NULL);
       if (errno != 0) {
          scan_err1(lc, "expected an integer number, got: %s", lc->str);
       }
@@ -476,11 +476,11 @@ void store_pint(LEX *lc, struct res_items *item, int index, int pass)
    int token;
 
    token = lex_get_token(lc);
-   if (token != T_NUMBER) {
-      scan_err1(lc, "expected an integer number, got: %s", lc->str);
+   if (token != T_NUMBER || !is_a_number(lc->str)) {
+      scan_err1(lc, "expected a positive integer number, got: %s", lc->str);
    } else {
       errno = 0;
-      token = strtol(lc->str, NULL, 0);
+      token = (int)strtod(lc->str, NULL);
       if (errno != 0 || token < 0) {
          scan_err1(lc, "expected a postive integer number, got: %s", lc->str);
       }
@@ -497,7 +497,8 @@ void store_int64(LEX *lc, struct res_items *item, int index, int pass)
    int token;
 
    token = lex_get_token(lc);
-   if (token != T_NUMBER) {
+   Dmsg2(400, "int64=:%s: %f\n", lc->str, strtod(lc->str, NULL)); 
+   if (token != T_NUMBER || !is_a_number(lc->str)) {
       scan_err1(lc, "expected an integer number, got: %s", lc->str);
    } else {
       errno = 0;
@@ -514,14 +515,16 @@ void store_size(LEX *lc, struct res_items *item, int index, int pass)
 {
    int token, i, ch;
    uint64_t value;
-   int mod[]  = {'k', 'm', 'g'};
-   uint64_t mult[] = {1024,         /* kilobyte */
+   int mod[]  = {'*', 'k', 'm', 'g', 0}; /* first item * not used */
+   uint64_t mult[] = {1,            /* byte */
+                     1024,          /* kilobyte */
                      1048576,       /* megabyte */
                      1073741824};   /* gigabyte */
 
 #ifdef we_have_a_compiler_that_works
-   int mod[]  = {'k', 'm', 'g', 't'};
-   uint64_t mult[] = {1024,         /* kilobyte */
+   int mod[]  = {'*', 'k', 'm', 'g', 't', 0};
+   uint64_t mult[] = {1,            /* byte */
+                     1024,          /* kilobyte */
                      1048576,       /* megabyte */
                      1073741824,    /* gigabyte */
                      1099511627776};/* terabyte */
@@ -532,9 +535,10 @@ void store_size(LEX *lc, struct res_items *item, int index, int pass)
    errno = 0;
    switch (token) {
    case T_NUMBER:
+      Dmsg2(400, "size num=:%s: %f\n", lc->str, strtod(lc->str, NULL)); 
       value = (uint64_t)strtod(lc->str, NULL);
       if (errno != 0 || token < 0) {
-         scan_err1(lc, "expected a size, got: %s", lc->str);
+         scan_err1(lc, "expected a size number, got: %s", lc->str);
       }
       *(uint64_t *)(item->value) = value;
       break;
@@ -547,25 +551,27 @@ void store_size(LEX *lc, struct res_items *item, int index, int pass)
         if (ISUPPER(ch)) {
            ch = tolower(ch);
         }
-        while (i < (int)sizeof(mod)) {
+        while (mod[++i] != 0) {
            if (ch == mod[i]) {
               lc->str_len--;
               lc->str[lc->str_len] = 0; /* strip modifier */
               break;
            }
-           i++;
         }
       }
-      if (i >= (int)sizeof(mod)) {
-         scan_err1(lc, "expected a size, got: %s", lc->str);
+      if (mod[i] == 0 || !is_a_number(lc->str)) {
+         scan_err1(lc, "expected a size number, got: %s", lc->str);
       }
+      Dmsg3(400, "size str=:%s: %f i=%d\n", lc->str, strtod(lc->str, NULL), i);
+
       value = (uint64_t)strtod(lc->str, NULL);
       Dmsg1(400, "Int value = %d\n", (int)value);
       if (errno != 0 || value < 0) {
-         scan_err1(lc, "expected a size, got: %s", lc->str);
+         scan_err1(lc, "expected a size number, got: %s", lc->str);
       }
-      *(uint64_t *)(item->value) = (uint64_t)(strtod(lc->str, NULL) * mult[i]);
-      Dmsg1(400, "Full value = %f\n", strtod(lc->str, NULL) * mult[i]);
+      *(uint64_t *)(item->value) = value * mult[i];
+      Dmsg2(400, "Full value = %f %" lld "\n", strtod(lc->str, NULL) * mult[i],
+         value *mult[i]);
       break;
    default:
       scan_err1(lc, "expected a size, got: %s", lc->str);
@@ -581,7 +587,7 @@ void store_size(LEX *lc, struct res_items *item, int index, int pass)
 void store_time(LEX *lc, struct res_items *item, int index, int pass)
 {
    int token, i, ch, value;
-   int  mod[]  = {'s', 'm', 'h', 'd', 'w', 'o', 'q', 'y'};
+   int  mod[]  = {'*', 's', 'm', 'h', 'd', 'w', 'o', 'q', 'y', 0};
    int mult[] = {1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, 
                  60*60*24*91, 60*60*24*365};
 
@@ -589,7 +595,7 @@ void store_time(LEX *lc, struct res_items *item, int index, int pass)
    errno = 0;
    switch (token) {
    case T_NUMBER:
-      token = strtol(lc->str, NULL, 0);
+      token = (int)strtod(lc->str, NULL);
       if (errno != 0 || token < 0) {
          scan_err1(lc, "expected a time period, got: %s", lc->str);
       }
@@ -604,17 +610,18 @@ void store_time(LEX *lc, struct res_items *item, int index, int pass)
         if (ISUPPER(ch)) {
            ch = tolower(ch);
         }
-        while (i < (int)sizeof(mod)) {
+        while (mod[++i] != 0) {
            if (ch == mod[i]) {
+              lc->str_len--;
+              lc->str[lc->str_len] = 0; /* strip modifier */
               break;
            }
-           i++;
         }
       }
-      if (i >= (int)sizeof(mod)) {
+      if (mod[i] == 0 || !is_a_number(lc->str)) {
          scan_err1(lc, "expected a time period, got: %s", lc->str);
       }
-      value = strtol(lc->str, NULL, 0);
+      value = (int)strtod(lc->str, NULL);
       if (errno != 0 || value < 0) {
          scan_err1(lc, "expected a time period, got: %s", lc->str);
       }
index fb1091ca4e60d9862ef7e956ce2c421e080ea3fd..36b1d17149d67b076a80592afa7e71bd960bc8d9 100644 (file)
@@ -138,6 +138,9 @@ char *               encode_mode             __PROTO((mode_t mode, char *buf));
 char *          edit_uint_with_commas   __PROTO((uint64_t val, char *buf));
 char *          add_commas              __PROTO((char *val, char *buf));
 int do_shell_expansion(char *name);
+int             is_a_number(const char *num);
+
+
 /*
  *void          print_ls_output         __PROTO((char *fname, char *lname, int type, struct stat *statp));
  */
index ab82295e9217bb97759e668082ced9e16b229d3e..742f373fe74ae18433a769d1e39688c2e75f82f5 100644 (file)
  */
 
 /*
- * Edit a number with commas, the supplied buffer
- * must be at least 27 bytes long.
+ * Check if specified string is a number or not.
+ *  Taken from SQLite, cool, thanks.
+ */
+int is_a_number(const char *n)
+{
+   int digit_seen = 0;
+
+   if( *n == '-' || *n == '+' ) {
+      n++;
+   }
+   while (ISDIGIT(*n)) {
+      digit_seen = 1;
+      n++;
+   }
+   if (digit_seen && *n == '.') {
+      n++;
+      while (ISDIGIT(*n)) { n++; }
+   }
+   if (digit_seen && (*n == 'e' || *n == 'E')
+       && (ISDIGIT(n[1]) || ((n[1]=='-' || n[1] == '+') && ISDIGIT(n[2])))) {
+      n += 2;                        /* skip e- or e+ */
+      while (ISDIGIT(*n)) { n++; }
+   }
+   return digit_seen && *n==0;
+}
+
+
+/*
+ * Edit an integer number with commas, the supplied buffer
+ * must be at least 27 bytes long.  The incoming number
+ * is always widened to 64 bits.
  */
 char *edit_uint_with_commas(uint64_t val, char *buf)
 {
@@ -42,6 +71,10 @@ char *edit_uint_with_commas(uint64_t val, char *buf)
    return add_commas(buf, buf);
 }
 
+/*
+ * Add commas to a string, which is presumably
+ * a number.  
+ */
 char *add_commas(char *val, char *buf)
 {
    int len, nc;
@@ -70,8 +103,7 @@ char *add_commas(char *val, char *buf)
 
 
 /* Convert a string in place to lower case */
-void 
-lcase(char *str)
+void lcase(char *str)
 {
    while (*str) {
       if (ISUPPER(*str))
index a7d3c19c0861f20bd02f16e6e51bd3401a30c1de..b064dd90701b52fe8a7903bfafe96eb58536f56d 100644 (file)
@@ -30,7 +30,7 @@
 
 /* Requests sent to the Director */
 static char Find_media[]    = "CatReq Job=%s FindMedia=%d\n";
-static char Find_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s\n";
+static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s\n";
 
 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s\
  VolJobs=%d VolFiles=%d VolBlocks=%d VolBytes=%" lld " VolMounts=%d\
@@ -46,7 +46,7 @@ static char Job_status[]   = "3012 Job %s jobstatus %d\n";
 /* Responses received from the Director */
 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%d VolFiles=%d\
  VolBlocks=%d VolBytes=%" lld " VolMounts=%d VolErrors=%d VolWrites=%d\
- VolMaxBytes=%" lld " VolCapacityBytes=%" lld "\n";
+ VolMaxBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s\n";
 
 static char OK_update[] = "1000 OK UpdateMedia\n";
 
@@ -80,7 +80,7 @@ static int do_request_volume_info(JCR *jcr)
               &vol->VolCatBlocks, &vol->VolCatBytes, 
               &vol->VolCatMounts, &vol->VolCatErrors,
               &vol->VolCatWrites, &vol->VolCatMaxBytes, 
-              &vol->VolCatCapacityBytes) != 10) {
+              &vol->VolCatCapacityBytes, vol->VolCatStatus) != 11) {
        Dmsg1(30, "Bad response from Dir: %s\n", dir->msg);
        return 0;
     }
@@ -88,7 +88,6 @@ static int do_request_volume_info(JCR *jcr)
     strcpy(jcr->VolumeName, vol->VolCatName); /* set desired VolumeName */
     
     Dmsg1(200, "Got Volume=%s\n", vol->VolCatName);
-    strcpy(vol->VolCatStatus, "Append");
     return 1;
 }
 
@@ -97,7 +96,8 @@ static int do_request_volume_info(JCR *jcr)
  * Get Volume info for a specific volume from the Director's Database
  *
  * Returns: 1 on success   (not Director guarantees that Pool and MediaType
- *                         are correct and VolStatus==Append)
+ *                         are correct and VolStatus==Append or
+ *                         VolStatus==Recycle)
  *         0 on failure
  *
  *         Volume information returned in jcr
@@ -109,7 +109,7 @@ int dir_get_volume_info(JCR *jcr)
     strcpy(jcr->VolCatInfo.VolCatName, jcr->VolumeName);
     Dmsg1(200, "dir_get_volume_info=%s\n", jcr->VolCatInfo.VolCatName);
     bash_spaces(jcr->VolCatInfo.VolCatName);
-    bnet_fsend(dir, Find_Vol_Info, jcr->Job, jcr->VolCatInfo.VolCatName);
+    bnet_fsend(dir, Get_Vol_Info, jcr->Job, jcr->VolCatInfo.VolCatName);
     return do_request_volume_info(jcr);
 }
 
index ead1ddf4d43b7b1868c52c8bc550529ee66921f5..f71b77f83f4dbcc62f63238099c89753ed5fd19e 100644 (file)
@@ -91,6 +91,7 @@ typedef struct s_volume_catalog_info {
    uint32_t VolCatErrors;             /* Number of errors this volume */
    uint32_t VolCatWrites;             /* Number of writes this volume */
    uint32_t VolCatReads;              /* Number of reads this volume */
+   uint32_t VolCatRecycles;           /* Number of recycles this volume */
    uint64_t VolCatMaxBytes;           /* max bytes to write */
    uint64_t VolCatCapacityBytes;      /* capacity estimate */
    char VolCatStatus[20];             /* Volume status */
index f92081f16d927f6a7367750f2bf0e3a8da0e73be..c577e6dfab20731428e66406d809c684889ba8c4 100644 (file)
@@ -288,6 +288,7 @@ static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *label_blk)
 static int ready_dev_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
 {
    int mounted = 0;
+   int recycle = 0;
 
    Dmsg0(100, "Enter ready_dev_for_append\n");
 
@@ -331,6 +332,9 @@ static int ready_dev_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
         case VOL_OK:
             Dmsg1(200, "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:
            /* Check if we can accept this as an anonymous volume */
@@ -387,8 +391,10 @@ mount_next_vol:
     *  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) {     /* fresh tape */
+   if (dev->VolHdr.LabelType == PRE_LABEL || recycle) {
       Dmsg1(90, "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);
@@ -415,13 +421,26 @@ mount_next_vol:
       write_volume_label_to_block(jcr, dev, block);
       dev->VolCatInfo.VolCatJobs = 1;
       dev->VolCatInfo.VolCatFiles = 1;
-      dev->VolCatInfo.VolCatMounts = 1;
       dev->VolCatInfo.VolCatErrors = 0;
-      dev->VolCatInfo.VolCatWrites = 1;
       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");
       dir_update_volume_info(jcr, &dev->VolCatInfo);
-      Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume %s on device %s\n"),
-        jcr->VolumeName, dev_name(dev));
+      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
index a2d0b62f3b665b21d0a85548ea30a58c16156485..7713d9626f5a7e483bc6ae208caa2c305d1e2933 100644 (file)
@@ -60,7 +60,7 @@ static int cancel_cmd(JCR *cjcr);
 static int mount_cmd(JCR *jcr);
 static int unmount_cmd(JCR *jcr);
 static int status_cmd(JCR *sjcr);
-static void label_device_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname);
+static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname);
 
 struct s_cmds {
    char *cmd;
@@ -260,12 +260,12 @@ static int label_cmd(JCR *jcr)
            if (open_dev(dev, volname, READ_WRITE) < 0) {
                bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
            } else {
-              label_device_if_ok(jcr, dev, volname, poolname);
+              label_volume_if_ok(jcr, dev, volname, poolname);
               force_close_dev(dev);
            }
         } else if (dev->dev_blocked && 
                    dev->dev_blocked != BST_DOING_ACQUIRE) {  /* device blocked? */
-           label_device_if_ok(jcr, dev, volname, poolname);
+           label_volume_if_ok(jcr, dev, volname, poolname);
         } else if (dev->state & ST_READ || dev->num_writers) {
            if (dev->state & ST_READ) {
                 bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
@@ -275,7 +275,7 @@ static int label_cmd(JCR *jcr)
                   dev_name(dev), dev->num_writers);
            }
         } else {                     /* device not being used */
-           label_device_if_ok(jcr, dev, volname, poolname);
+           label_volume_if_ok(jcr, dev, volname, poolname);
         }
         V(dev->mutex);
       } else {
@@ -300,7 +300,7 @@ static int label_cmd(JCR *jcr)
  *
  *  Enter with the mutex set
  */
-static void label_device_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname)
+static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname)
 {
    BSOCK *dir = jcr->dir_bsock;
    DEV_BLOCK *block;
index 33f8cc859791be7ee1294ed0f74bdc820284ba40..df061e161c114eef91a7e15b504632272c707518 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #define VERSION "1.19"
 #define VSTRING "1"
-#define DATE    "24 April 2002"
-#define LSMDATE "24Apr02"
+#define DATE    "25 April 2002"
+#define LSMDATE "25Apr02"
 
 /* Debug flags */
 #define DEBUG 1