From: Kern Sibbald Date: Sat, 4 May 2002 15:19:08 +0000 (+0000) Subject: Retention period updates X-Git-Tag: Release-1.20~15 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=288ea8ab889d58c06cc1b95aeca0485082a63bb9;p=bacula%2Fbacula Retention period updates git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@14 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/Makefile.in b/bacula/src/Makefile.in index 00e075d1b3..ee55b709d4 100644 --- a/bacula/src/Makefile.in +++ b/bacula/src/Makefile.in @@ -1,4 +1,5 @@ # +# $Id$ # @MCOMMON@ diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 6968b0a6a4..5c50c0bfd7 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -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; diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index 6ae35962fe..2c155f9913 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -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, diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in index f811e69873..ad51ac11dd 100644 --- a/bacula/src/cats/make_sqlite_tables.in +++ b/bacula/src/cats/make_sqlite_tables.in @@ -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 ( diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index f420b21f57..e251ae94b6 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -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; diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 59335b2edc..68b931fe35 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -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); diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index 213cc4acf8..21fdbe4436 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -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) diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 129e962498..73aa0c7813 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -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"), diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index c0e27e54e6..aa1e39e804 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -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); diff --git a/bacula/src/cats/sqlite.c b/bacula/src/cats/sqlite.c index b9a43ce64d..bbe0d09f10 100644 --- a/bacula/src/cats/sqlite.c +++ b/bacula/src/cats/sqlite.c @@ -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; diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 0fac356507..3108ef206b 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -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; diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 7d6950d7cc..92c1f6e200 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -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); } diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index e59dcaf326..8689a33b08 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -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} }; diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index d8c899cc6e..8f1753440e 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -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; diff --git a/bacula/src/dird/newvol.c b/bacula/src/dird/newvol.c index 1f7dda1714..e3982203d9 100644 --- a/bacula/src/dird/newvol.c +++ b/bacula/src/dird/newvol.c @@ -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); diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 35accb51c6..51581b34a6 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -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); } diff --git a/bacula/src/dird/ua.h b/bacula/src/dird/ua.h index 28e9799491..3fa6f25a3b 100644 --- a/bacula/src/dird/ua.h +++ b/bacula/src/dird/ua.h @@ -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); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index f2b137a375..ff24bb6b14 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -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) diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index bd88cceb2b..9a24d052b1 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -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 ( ;; ) { diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index a7a97df109..ff572affa4 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -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); + } + +} diff --git a/bacula/src/dird/ua_prune.c b/bacula/src/dird/ua_prune.c index 389ac441df..c8c697cb31 100644 --- a/bacula/src/dird/ua_prune.c +++ b/bacula/src/dird/ua_prune.c @@ -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; +} diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c index eab8d01c63..834d129058 100644 --- a/bacula/src/dird/ua_purge.c +++ b/bacula/src/dird/ua_purge.c @@ -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; +} diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index 9ad7b6b6e7..60d8a3739a 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -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; } diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c index 75a09d86c4..b58405a0cc 100644 --- a/bacula/src/dird/ua_server.c +++ b/bacula/src/dird/ua_server.c @@ -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); diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index b9d3a7de0f..8c3c63d9b9 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -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);