]> git.sur5r.net Git - bacula/bacula/commitdiff
Retention period updates
authorKern Sibbald <kern@sibbald.com>
Sat, 4 May 2002 15:19:08 +0000 (15:19 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 4 May 2002 15:19:08 +0000 (15:19 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@14 91ce42f0-d328-0410-95d8-f526ca767f89

25 files changed:
bacula/src/Makefile.in
bacula/src/cats/cats.h
bacula/src/cats/make_mysql_tables.in
bacula/src/cats/make_sqlite_tables.in
bacula/src/cats/mysql.c
bacula/src/cats/protos.h
bacula/src/cats/sql.c
bacula/src/cats/sql_create.c
bacula/src/cats/sql_get.c
bacula/src/cats/sqlite.c
bacula/src/console/console.c
bacula/src/dird/backup.c
bacula/src/dird/dird_conf.c
bacula/src/dird/dird_conf.h
bacula/src/dird/newvol.c
bacula/src/dird/restore.c
bacula/src/dird/ua.h
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_input.c
bacula/src/dird/ua_output.c
bacula/src/dird/ua_prune.c
bacula/src/dird/ua_purge.c
bacula/src/dird/ua_select.c
bacula/src/dird/ua_server.c
bacula/src/dird/verify.c

index 00e075d1b34cebb8ee5a63ba8900511bae104f34..ee55b709d42d51481ed9efcdf2901e5dac0b3ae3 100644 (file)
@@ -1,4 +1,5 @@
 #
+# $Id$
 #
 @MCOMMON@
 
index 6968b0a6a483b0ef8a69f589a299743128f1581f..5c50c0bfd7b78e005e601736e3213a4a2d8d603b 100644 (file)
@@ -171,7 +171,7 @@ typedef struct s_db {
 /* Change this each time there is some incompatible
  * file format change!!!!
  */
-#define BDB_VERSION 7                 /* file version number */
+#define BDB_VERSION 8                 /* file version number */
 
 struct s_control {
    int bdb_version;                   /* Version number */
@@ -238,7 +238,7 @@ typedef uint32_t JobId_t;
  */
 /* Job record */
 typedef struct {
-   uint32_t JobId;
+   JobId_t JobId;
    char Job[MAX_NAME_LENGTH];         /* Job unique name */
    char Name[MAX_NAME_LENGTH];        /* Job base name */
    int Type;                          /* actually char(1) */
@@ -250,6 +250,7 @@ typedef struct {
    time_t SchedTime;                  /* Time job scheduled */
    time_t StartTime;                  /* Job start time */
    time_t EndTime;                    /* Job termination time */
+   btime_t StartDay;                  /* Start time/date in seconds */
    uint32_t VolSessionId;
    uint32_t VolSessionTime;
    uint32_t JobFiles;
@@ -280,7 +281,7 @@ typedef struct {
 /* JobMedia record */
 typedef struct {
    uint32_t JobMediaId;               /* record id */
-   uint32_t JobId;                    /* JobId */
+   JobId_t  JobId;                    /* JobId */
    uint32_t MediaId;                  /* MediaId */
    uint32_t FirstIndex;               /* First index this Volume */
    uint32_t LastIndex;                /* Last index this Volume */
@@ -291,8 +292,6 @@ typedef struct {
 } JOBMEDIA_DBR;
 
 
-
-
 /* Attributes record -- NOT same as in database because
  *  in general, this "record" creates multiple database
  *  records (e.g. pathname, filename, fileattributes).
@@ -303,7 +302,7 @@ typedef struct {
    char *attr;                        /* attributes statp */
    uint32_t FileIndex;
    uint32_t Stream;
-   uint32_t JobId;
+   JobId_t  JobId;
    uint32_t ClientId;
    uint32_t PathId;
    uint32_t FilenameId;
@@ -315,7 +314,7 @@ typedef struct {
 typedef struct {
    FileId_t FileId;
    uint32_t FileIndex;
-   uint32_t JobId;
+   JobId_t  JobId;
    uint32_t FilenameId;
    uint32_t PathId;
    char LStat[256];
@@ -333,7 +332,8 @@ typedef struct {
    int UseCatalog;                    /* set to use catalog */
    int AcceptAnyVolume;               /* set to accept any volume sequence */
    int AutoRecycle;                   /* set to recycle automatically */
-   uint32_t VolumeRetention;          /* retention period in seconds */
+   int Recycle;                       /* default Vol recycle flag */
+   btime_t VolumeRetention;           /* retention period in seconds */
    char PoolType[MAX_NAME_LENGTH];             
    char LabelFormat[MAX_NAME_LENGTH];
    /* Extra stuff not in DB */
@@ -359,8 +359,9 @@ typedef struct {
    uint64_t VolBytes;                 /* Number of bytes written */
    uint64_t VolMaxBytes;              /* max bytes to write */
    uint64_t VolCapacityBytes;         /* capacity estimate */
+   btime_t  VolRetention;             /* Volume retention in seconds */
+   int Recycle;                       /* recycle yes/no */
    char VolStatus[20];                /* Volume status */
-   char Recycle[20];                  /* Recycle yes/no */
    /* Extra stuff not in DB */
    faddr_t rec_addr;                  /* found record address */
 } MEDIA_DBR;
@@ -368,6 +369,9 @@ typedef struct {
 /* Client record -- same as the database */
 typedef struct {
    uint32_t ClientId;                 /* Unique Client id */
+   int AutoPrune;
+   btime_t FileRetention;
+   btime_t JobRetention;
    char Name[MAX_NAME_LENGTH];        /* Client name */
    char Uname[256];                   /* Uname for client */
 } CLIENT_DBR;
index 6ae35962fea385fcafd3cf7c728aad3350dcf878..2c155f99137a06eb7a016084e15fef787bda99d1 100644 (file)
@@ -104,7 +104,8 @@ CREATE TABLE Media (
    VolCapacityBytes BIGINT UNSIGNED NOT NULL,
    VolStatus ENUM('Full', 'Archive', 'Append', 'Recycle', 'Purged',
     'Read-Only', 'Disabled', 'Error', 'Busy') NOT NULL,
-   Recycle ENUM('No', 'Yes') NOT NULL,
+   Recycle TINYINT NOT NULL,
+   VolRetention BIGINT UNSIGNED NOT NULL,
    PRIMARY KEY(MediaId),
    INDEX (PoolId)
    );
@@ -117,6 +118,9 @@ CREATE TABLE Pool (
    UseOnce TINYINT NOT NULL,
    UseCatalog TINYINT NOT NULL,
    AcceptAnyVolume TINYINT NOT NULL,
+   VolRetention BIGINT NOT NULL,
+   AutoRecycle TINYINT NOT NULL,
+   Recycle TINYINT NOT NULL,
    PoolType ENUM('Backup', 'Copy', 'Cloned', 'Archive', 'Migration') NOT NULL,
    LabelFormat TINYBLOB,
    UNIQUE (Name(128)),
@@ -128,10 +132,21 @@ CREATE TABLE Client (
    ClientId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
    Name TINYBLOB NOT NULL,
    Uname TINYBLOB NOT NULL,      /* full uname -a of client */
+   AutoPrune TINYINT NOT NULL,
+   FileRetention BIGINT NOT NULL,
+   JobRetention  BIGINT NOT NULL,
    UNIQUE (Name(128)),
    PRIMARY KEY(ClientId)
    );
 
+CREATE TABLE Version (
+   VersionId INTEGER UNSIGNED NOT NULL 
+   );
+
+-- Initialize Version           
+INSERT INTO Version (VersionId) VALUES (1);
+
+
 ## Experimental
 #CREATE TABLE FileSave (
 #   FileSaveId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
index f811e69873cb539f47d02ccd1391d1016f1e6f27..ad51ac11ddb969df15f789cd1d9c111b788cfae1 100644 (file)
@@ -42,7 +42,7 @@ CREATE TABLE Job (
    SchedTime DATETIME NOT NULL,
    StartTime DATETIME DEFAULT 0,
    EndTime DATETIME DEFAULT 0,
-   StartDay INTEGER UNSIGNED DEFAULT 0,
+   StartDay BIGINT UNSIGNED DEFAULT 0,
    VolSessionId INTEGER UNSIGNED DEFAULT 0,
    VolSessionTime INTEGER UNSIGNED DEFAULT 0,
    JobFiles INTEGER UNSIGNED DEFAULT 0,
@@ -93,7 +93,8 @@ CREATE TABLE Media (
    VolMaxBytes BIGINT UNSIGNED DEFAULT 0,
    VolCapacityBytes BIGINT UNSIGNED DEFAULT 0,
    VolStatus VARCHAR(20) NOT NULL,
-   Recycle VARCHAR(20) NOT NULL,
+   Recycle TINYINT NOT NULL,
+   VolRetention BIGINT UNSIGNED NOT NULL,
    PRIMARY KEY(MediaId)
    );
 
@@ -105,6 +106,9 @@ CREATE TABLE Pool (
    UseOnce TINYINT NOT NULL,
    UseCatalog TINYINT NOT NULL,
    AcceptAnyVolume TINYINT NOT NULL,
+   VolRetention BIGINT NOT NULL,
+   AutoRecycle TINYINT NOT NULL,
+   Recycle TINYINT NOT NULL,
    PoolType VARCHAR(20) NOT NULL,
    LabelFormat VARCHAR(128) NOT NULL,
    UNIQUE (Name),
@@ -116,6 +120,9 @@ CREATE TABLE Client (
    ClientId INTEGER UNSIGNED AUTOINCREMENT,
    Name VARCHAR(128) NOT NULL,
    Uname VARCHAR(255) NOT NULL,   -- uname -a field
+   AutoPrune TINYINT NOT NULL,
+   FileRetention BIGINT NOT NULL,
+   JobRetention  BIGINT NOT NULL,
    UNIQUE (Name),
    PRIMARY KEY(ClientId)
    );
@@ -129,6 +136,14 @@ CREATE TABLE NextId (
 -- Initialize JobId to start at 1
 INSERT INTO NextId (id, TableName) VALUES (1, "Job");
 
+CREATE TABLE Version (
+   VersionId INTEGER UNSIGNED NOT NULL 
+   );
+
+-- Initialize Version           
+INSERT INTO Version (VersionId) VALUES (1);
+
+
 -- Experimental stuff below. Not used.
 -- Invariant part of File
 CREATE TABLE BaseFile (
index f420b21f57437e94ed512c3d8e2acc3172190969..e251ae94b6cc2faf137c7b6c06b9664841397447 100644 (file)
@@ -141,6 +141,12 @@ It is probably not running or your password is incorrect.\n"),
       V(mutex);
       return 0;
    }
+
+   if (!check_tables_version(mdb)) {
+      V(mutex);
+      return 0;
+   }
+
    mdb->connected = TRUE;
    V(mutex);
    return 1;
index 59335b2edcde9e5ab84524670d75f3b56aa7b473..68b931fe35df4a8f1c2fecbe4f67359c793649b0 100644 (file)
@@ -34,6 +34,7 @@ char *db_strerror(B_DB *mdb);
 int get_sql_record_max(B_DB *mdb);
 char *db_next_index(B_DB *mdb, char *table);
 int db_sql_query(B_DB *mdb, char *cmd, DB_RESULT_HANDLER *result_handler, void *ctx);
+int check_tables_version(B_DB *mdb);
 
 /* create.c */
 int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar);
index 213cc4acf8f7c37b01eef178d9aa5f5c06f0634d..21fdbe4436bae7a71d101d481a90e2b7e2062294 100644 (file)
@@ -46,6 +46,13 @@ void print_result(B_DB *mdb);
  *  calling subroutine sets and clears the mutex
  */
 
+/* Check that the tables conrrespond to the version we want */
+int check_tables_version(B_DB *mdb)
+{
+/*****FIXME***** implement */
+   return 1;
+}
+
 /* Utility routine for queries */
 int
 QueryDB(char *file, int line, B_DB *mdb, char *cmd)
index 129e96249890089625971d1cea61f63428a7432e..73aa0c78137dd1f6ad3d47a100a020d790acc5bc 100644 (file)
@@ -160,6 +160,7 @@ int
 db_create_pool_record(B_DB *mdb, POOL_DBR *pool_dbr)
 {
    int stat;
+   char ed1[30];
 
    P(mdb->mutex);
    Mmsg(&mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name=\"%s\"", pool_dbr->Name);
@@ -181,12 +182,14 @@ db_create_pool_record(B_DB *mdb, POOL_DBR *pool_dbr)
    /* Must create it */
    Mmsg(&mdb->cmd, 
 "INSERT INTO Pool (Name, NumVols, MaxVols, UseOnce, UseCatalog, \
-AcceptAnyVolume, PoolType, LabelFormat) \
-VALUES (\"%s\", %d, %d, %d, %d, %d, \"%s\", \"%s\")", 
+AcceptAnyVolume, AutoRecycle, Recycle, VolumeRetention, PoolType, LabelFormat) \
+VALUES (\"%s\", %d, %d, %d, %d, %d, %d, %d, %s \"%s\", \"%s\")", 
                  pool_dbr->Name,
                  pool_dbr->NumVols, pool_dbr->MaxVols,
                  pool_dbr->UseOnce, pool_dbr->UseCatalog,
                  pool_dbr->AcceptAnyVolume,
+                 pool_dbr->AutoRecycle, pool_dbr->Recycle,
+                 edit_uint64(pool_dbr->VolumeRetention, ed1),
                  pool_dbr->PoolType, pool_dbr->LabelFormat);
 
    if (!INSERT_DB(mdb, mdb->cmd)) {
@@ -213,7 +216,7 @@ int
 db_create_media_record(B_DB *mdb, MEDIA_DBR *mr)
 {
    int stat;
-   char ed1[30], ed2[30];
+   char ed1[30], ed2[30], ed3[30];
 
    P(mdb->mutex);
    Mmsg(&mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName=\"%s\"", 
@@ -234,12 +237,14 @@ db_create_media_record(B_DB *mdb, MEDIA_DBR *mr)
    /* Must create it */
    Mmsg(&mdb->cmd, 
 "INSERT INTO Media (VolumeName, MediaType, PoolId, VolMaxBytes, VolCapacityBytes, \
-VolStatus, Recycle) VALUES (\"%s\", \"%s\", %d, %s, %s, \"%s\", \"%s\")", 
+VolStatus, Recycle) VALUES (\"%s\", \"%s\", %d, %s, %s, %d, %s, \"%s\")", 
                  mr->VolumeName,
                  mr->MediaType, mr->PoolId, 
                  edit_uint64(mr->VolMaxBytes,ed1),
                  edit_uint64(mr->VolCapacityBytes, ed2),
-                 mr->VolStatus, mr->Recycle);
+                 mr->Recycle,
+                 edit_uint64(mr->VolRetention, ed3),
+                 mr->VolStatus);
 
    if (!INSERT_DB(mdb, mdb->cmd)) {
       Mmsg2(&mdb->errmsg, _("Create DB Media record %s failed. ERR=%s\n"),
@@ -264,6 +269,7 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr)
 {
    SQL_ROW row;
    int stat;
+   char ed1[30], ed2[30];
 
    P(mdb->mutex);
    Mmsg(&mdb->cmd, "SELECT ClientId FROM Client WHERE Name=\"%s\"", cr->Name);
@@ -295,8 +301,11 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr)
    }
 
    /* Must create it */
-   Mmsg(&mdb->cmd, "INSERT INTO Client (Name, Uname) VALUES \
-(\"%s\", \"%s\")", cr->Name, cr->Uname);
+   Mmsg(&mdb->cmd, "INSERT INTO Client (Name, Uname, AutoPrune, \
+FileRetention, JobRetention) VALUES \
+(\"%s\", \"%s\")", cr->Name, cr->Uname, cr->AutoPrune,
+      edit_uint64(cr->FileRetention, ed1),
+      edit_uint64(cr->JobRetention, ed2));
 
    if (!INSERT_DB(mdb, mdb->cmd)) {
       Mmsg2(&mdb->errmsg, _("Create DB Client record %s failed. ERR=%s\n"),
index c0e27e54e6051ee5cceb27540c404467d32af7d8..aa1e39e8044d6fa220c66fd58bbf2bda90dc4655 100644 (file)
@@ -273,11 +273,11 @@ int db_get_job_record(B_DB *mdb, JOB_DBR *jr)
    P(mdb->mutex);
    if (jr->JobId == 0) {
       Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
-PoolId, StartTime, EndTime, JobFiles, JobBytes, Job \
+PoolId, StartTime, EndTime, JobFiles, JobBytes, StartDay, Job \
 FROM Job WHERE Job=\"%s\"", jr->Job);
     } else {
       Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \
-PoolId, StartTime, EndTime, JobFiles, JobBytes, Job \
+PoolId, StartTime, EndTime, JobFiles, JobBytes, StartDay, Job \
 FROM Job WHERE JobId=%d", jr->JobId);
     }
 
@@ -299,7 +299,8 @@ FROM Job WHERE JobId=%d", jr->JobId);
    strcpy(jr->cEndTime, row[4]);
    jr->JobFiles = atol(row[5]);
    jr->JobBytes = (uint64_t)strtod(row[6], NULL);
-   strcpy(jr->Job, row[7]);
+   jr->StartDay = (btime_t)strtod(row[7], NULL);
+   strcpy(jr->Job, row[8]);
    sql_free_result(mdb);
 
    V(mdb->mutex);
index b9a43ce64d580c3482bbb13bed9e954126f42ad6..bbe0d09f1050ddf42dc77fefde77d687fe8da400 100644 (file)
@@ -137,6 +137,11 @@ db_open_database(B_DB *mdb)
       return 0;
    }
    free(db_name);
+   if (!check_tables_version(mdb)) {
+      V(mutex);
+      return 0;
+   }
+
    mdb->connected = TRUE;
    V(mutex);
    return 1;
index 0fac356507b79f3a3be79b8eb70b32f9a9c146c1..3108ef206ba3f64c3966eceecf8abe8c9e01fcc1 100644 (file)
@@ -43,7 +43,7 @@ extern int rl_catch_signals;
 
 /* Forward referenced functions */
 static void terminate_console(int sig);
-int get_cmd(char *prompt, BSOCK *sock, int sec);
+int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec);
 
 /* Static variables */
 static char *configfile = NULL;
@@ -69,6 +69,64 @@ static void usage()
    exit(1);
 }
 
+static void read_and_process_input(FILE *input, BSOCK *UA_sock) 
+{
+   char *prompt = "*";
+   int at_prompt = FALSE;
+   int tty_input = isatty(fileno(input));
+   int stat;
+
+   for ( ;; ) { 
+      if (at_prompt) {                /* don't prompt multiple times */
+         prompt = "";
+      } else {
+         prompt = "*";
+        at_prompt = TRUE;
+      }
+      if (tty_input) {
+        stat = get_cmd(input, prompt, UA_sock, 30);
+      } else {
+        int len = sizeof_pool_memory(UA_sock->msg) - 1;
+        if (fgets(UA_sock->msg, len, input) == NULL) {
+           stat = -1;
+        } else {
+           strip_trailing_junk(UA_sock->msg);
+           UA_sock->msglen = strlen(UA_sock->msg);
+           stat = 1;
+        }
+      }
+      if (stat < 0) { 
+        break;                       /* error */
+      } else if (stat == 0) {        /* timeout */
+         bnet_fsend(UA_sock, ".messages");
+      } else {
+        at_prompt = FALSE;
+        if (!bnet_send(UA_sock)) {   /* send command */
+           break;                    /* error */
+        }
+      }
+      if (strcmp(UA_sock->msg, "quit") == 0 || strcmp(UA_sock->msg, "exit") == 0) {
+        break;
+      }
+      while ((stat = bnet_recv(UA_sock)) > 0) {
+        if (at_prompt) {
+            fprintf(output, "\n");
+           at_prompt = FALSE;
+        }
+         printf("%s", UA_sock->msg);
+      }
+      fflush(output);
+      if (stat < 0) {
+        break;                       /* error */
+      } else if (stat == 0) {
+        if (UA_sock->msglen == BNET_PROMPT) {
+           at_prompt = TRUE;
+        }
+         Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
+      }
+   }
+}
+
 
 /*********************************************************************
  *
@@ -77,12 +135,10 @@ static void usage()
  */
 int main(int argc, char *argv[])
 {
-   int ch, stat, i, ndir, item;
+   int ch, i, ndir, item;
    int no_signals = FALSE;
    int test_config = FALSE;
    JCR jcr;
-   char *prompt = "*";
-   int at_prompt = FALSE;
 
    init_stack_dump();
    my_name_is(argc, argv, "console");
@@ -171,7 +227,7 @@ try_again:
            dir->DIRport);
       }
       UnlockRes();
-      if (get_cmd("Select Director: ", UA_sock, 600) < 0) {
+      if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) {
         return 1;
       }
       item = atoi(UA_sock->msg);
@@ -209,44 +265,8 @@ try_again:
 
    Dmsg0(40, "Opened connection with Director daemon\n");
 
-   for ( ;; ) { 
-      if (at_prompt) {                /* don't prompt multiple times */
-         prompt = "";
-      } else {
-         prompt = "*";
-        at_prompt = TRUE;
-      }
-      stat = get_cmd(prompt, UA_sock, 30);
-      if (stat < 0) { 
-        break;                       /* error */
-      } else if (stat == 0) {        /* timeout */
-         bnet_fsend(UA_sock, ".messages");
-      } else {
-        at_prompt = FALSE;
-        if (!bnet_send(UA_sock)) {   /* send command */
-           break;                    /* error */
-        }
-      }
-      if (strcmp(UA_sock->msg, "quit") == 0 || strcmp(UA_sock->msg, "exit") == 0) {
-        break;
-      }
-      while ((stat = bnet_recv(UA_sock)) > 0) {
-        if (at_prompt) {
-            printf("\n");
-           at_prompt = FALSE;
-        }
-         printf("%s", UA_sock->msg);
-      }
-      fflush(stdout);
-      if (stat < 0) {
-        break;                       /* error */
-      } else if (stat == 0) {
-        if (UA_sock->msglen == BNET_PROMPT) {
-           at_prompt = TRUE;
-        }
-         Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
-      }
-   }
+   read_and_process_input(stdin, UA_sock);
+
    if (UA_sock) {
       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
       bnet_close(UA_sock);
@@ -273,8 +293,9 @@ static void terminate_console(int sig)
 #include "readline/readline.h"
 #include "readline/history.h"
 
+
 int 
-get_cmd(char *prompt, BSOCK *sock, int sec)
+get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
 {
    char *line;
 
@@ -334,17 +355,19 @@ wait_for_data(int fd, int sec)
  *          -1 if EOF or error
  */
 int 
-get_cmd(char *prompt, BSOCK *sock, int sec)
+get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
 {
+   int len;  
    fprintf(output, prompt);
    fflush(output);
-   switch (wait_for_data(fileno(stdin), sec)) {
+   switch (wait_for_data(fileno(input), sec)) {
       case 0:
         return 0;                    /* timeout */
       case -1: 
         return -1;                   /* error */
       default:
-        if (fgets(sock->msg, 200, stdin) == NULL) {
+        len = sizeof_pool_memory(sock->msg) - 1;
+        if (fgets(sock->msg, len, input) == NULL) {
            return -1;
         }
         break;
index 7d6950d7cc841b3ba6be247bd747691520d30eb4..92c1f6e200e415b48acb7429a83b06ae539cb045 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "bacula.h"
 #include "dird.h"
+#include "ua.h"
 
 /* Commands sent to File daemon */
 static char backupcmd[] = "backup\n";
@@ -79,6 +80,9 @@ int do_backup(JCR *jcr)
     */
    memset(&cr, 0, sizeof(cr));
    strcpy(cr.Name, jcr->client->hdr.name);
+   cr.AutoPrune = jcr->client->AutoPrune;
+   cr.FileRetention = jcr->client->FileRetention;
+   cr.JobRetention = jcr->client->JobRetention;
    if (jcr->client_name) {
       free(jcr->client_name);
    }
index e59dcaf3266aab13395e0039277b0d4edd924594..8689a33b08e85e58172a3ceb7fae768fefb295b0 100644 (file)
@@ -207,16 +207,17 @@ static struct res_items group_items[] = {
  */
 static struct res_items pool_items[] = {
    {"name",            store_name,    ITEM(res_pool.hdr.name),        0, ITEM_REQUIRED, 0},
-   {"description",     store_str,     ITEM(res_pool.hdr.desc),        0, 0,             0},
+   {"description",     store_str,     ITEM(res_pool.hdr.desc),        0, 0,     0},
    {"pooltype",        store_strname, ITEM(res_pool.pool_type),       0, ITEM_REQUIRED, 0},
-   {"labelformat",     store_strname, ITEM(res_pool.label_format),    0, 0,             0},
+   {"labelformat",     store_strname, ITEM(res_pool.label_format),    0, 0,     0},
    {"usecatalog",      store_yesno, ITEM(res_pool.use_catalog),     1, ITEM_DEFAULT,  1},
-   {"usevolumeonce",   store_yesno, ITEM(res_pool.use_volume_once), 1, 0,             0},
+   {"usevolumeonce",   store_yesno, ITEM(res_pool.use_volume_once), 1, 0,       0},
    {"maximumvolumes",  store_pint,  ITEM(res_pool.max_volumes),     0, 0,             0},
-   {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, 0,           0},
+   {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, 0,     0},
    {"catalogfiles",    store_yesno, ITEM(res_pool.catalog_files),   1, ITEM_DEFAULT,  1},
    {"volumeretention", store_time,  ITEM(res_pool.VolumeRetention), 0, ITEM_DEFAULT, 60*60*24*365},
-   {"autorecycle",     store_yesno, ITEM(res_pool.AutoRecycle), 0, ITEM_DEFAULT, 1},
+   {"autorecycle",     store_yesno, ITEM(res_pool.AutoRecycle), 1, ITEM_DEFAULT, 1},
+   {"recycle",         store_yesno, ITEM(res_pool.Recycle),     1, ITEM_DEFAULT, 1},
    {NULL, NULL, NULL, 0, 0, 0} 
 };
 
index d8c899cc6e66fe8b518748e04a23f7433e3b0603..8f1753440ee766c5add54de6b74b0c93b2dd6031 100644 (file)
@@ -214,7 +214,8 @@ struct s_res_pool {
    int   accept_any_volume;           /* accept any volume */
    int   max_volumes;                 /* max number of volumes */
    btime_t VolumeRetention;           /* volume retention period in seconds */
-   int   AutoRecycle;                 /* auto recycle */
+   int   AutoRecycle;                 /* default for pool auto recycle */
+   int   Recycle;                     /* default for media recycle yes/no */
 };
 typedef struct s_res_pool POOL;
 
index 1f7dda17149565a7772c628123c25a9bc7b4229e..e3982203d9e57363d9a06d2735cedc4fdc821674 100644 (file)
@@ -59,7 +59,8 @@ int newVolume(JCR *jcr)
          strcat(name, "%04d");
         sprintf(mr.VolumeName, name, ++pr.NumVols);
          strcpy(mr.VolStatus, "Append");
-         strcpy(mr.Recycle, "No");
+        mr.Recycle = pr.Recycle;
+        mr.VolRetention = pr.VolumeRetention;
         if (db_create_media_record(jcr->db, &mr) &&
            db_update_pool_record(jcr->db, &pr) == 1) {
             Dmsg1(90, "Created new Volume=%s\n", mr.VolumeName);
index 35accb51c659a09ce978b12f6c915e12e66b26c6..51581b34a65c6cc25a14d919aa5111bc67cac62f 100644 (file)
@@ -75,6 +75,9 @@ int do_restore(JCR *jcr)
     */
    memset(&cr, 0, sizeof(cr));
    strcpy(cr.Name, jcr->client->hdr.name);
+   cr.AutoPrune = jcr->client->AutoPrune;
+   cr.FileRetention = jcr->client->FileRetention;
+   cr.JobRetention = jcr->client->JobRetention;
    if (jcr->client_name) {
       free(jcr->client_name);
    }
index 28e979949123a90f2d3191c5eed8e3cf3280c180..3fa6f25a3bbadb421d4d49fb2f58dd8d87e2d350 100644 (file)
@@ -31,17 +31,19 @@ typedef struct s_ua_context {
    JCR *jcr;
    B_DB *db;
    CAT *catalog;
-   char *cmd;                        /* return command/name buffer */
-   char *args;                       /* command line arguments */
-   char *argk[MAX_ARGS];             /* argument keywords */
-   char *argv[MAX_ARGS];             /* argument values */
-   int argc;                         /* number of arguments */
-   char **prompt;                    /* list of prompts */
-   int max_prompts;                  /* max size of list */
-   int num_prompts;                  /* current number in list */
-   int auto_display_messages;        /* if set, display messages */
+   char *cmd;                         /* return command/name buffer */
+   char *args;                        /* command line arguments */
+   char *argk[MAX_ARGS];              /* argument keywords */
+   char *argv[MAX_ARGS];              /* argument values */
+   int argc;                          /* number of arguments */
+   char **prompt;                     /* list of prompts */
+   int max_prompts;                   /* max size of list */
+   int num_prompts;                   /* current number in list */
+   int auto_display_messages;         /* if set, display messages */
    int user_notified_msg_pending;     /* set when user notified */
-   int automount;                    /* if set, mount after label */
+   int automount;                     /* if set, mount after label */
+   int quit;                          /* if set, quit */
+   int verbose;                       /* set for normal UA verbosity */
 } UAContext;
 
 /* ua_cmds.c */
@@ -73,7 +75,7 @@ int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
 void   start_prompt(UAContext *ua, char *msg);
 void   add_prompt(UAContext *ua, char *prompt);
 int    do_prompt(UAContext *ua, char *msg, char *prompt);
-CAT   *get_catalog_resource(UAContext *ua);          
+CAT   *get_catalog_resource(UAContext *ua);           
 STORE *get_storage_resource(UAContext *ua, char *cmd);
 int    get_media_type(UAContext *ua, char *MediaType);
 int    get_pool_dbr(UAContext *ua, POOL_DBR *pr);
index f2b137a375137ba4fc51c7839b641e3135d6c1a4..ff24bb6b14e0d31158b3490302ad72314b479f5e 100644 (file)
@@ -241,7 +241,8 @@ getVolName:
           
    mr.PoolId = pr.PoolId;
    strcpy(mr.VolStatus, "Append");
-   strcpy(mr.Recycle, "No");
+   mr.Recycle = pr.Recycle;
+   mr.VolRetention = pr.VolumeRetention;
    for (i=startnum; i < num+startnum; i++) { 
       sprintf(mr.VolumeName, name, i);
       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
@@ -1028,8 +1029,9 @@ gotVol:
       return 1;
    }
    mr.PoolId = pr.PoolId;
-   strcpy(mr.Recycle, "Yes");
    strcpy(mr.VolStatus, "Append");
+   mr.Recycle = pr.Recycle;
+   mr.VolRetention = pr.VolumeRetention;
 
    ua->jcr->store = store;
    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
@@ -1064,7 +1066,9 @@ gotVol:
            mr.VolumeName);
         if (ua->automount) {
             bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
+           bash_spaces(dev_name);
             bnet_fsend(sd, "mount %s", dev_name);
+           unbash_spaces(dev_name);
            while (bnet_recv(sd) > 0) {
                bsendmsg(ua, "%s", sd->msg);
               /* Here we can get
@@ -1181,7 +1185,8 @@ static int usecmd(UAContext *ua, char *cmd)
 
 int quitcmd(UAContext *ua, char *cmd) 
 {
-   return 0;
+   ua->quit = TRUE;
+   return 1;
 }
 
 static int helpcmd(UAContext *ua, char *cmd)
index bd88cceb2b5c6d14c10a1bd91a5a82193c89736b..9a24d052b1b2404be6593a716e2eefdda5ecf630 100644 (file)
@@ -40,6 +40,9 @@ int get_cmd(UAContext *ua, char *prompt)
    BSOCK *sock = ua->UA_sock;
 
    ua->cmd[0] = 0;
+   if (!sock) {                      /* No UA */
+      return 0;
+   }
    bnet_fsend(sock, "%s", prompt);
    bnet_sig(sock, BNET_PROMPT);       /* request more input */
    for ( ;; ) {
index a7a97df109eaf41745904873c8b3cef97eb62675..ff572affa4bf412ae64a52890f23641a1b24d4dd 100644 (file)
@@ -168,35 +168,6 @@ int showcmd(UAContext *ua, char *cmd)
 }
 
 
-/*
- * Callback routine for "printing" database file listing
- */
-void prtit(void *ctx, char *msg)
-{
-   UAContext *ua = (UAContext *)ctx;
-   bnet_fsend(ua->UA_sock, "%s", msg);
-}
-
-/* Format message and send to other end */
-void bsendmsg(void *ctx, char *fmt, ...)
-{
-   va_list arg_ptr;
-   UAContext *ua = (UAContext *)ctx;
-   BSOCK *bs = ua->UA_sock;
-   int maxlen;
-
-again:
-   maxlen = sizeof_pool_memory(bs->msg) - 1;
-   va_start(arg_ptr, fmt);
-   bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr);
-   va_end(arg_ptr);
-   if (bs->msglen < 0 || bs->msglen >= maxlen) {
-      bs->msg = (char *) realloc_pool_memory(bs->msg, maxlen + 200);
-      goto again;
-   }
-   bnet_send(bs);
-}
 
 
 /*
@@ -385,3 +356,54 @@ int messagescmd(UAContext *ua, char *cmd)
    }
    return 1;
 }
+
+/*
+ * Callback routine for "printing" database file listing
+ */
+void prtit(void *ctx, char *msg)
+{
+   UAContext *ua = (UAContext *)ctx;
+   bnet_fsend(ua->UA_sock, "%s", msg);
+}
+
+/* 
+ * Format message and send to other end.  
+
+ * If the UA_sock is NULL, it means that there is no user
+ * agent, so we are being called from Bacula core. In
+ * that case direct the messages to the Job.
+ */
+void bsendmsg(void *ctx, char *fmt, ...)
+{
+   va_list arg_ptr;
+   UAContext *ua = (UAContext *)ctx;
+   BSOCK *bs = ua->UA_sock;
+   int maxlen, len;
+   char *msg;
+
+   if (bs) {
+      msg = bs->msg;
+   } else {
+      msg = (char *)get_pool_memory(PM_EMSG);
+   }
+
+again:
+   maxlen = sizeof_pool_memory(msg) - 1;
+   va_start(arg_ptr, fmt);
+   len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
+   va_end(arg_ptr);
+   if (len < 0 || len >= maxlen) {
+      msg = (char *) realloc_pool_memory(msg, maxlen + 200);
+      goto again;
+   }
+
+   if (bs) {
+      bs->msglen = len;
+      bnet_send(bs);
+   } else {                          /* No UA, send to Job */
+      Jmsg(ua->jcr, M_INFO, 0, msg);
+      free_memory(msg);
+   }
+
+}
index 389ac441df82d07939e98ce4d5772a82db705734..c8c697cb31c04ae56d7fb5bff2e6f611db498cd3 100644 (file)
@@ -34,6 +34,7 @@
 int prune_files(UAContext *ua, CLIENT *client);
 int prune_jobs(UAContext *ua, CLIENT *client);
 int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
+static int mark_media_purged(UAContext *ua, MEDIA_DBR *mr);
 
 
 #define MAX_DEL_LIST_LEN 1000000
@@ -184,6 +185,10 @@ static int file_delete_handler(void *ctx, int num_fields, char **row)
 
 /*
  *   Prune records from database
+ *
+ *    prune files (from) client=xxx
+ *    prune jobs (from) client=xxx
+ *    prune volume=xxx 
  */
 int prunecmd(UAContext *ua, char *cmd)
 {
@@ -262,6 +267,7 @@ int prune_files(UAContext *ua, CLIENT *client)
    char ed1[50];
 
    memset(&cr, 0, sizeof(cr));
+   memset(&del, 0, sizeof(del));
    strcpy(cr.Name, client->hdr.name);
    if (!db_create_client_record(ua->db, &cr)) {
       return 0;
@@ -273,12 +279,6 @@ int prune_files(UAContext *ua, CLIENT *client)
    today = (uint64_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) -
        date_encode(2000, 1, 1));
        
-   del.JobId = NULL;
-   del.num_ids = 0;
-   del.tot_ids = 0;
-   del.num_del = 0;
-   del.max_ids = 0;
-
    Dmsg3(100, "Today=%d period=%d period=%d\n", (uint32_t)today, (uint32_t)period,          
       (uint32_t)(period/(3600*24)));
 
@@ -375,12 +375,13 @@ int prune_jobs(UAContext *ua, CLIENT *client)
    char *query = (char *)get_pool_memory(PM_MESSAGE);
    int i;
    struct tm tm;
-   uint64_t today, period;
+   btime_t today, period;
    time_t now;
    CLIENT_DBR cr;
    char ed1[50];
 
    memset(&cr, 0, sizeof(cr));
+   memset(&del, 0, sizeof(del));
    strcpy(cr.Name, client->hdr.name);
    if (!db_create_client_record(ua->db, &cr)) {
       return 0;
@@ -389,16 +390,10 @@ int prune_jobs(UAContext *ua, CLIENT *client)
    period = client->JobRetention;
    now = time(NULL);
    localtime_r(&now, &tm);
-   today = (uint64_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) -
+   today = (btime_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) -
        date_encode(2000, 1, 1));
        
 
-   del.JobId = NULL;
-   del.num_ids = 0;
-   del.tot_ids = 0;
-   del.num_del = 0;
-   del.max_ids = 0;
-
    Dmsg3(050, "Today=%d period=%d period=%d\n", (uint32_t)today, (uint32_t)period,          
       (uint32_t)(period/(3600*24)));
 
@@ -493,7 +488,16 @@ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
 {
    char *query = (char *)get_pool_memory(PM_MESSAGE);
    struct s_count_ctx cnt;
+   struct s_file_del_ctx del;
+   int i;
+   JOB_DBR jr;
+   struct tm tm;
+   btime_t today, period;
+   time_t now;
 
+   memset(&jr, 0, sizeof(jr));
+   memset(&del, 0, sizeof(del));
+   cnt.count = 0;
    Mmsg(&query, "SELECT count(*) FROM JobMedia WHERE MediaId=%d", mr->MediaId);
    if (!db_sql_query(ua->db, query, count_handler, (void *)&cnt)) {
       bsendmsg(ua, "%s", db_strerror(ua->db));
@@ -504,11 +508,81 @@ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
    if (cnt.count == 0) {
       bsendmsg(ua, "There are no Jobs associated with Volume %s. It is purged.\n",
         mr->VolumeName);
+      if (!mark_media_purged(ua, mr)) {
+        goto bail_out;
+      }
+      goto bail_out;
+   }
+
+   if (cnt.count < MAX_DEL_LIST_LEN) {
+      del.max_ids = cnt.count + 1;
    } else {
-      bsendmsg(ua, "There are still %d Jobs on Volume %s. It is not purged.\n",
-        cnt.count, mr->VolumeName);
+      del.max_ids = MAX_DEL_LIST_LEN; 
    }
+
+   del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
+
+   Mmsg(&query, "SELECT JobId FROM JobMedia WHERE MediaId=%d", mr->MediaId);
+   if (!db_sql_query(ua->db, query, file_delete_handler, (void *)&del)) {
+      bsendmsg(ua, "%s", db_strerror(ua->db));
+      Dmsg0(050, "Count failed\n");
+      goto bail_out;
+   }
+
+   /* Use Volume Retention to purge Jobs and Files */
+   period = mr->VolRetention;
+   period = 30 * 3600 *24;    /* ****FIXME***** remove */
+   now = time(NULL);
+   localtime_r(&now, &tm);
+   today = (btime_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) -
+       date_encode(2000, 1, 1));
+
+   Dmsg3(050, "Today=%d period=%d period=%d\n", (uint32_t)today, (uint32_t)period,          
+      (uint32_t)(period/(3600*24)));
+
+   for (i=0; i < del.num_ids; i++) {
+      jr.JobId = del.JobId[i];
+      if (!db_get_job_record(ua->db, &jr)) {
+        continue;
+      }
+      if (jr.StartDay >= (today - period/(3600*24))) {
+        continue;
+      }
+      Dmsg1(050, "Delete JobId=%d\n", del.JobId[i]);
+      Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(ua->db, query, NULL, (void *)NULL);
+      Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(ua->db, query, NULL, (void *)NULL);
+      Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(ua->db, query, NULL, (void *)NULL);
+      Dmsg1(050, "Del sql=%s\n", query);
+      del.num_del++;
+   }
+   if (del.JobId) {
+      free(del.JobId);
+   }
+   bsendmsg(ua, _("%d Jobs on Volume %s pruned from catalog.\n"), del.num_del,
+      mr->VolumeName);
+
+   /* If purged, mark it so */
+   if (del.num_ids == del.num_del) {
+      mark_media_purged(ua, mr);
+   }
+
 bail_out:   
    free_pool_memory(query);
    return 1;
 }
+
+static int mark_media_purged(UAContext *ua, MEDIA_DBR *mr)
+{
+   if (strcmp(mr->VolStatus, "Append") == 0 || 
+       strcmp(mr->VolStatus, "Full")   == 0) {
+      strcpy(mr->VolStatus, "Purged");
+      if (!db_update_media_record(ua->db, mr)) {
+         bsendmsg(ua, "%s", db_strerror(ua->db));
+        return 0;
+      }
+   }
+   return 1;
+}
index eab8d01c63cfa90031d72469105bc4730c0d12db..834d12905814e86b94fc22ee3f846a55b0262aaf 100644 (file)
@@ -39,6 +39,7 @@ int purge_jobs_from_client(UAContext *ua, CLIENT *client);
 void purge_files_from_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr );
 void purge_jobs_from_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
 void purge_files_from_job(UAContext *ua, JOB_DBR *jr);
+static int mark_media_purged(UAContext *ua, MEDIA_DBR *mr);
 
 
 #define MAX_DEL_LIST_LEN 1000000
@@ -76,6 +77,20 @@ struct s_count_ctx {
    int count;
 };
 
+/*
+ * Called here to count entries to be deleted 
+ */
+static int count_handler(void *ctx, int num_fields, char **row)
+{
+   struct s_count_ctx *cnt = (struct s_count_ctx *)ctx;
+
+   if (row[0]) {
+      cnt->count = atoi(row[0]);
+   } else {
+      cnt->count = 0;
+   }
+   return 0;
+}
 
 /*
  * Called here to count entries to be deleted 
@@ -137,16 +152,11 @@ static int file_delete_handler(void *ctx, int num_fields, char **row)
    return 0;
 }
 
-void purge_files_from_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr ) {} /* ***FIXME*** implement */
-void purge_jobs_from_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) {} /* ***FIXME*** implement */
-
-
-
 /*
  *   Purge records from database
  *
- *     Purge Files from [Job|JobId|Client|Volume]
- *     Purge Jobs  from [Client|Volume]
+ *     Purge Files (from) [Job|JobId|Client|Volume]
+ *     Purge Jobs  (from) [Client|Volume]
  *
  *  N.B. Not all above is implemented yet.
  */
@@ -174,7 +184,7 @@ int purgecmd(UAContext *ua, char *cmd)
       NULL};
       
    bsendmsg(ua, _(
-      "This command is DANGEROUUS!\n"
+      "This command is DANGEROUS!!!\n"
       "It purges (deletes) all Files from a Job,\n"
       "JobId, Client or Volume; or it purges (deletes)\n"
       "all Jobs from a Client or Volume. Normally you\n" 
@@ -254,17 +264,13 @@ int purge_files_from_client(UAContext *ua, CLIENT *client)
    CLIENT_DBR cr;
 
    memset(&cr, 0, sizeof(cr));
+   memset(&del, 0, sizeof(del));
+
    strcpy(cr.Name, client->hdr.name);
    if (!db_create_client_record(ua->db, &cr)) {
       return 0;
    }
 
-   del.JobId = NULL;
-   del.num_ids = 0;
-   del.tot_ids = 0;
-   del.num_del = 0;
-   del.max_ids = 0;
-
    Mmsg(&query, select_jobsfiles_from_client, cr.ClientId);
 
    Dmsg1(050, "select sql=%s\n", query);
@@ -335,17 +341,13 @@ int purge_jobs_from_client(UAContext *ua, CLIENT *client)
    CLIENT_DBR cr;
 
    memset(&cr, 0, sizeof(cr));
+   memset(&del, 0, sizeof(del));
+
    strcpy(cr.Name, client->hdr.name);
    if (!db_create_client_record(ua->db, &cr)) {
       return 0;
    }
 
-   del.JobId = NULL;
-   del.num_ids = 0;
-   del.tot_ids = 0;
-   del.num_del = 0;
-   del.max_ids = 0;
-
    Mmsg(&query, select_jobs_from_client, cr.ClientId);
 
    Dmsg1(050, "select sql=%s\n", query);
@@ -369,8 +371,6 @@ int purge_jobs_from_client(UAContext *ua, CLIENT *client)
 
    del.tot_ids = 0;
 
-      
-
    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
    del.PurgedFiles = (char *)malloc(del.max_ids);
 
@@ -423,3 +423,87 @@ void purge_files_from_job(UAContext *ua, JOB_DBR *jr)
 
    free_pool_memory(query);
 }
+
+void purge_files_from_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr ) 
+{} /* ***FIXME*** implement */
+
+void purge_jobs_from_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) 
+{
+   char *query = (char *)get_pool_memory(PM_MESSAGE);
+   struct s_count_ctx cnt;
+   struct s_file_del_ctx del;
+   int i;
+   JOB_DBR jr;
+
+   memset(&jr, 0, sizeof(jr));
+   memset(&del, 0, sizeof(del));
+   cnt.count = 0;
+   Mmsg(&query, "SELECT count(*) FROM JobMedia WHERE MediaId=%d", mr->MediaId);
+   if (!db_sql_query(ua->db, query, count_handler, (void *)&cnt)) {
+      bsendmsg(ua, "%s", db_strerror(ua->db));
+      Dmsg0(050, "Count failed\n");
+      goto bail_out;
+   }
+      
+   if (cnt.count == 0) {
+      bsendmsg(ua, "There are no Jobs associated with Volume %s. It is purged.\n",
+        mr->VolumeName);
+      if (!mark_media_purged(ua, mr)) {
+        goto bail_out;
+      }
+      goto bail_out;
+   }
+
+   if (cnt.count < MAX_DEL_LIST_LEN) {
+      del.max_ids = cnt.count + 1;
+   } else {
+      del.max_ids = MAX_DEL_LIST_LEN; 
+   }
+
+   del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
+
+   Mmsg(&query, "SELECT JobId FROM JobMedia WHERE MediaId=%d", mr->MediaId);
+   if (!db_sql_query(ua->db, query, file_delete_handler, (void *)&del)) {
+      bsendmsg(ua, "%s", db_strerror(ua->db));
+      Dmsg0(050, "Count failed\n");
+      goto bail_out;
+   }
+
+   for (i=0; i < del.num_ids; i++) {
+      Dmsg1(050, "Delete JobId=%d\n", del.JobId[i]);
+      Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(ua->db, query, NULL, (void *)NULL);
+      Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(ua->db, query, NULL, (void *)NULL);
+      Mmsg(&query, "DELETE FROM JobMedia WHERE JobId=%d", del.JobId[i]);
+      db_sql_query(ua->db, query, NULL, (void *)NULL);
+      Dmsg1(050, "Del sql=%s\n", query);
+      del.num_del++;
+   }
+   if (del.JobId) {
+      free(del.JobId);
+   }
+   bsendmsg(ua, _("%d Files for Volume %s purged from catalog.\n"), del.num_del,
+      mr->VolumeName);
+
+   /* If purged, mark it so */
+   if (del.num_ids == del.num_del) {
+      mark_media_purged(ua, mr);
+   }
+
+bail_out:   
+   free_pool_memory(query);
+}
+
+static int mark_media_purged(UAContext *ua, MEDIA_DBR *mr)
+{
+   if (strcmp(mr->VolStatus, "Append") == 0 || 
+       strcmp(mr->VolStatus, "Full")   == 0) {
+      strcpy(mr->VolStatus, "Purged");
+      if (!db_update_media_record(ua->db, mr)) {
+         bsendmsg(ua, "%s", db_strerror(ua->db));
+        return 0;
+      }
+   }
+   return 1;
+}
index 9ad7b6b6e7d370da989d33f571e954478c57f07e..60d8a3739a4390f5c0d13d4e72469e80119021d2 100644 (file)
@@ -483,7 +483,8 @@ int do_prompt(UAContext *ua, char *msg, char *prompt)
       } else {
          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
       }
-      if (!get_cmd(ua, pmsg) || *ua->cmd == '.') {
+      /* Either a . or an @ will get you out of the loop */
+      if (!get_cmd(ua, pmsg) || *ua->cmd == '.' || *ua->cmd == '@') {
         item = -1;                   /* error */
         break;
       }
index 75a09d86c458fa39a84adf47a950a3fff66eb3b2..b58405a0ccc6b8f9fba617c5bdcc08cc349553e5 100644 (file)
@@ -90,7 +90,7 @@ static void *connect_thread(void *arg)
  */
 static void handle_UA_client_request(void *arg)
 {
-   int quit, stat;
+   int stat;
    static char cmd[1000];
    UAContext ua;
    BSOCK *UA_sock = (BSOCK *) arg;
@@ -99,6 +99,7 @@ static void handle_UA_client_request(void *arg)
 
    memset(&ua, 0, sizeof(ua));
    ua.automount = TRUE;
+   ua.verbose = TRUE;
    ua.jcr = new_jcr(sizeof(JCR), dird_free_jcr);
    close_msg(ua.jcr);                 /* we don't handle messages */
    ua.jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */
@@ -115,19 +116,18 @@ static void handle_UA_client_request(void *arg)
       goto getout;
    }
 
-   quit = FALSE;
-   while (!quit) {
+   while (!ua.quit) {
       stat = bnet_recv(ua.UA_sock);
       if (stat > 0) {
         strncpy(cmd, ua.UA_sock->msg, sizeof(cmd));
         cmd[sizeof(cmd)-1] = 0;       /* ensure it is terminated/trucated */
         parse_command_args(&ua);
          if (ua.argc > 0 && ua.argk[0][0] == '.') {
-           quit = !do_a_dot_command(&ua, cmd);
+           do_a_dot_command(&ua, cmd);
         } else {
-           quit = !do_a_command(&ua, cmd);
+           do_a_command(&ua, cmd);
         }
-        if (!quit) {
+        if (!ua.quit) {
            if (ua.auto_display_messages) {
                strcpy(cmd, "messages");
               qmessagescmd(&ua, cmd);
@@ -140,7 +140,7 @@ static void handle_UA_client_request(void *arg)
         }
       } else if (stat == 0) {
         if (ua.UA_sock->msglen == BNET_TERMINATE) {
-           quit = TRUE;
+           ua.quit = TRUE;
            break;
         }
         bnet_sig(ua.UA_sock, BNET_POLL);
index b9d3a7de0f1473ad8c641c0874134f8147200edb..8c3c63d9b9fec51eecdd229f8c4b573080ef1a9e 100644 (file)
@@ -73,6 +73,9 @@ int do_verify(JCR *jcr)
    CLIENT_DBR cr;
 
    memset(&cr, 0, sizeof(cr));
+   cr.AutoPrune = jcr->client->AutoPrune;
+   cr.FileRetention = jcr->client->FileRetention;
+   cr.JobRetention = jcr->client->JobRetention;
    strcpy(cr.Name, jcr->client->hdr.name);
    if (jcr->client_name) {
       free(jcr->client_name);