From: Kern Sibbald Date: Mon, 29 Apr 2002 15:54:42 +0000 (+0000) Subject: add Prune command -- not yet tested X-Git-Tag: Release-1.20~20 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=9a0ee8018bcc482e9996ddc710519a07baaa13f0;p=bacula%2Fbacula add Prune command -- not yet tested git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@9 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/cats/bdb_list.c b/bacula/src/cats/bdb_list.c index 6cf9512115..36d22e73b9 100644 --- a/bacula/src/cats/bdb_list.c +++ b/bacula/src/cats/bdb_list.c @@ -112,7 +112,7 @@ void db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, len = sizeof(mr); while (fread(&mr, len, 1, mdb->mediafd) > 0) { Mmsg(&mdb->cmd, " %-10s %17s %-15s %s\n", - mr.VolStatus, edit_uint_with_commas(mr.VolBytes, ewc), + mr.VolStatus, edit_uint64_with_commas(mr.VolBytes, ewc), mr.MediaType, mr.VolumeName); sendit(ctx, mdb->cmd); } @@ -212,8 +212,8 @@ void db_list_job_records(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void * strftime(dt, sizeof(dt), "%m-%d %H:%M", &tm); Mmsg(&mdb->cmd, " %7d %-10s %c %c %14s %10s %c %s\n", ojr.JobId, dt, (char)ojr.Type, (char)ojr.Level, - edit_uint_with_commas(ojr.JobBytes, ewc1), - edit_uint_with_commas(ojr.JobFiles, ewc2), + edit_uint64_with_commas(ojr.JobBytes, ewc1), + edit_uint64_with_commas(ojr.JobFiles, ewc2), (char)ojr.JobStatus, ojr.Name); sendit(ctx, mdb->cmd); } @@ -253,9 +253,9 @@ void db_list_job_totals(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *c total_jobs++; } Mmsg(&mdb->cmd, " %7s %10s %15s\n", - edit_uint_with_commas(total_jobs, ewc1), - edit_uint_with_commas(total_files, ewc2), - edit_uint_with_commas(total_bytes, ewc3)); + edit_uint64_with_commas(total_jobs, ewc1), + edit_uint64_with_commas(total_files, ewc2), + edit_uint64_with_commas(total_bytes, ewc3)); sendit(ctx, mdb->cmd); sendit(ctx, "=======================================\n"); V(mdb->mutex); diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index 0cf996e15f..6ae35962fe 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -49,7 +49,7 @@ CREATE TABLE Job ( SchedTime DATETIME NOT NULL, StartTime DATETIME NOT NULL, EndTime DATETIME NOT NULL, - StartDay INTEGER UNSIGNED NOT NULL, + StartDay BIGINT UNSIGNED NOT NULL, VolSessionId INTEGER UNSIGNED NOT NULL, VolSessionTime INTEGER UNSIGNED NOT NULL, JobFiles INTEGER UNSIGNED NOT NULL, diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index c8436fa2d8..213cc4acf8 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -79,7 +79,9 @@ InsertDB(char *file, int line, B_DB *mdb, char *cmd) mdb->num_rows = 1; } if (mdb->num_rows != 1) { - m_msg(file, line, &mdb->errmsg, _("Insertion problem: affect_rows=%" lld "\n"), mdb->num_rows); + char ed1[30]; + m_msg(file, line, &mdb->errmsg, _("Insertion problem: affect_rows=%s\n"), + edit_uint64(mdb->num_rows, ed1)); e_msg(file, line, M_FATAL, 0, mdb->errmsg); /* ***FIXME*** remove me */ return 0; } @@ -102,7 +104,9 @@ UpdateDB(char *file, int line, B_DB *mdb, char *cmd) } mdb->num_rows = sql_affected_rows(mdb); if (mdb->num_rows != 1) { - m_msg(file, line, &mdb->errmsg, _("Update problem: affect_rows=%" lld "\n"), mdb->num_rows); + char ed1[30]; + m_msg(file, line, &mdb->errmsg, _("Update problem: affect_rows=%s\n"), + edit_uint64(mdb->num_rows, ed1)); e_msg(file, line, M_ERROR, 0, mdb->errmsg); e_msg(file, line, M_ERROR, 0, "%s\n", cmd); return 0; diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 82b6daebcc..129e962498 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -68,13 +68,14 @@ db_create_job_record(B_DB *mdb, JOB_DBR *jr) struct tm tm; int stat; char *JobId; - int32_t StartDay; + btime_t StartDay; + char ed1[30]; stime = jr->SchedTime; localtime_r(&stime, &tm); strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); - StartDay = (int32_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) - + StartDay = (btime_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) - date_encode(2000, 1, 1)); P(mdb->mutex); @@ -87,9 +88,9 @@ db_create_job_record(B_DB *mdb, JOB_DBR *jr) /* Must create it */ Mmsg(&mdb->cmd, "INSERT INTO Job (JobId, Job, Name, Type, Level, SchedTime, StartDay) VALUES \ -(%s, \"%s\", \"%s\", \"%c\", \"%c\", \"%s\", %d)", +(%s, \"%s\", \"%s\", \"%c\", \"%c\", \"%s\", %s)", JobId, jr->Job, jr->Name, (char)(jr->Type), (char)(jr->Level), dt, - StartDay); + edit_uint64(StartDay, ed1)); if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"), @@ -212,6 +213,7 @@ int db_create_media_record(B_DB *mdb, MEDIA_DBR *mr) { int stat; + char ed1[30], ed2[30]; P(mdb->mutex); Mmsg(&mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName=\"%s\"", @@ -232,10 +234,11 @@ 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, %" lld ", %" lld ", \"%s\", \"%s\")", +VolStatus, Recycle) VALUES (\"%s\", \"%s\", %d, %s, %s, \"%s\", \"%s\")", mr->VolumeName, mr->MediaType, mr->PoolId, - mr->VolMaxBytes, mr->VolCapacityBytes, + edit_uint64(mr->VolMaxBytes,ed1), + edit_uint64(mr->VolCapacityBytes, ed2), mr->VolStatus, mr->Recycle); if (!INSERT_DB(mdb, mdb->cmd)) { @@ -550,8 +553,9 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { - Mmsg2(&mdb->errmsg, _("More than one Path!: %" lld " for Path=%s\n"), - mdb->num_rows, path); + char ed1[30]; + Mmsg2(&mdb->errmsg, _("More than one Path!: %s for Path=%s\n"), + edit_uint64(mdb->num_rows, ed1), path); Emsg1(M_ERROR, 0, "%s", mdb->errmsg); Emsg1(M_ERROR, 0, "%s\n", mdb->cmd); } diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index a50a179259..c0e27e54e6 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -232,11 +232,12 @@ static int db_get_path_record(B_DB *mdb, char *path) Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path=\"%s\"", path); if (QUERY_DB(mdb, mdb->cmd)) { - + char ed1[30]; mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { - Mmsg1(&mdb->errmsg, _("More than one Path!: %" lld "\n"), mdb->num_rows); + Mmsg1(&mdb->errmsg, _("More than one Path!: %s\n"), + edit_uint64(mdb->num_rows, ed1)); Emsg0(M_FATAL, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { @@ -433,7 +434,9 @@ PoolType, LabelFormat FROM Pool WHERE Pool.Name=\"%s\"", pdbr->Name); if (QUERY_DB(mdb, mdb->cmd)) { mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { - Mmsg1(&mdb->errmsg, _("More than one Pool!: %" lld "\n"), mdb->num_rows); + char ed1[30]; + Mmsg1(&mdb->errmsg, _("More than one Pool!: %s\n"), + edit_uint64(mdb->num_rows, ed1)); Emsg0(M_ERROR, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { @@ -550,7 +553,9 @@ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); if (QUERY_DB(mdb, mdb->cmd)) { mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { - Mmsg1(&mdb->errmsg, _("More than one Volume!: %" lld "\n"), mdb->num_rows); + char ed1[30]; + Mmsg1(&mdb->errmsg, _("More than one Volume!: %s\n"), + edit_uint64(mdb->num_rows, ed1)); Emsg0(M_ERROR, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { @@ -574,6 +579,8 @@ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); mr->PoolId = atoi(row[13]); stat = mr->MediaId; } + } else { + Mmsg0(&mdb->errmsg, _("Media record not found.\n")); } sql_free_result(mdb); } diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index 4a2183a63c..1b6d2dbfce 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -100,19 +100,20 @@ db_update_job_start_record(B_DB *mdb, JOB_DBR *jr) char dt[MAX_TIME_LENGTH]; time_t stime; struct tm tm; - int32_t StartDay; + btime_t StartDay; int stat; + char ed1[30]; stime = jr->StartTime; localtime_r(&stime, &tm); strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); - StartDay = (int32_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) - + StartDay = (btime_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) - date_encode(2000, 1, 1)); P(mdb->mutex); Mmsg(&mdb->cmd, "UPDATE Job SET Level='%c', StartTime=\"%s\", \ -ClientId=%d, StartDay=%d WHERE JobId=%d", - (char)(jr->Level), dt, jr->ClientId, StartDay, jr->JobId); +ClientId=%d, StartDay=%s WHERE JobId=%d", + (char)(jr->Level), dt, jr->ClientId, edit_uint64(StartDay, ed1), jr->JobId); stat = UPDATE_DB(mdb, mdb->cmd); V(mdb->mutex); return stat; @@ -133,19 +134,23 @@ db_update_job_end_record(B_DB *mdb, JOB_DBR *jr) time_t ttime; struct tm tm; int stat; + char ed1[30], ed2[30]; + btime_t StartDay; ttime = jr->EndTime; localtime_r(&ttime, &tm); strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); + StartDay = (btime_t)(date_encode(tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday) - + date_encode(2000, 1, 1)); P(mdb->mutex); Mmsg(&mdb->cmd, "UPDATE Job SET JobStatus='%c', EndTime='%s', \ -ClientId=%d, JobBytes=%" lld ", JobFiles=%d, JobErrors=%d, VolSessionId=%d, \ -VolSessionTime=%d, PoolId=%d, FileSetId=%d WHERE JobId=%d", - (char)(jr->JobStatus), dt, jr->ClientId, jr->JobBytes, jr->JobFiles, - jr->JobErrors, jr->VolSessionId, jr->VolSessionTime, - jr->PoolId, jr->FileSetId, jr->JobId); +ClientId=%d, JobBytes=%s, JobFiles=%d, JobErrors=%d, VolSessionId=%d, \ +VolSessionTime=%d, PoolId=%d, FileSetId=%d, StartDay=%s WHERE JobId=%d", + (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1), + jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime, + jr->PoolId, jr->FileSetId, edit_uint64(StartDay, ed2), jr->JobId); stat = UPDATE_DB(mdb, mdb->cmd); V(mdb->mutex); @@ -183,6 +188,7 @@ db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) time_t ttime; struct tm tm; int stat; + char ed1[30], ed2[30]; ttime = mr->LastWritten; localtime_r(&ttime, &tm); @@ -199,12 +205,13 @@ db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) } Mmsg(&mdb->cmd, "UPDATE Media SET VolJobs=%d,\ - VolFiles=%d, VolBlocks=%d, VolBytes=%" lld ", VolMounts=%d, VolErrors=%d,\ - VolWrites=%d, VolMaxBytes=%" lld ", LastWritten=\"%s\", VolStatus=\"%s\" \ + VolFiles=%d, VolBlocks=%d, VolBytes=%s, VolMounts=%d, VolErrors=%d,\ + VolWrites=%d, VolMaxBytes=%s, LastWritten=\"%s\", VolStatus=\"%s\" \ WHERE VolumeName=\"%s\"", - mr->VolJobs, mr->VolFiles, mr->VolBlocks, mr->VolBytes, mr->VolMounts, - mr->VolErrors, mr->VolWrites, mr->VolMaxBytes, dt, mr->VolStatus, - mr->VolumeName); + mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1), + mr->VolMounts, mr->VolErrors, mr->VolWrites, + edit_uint64(mr->VolMaxBytes, ed2), dt, + mr->VolStatus, mr->VolumeName); stat = UPDATE_DB(mdb, mdb->cmd); V(mdb->mutex); diff --git a/bacula/src/console.glade b/bacula/src/console.glade index e0ba071194..5a7fa1c3ec 100644 --- a/bacula/src/console.glade +++ b/bacula/src/console.glade @@ -15,17 +15,6 @@ False - - GnomeAbout - about - False - True - Copyright (c) 1999 - 2002, Kern Sibbald and John Walker - Kern Sibbald and John Walker - - It comes by night and sucks the essence from your computers. - - GnomeMessageBox messagebox1 @@ -1268,4 +1257,195 @@ + + GtkDialog + about1 + 382 + 242 + About Bacula Console + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + True + False + False + False + + + GtkVBox + Dialog:vbox + dialog-vbox5 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area5 + 10 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkHBox + hbox20 + False + 0 + + 0 + True + True + + + + GtkLabel + label44 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + False + + + + + GtkButton + about_button + 1 + 80 + True + True + + clicked + on_about_button_clicked + Sun, 28 Apr 2002 15:55:15 GMT + + GNOME_STOCK_BUTTON_OK + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + + + GtkVBox + vbox8 + False + 0 + + 0 + True + True + + + + GtkVBox + vbox9 + False + 0 + + 0 + True + True + + + + GtkLabel + about_head + 102 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHSeparator + hseparator1 + + 0 + False + False + + + + + GtkLabel + copyright + + GTK_JUSTIFY_LEFT + False + 0.1 + 0.5 + 0 + 0 + + 0 + True + False + + + + + GtkLabel + authors + + GTK_JUSTIFY_LEFT + False + 0.0400001 + 0.5 + 0 + 0 + + 0 + True + False + + + + + GtkLabel + theme + + GTK_JUSTIFY_LEFT + False + 0.15 + 0.5 + 0 + 0 + + 0 + True + False + + + + + + + diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in index fa96686e51..a7aeaf24b3 100644 --- a/bacula/src/dird/Makefile.in +++ b/bacula/src/dird/Makefile.in @@ -20,22 +20,28 @@ first_rule: all dummy: # -SVRSRCS = dird.c authenticate.c backup.c catreq.c dird_conf.c \ +SVRSRCS = dird.c authenticate.c backup.c \ + catreq.c dird_conf.c \ fd_cmds.c getmsg.c job.c \ - mountreq.c msgchan.c newvol.c run_conf.c restore.c \ + mountreq.c msgchan.c newvol.c \ + run_conf.c restore.c \ scheduler.c ua_cmds.c \ ua_dotcmds.c \ ua_db_query.c ua_retention.c \ - ua_input.c ua_output.c ua_prune.c ua_run.c \ + ua_input.c ua_output.c ua_prune.c \ + ua_purge.c ua_run.c \ ua_select.c ua_server.c \ ua_status.c verify.c -SVROBJS = dird.o authenticate.o backup.o catreq.o dird_conf.o \ +SVROBJS = dird.o authenticate.o backup.o \ + catreq.o dird_conf.o \ fd_cmds.o getmsg.o job.o \ - mountreq.o msgchan.o newvol.o run_conf.o restore.o \ + mountreq.o msgchan.o newvol.o \ + run_conf.o restore.o \ scheduler.o ua_cmds.o \ ua_dotcmds.o \ ua_db_query.o ua_retention.o \ - ua_input.o ua_output.o ua_prune.o ua_run.o \ + ua_input.o ua_output.o ua_prune.o \ + ua_purge.o ua_run.o \ ua_select.o ua_server.o \ ua_status.o verify.o diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 3d5c4c239c..7d6950d7cc 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -432,12 +432,12 @@ Termination: %s\n"), jcr->client->hdr.name, sdt, edt, - edit_uint_with_commas(jcr->jr.JobBytes, ec1), - edit_uint_with_commas(jcr->jr.JobFiles, ec2), + edit_uint64_with_commas(jcr->jr.JobBytes, ec1), + edit_uint64_with_commas(jcr->jr.JobFiles, ec2), jcr->VolumeName, jcr->VolSessionId, jcr->VolSessionTime, - edit_uint_with_commas(mr.VolBytes, ec3), + edit_uint64_with_commas(mr.VolBytes, ec3), term_msg); Dmsg0(100, "Leave backup_cleanup()\n"); diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index fbf4e4e828..e59dcaf326 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -358,10 +358,11 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... } switch (type) { case R_DIRECTOR: - sendit(sock, "Director: name=%s maxjobs=%d FDtimeout=%" lld " SDtimeout=%" lld "\n", + char ed1[30], ed2[30]; + sendit(sock, "Director: name=%s maxjobs=%d FDtimeout=%s SDtimeout=%s\n", reshdr->name, res->res_dir.MaxConcurrentJobs, - res->res_dir.FDConnectTimeout, - res->res_dir.SDConnectTimeout); + edit_uint64(res->res_dir.FDConnectTimeout, ed1), + edit_uint64(res->res_dir.SDConnectTimeout, ed2)); if (res->res_dir.query_file) { sendit(sock, " query_file=%s\n", res->res_dir.query_file); } diff --git a/bacula/src/dird/ua.h b/bacula/src/dird/ua.h index d9f41204d8..28e9799491 100644 --- a/bacula/src/dird/ua.h +++ b/bacula/src/dird/ua.h @@ -31,17 +31,17 @@ 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 */ } UAContext; /* ua_cmds.c */ @@ -68,16 +68,18 @@ JOB *select_job_resource(UAContext *ua); int select_pool_dbr(UAContext *ua, POOL_DBR *pr); CLIENT *select_client_resource(UAContext *ua); FILESET *select_fs_resource(UAContext *ua); +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); POOL *get_pool_resource(UAContext *ua); CLIENT *get_client_resource(UAContext *ua); +int get_job_dbr(UAContext *ua, JOB_DBR *jr); int find_arg_keyword(UAContext *ua, char **list); int do_keyword_prompt(UAContext *ua, char *msg, char **list); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 63c43b7ec3..f2b137a375 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -51,6 +51,7 @@ extern int querycmd(UAContext *ua, char *cmd); extern int runcmd(UAContext *ua, char *cmd); extern int retentioncmd(UAContext *ua, char *cmd); extern int prunecmd(UAContext *ua, char *cmd); +extern int purgecmd(UAContext *ua, char *cmd); /* Forward referenced functions */ static int addcmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd); @@ -82,6 +83,7 @@ static struct cmdstruct commands[] = { { N_("messages"), messagescmd, _("messages")}, { N_("mount"), mountcmd, _("mount ")}, { N_("prune"), prunecmd, _("prune expired records from catalog")}, + { N_("purge"), purgecmd, _("purge records from catalog")}, { N_("run"), runcmd, _("run ")}, { N_("setdebug"), setdebugcmd, _("sets debug level")}, { N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")}, @@ -926,37 +928,13 @@ static int delete_media(UAContext *ua) { POOL_DBR pr; MEDIA_DBR mr; - int found = FALSE; - int i; - memset(&pr, 0, sizeof(pr)); - memset(&mr, 0, sizeof(mr)); - - /* Get the pool, possibly from pool= */ - if (!get_pool_dbr(ua, &pr)) { + if (!select_pool_and_media_dbr(ua, &pr, &mr)) { return 1; } - mr.PoolId = pr.PoolId; - - /* See if a volume name is specified as an argument */ - for (i=1; iargc; i++) { - if (strcasecmp(ua->argk[i], _("volume")) == 0 && ua->argv[i]) { - found = TRUE; - break; - } - } - if (found) { - strcpy(mr.VolumeName, ua->argv[i]); - } else { - db_list_media_records(ua->db, &mr, prtit, ua); - if (!get_cmd(ua, _("Enter the Volume name to delete: "))) { - return 1; - } - } - 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")); + "and all Jobs saved on that volume from the Catalog\n"), + mr.VolumeName); if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) { return 1; diff --git a/bacula/src/dird/ua_prune.c b/bacula/src/dird/ua_prune.c new file mode 100644 index 0000000000..389ac441df --- /dev/null +++ b/bacula/src/dird/ua_prune.c @@ -0,0 +1,514 @@ +/* + * + * Bacula Director -- User Agent Database prune Command + * Applies retention periods + * + * Kern Sibbald, February MMII + */ + +/* + Copyright (C) 2002 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "dird.h" +#include "ua.h" + +/* Forward referenced functions */ +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); + + +#define MAX_DEL_LIST_LEN 1000000 + +/* + * Select JobIds for File deletion. + */ +static char *select_job = + "SELECT JobId from Job " + "WHERE StartDay < %s " + "AND ClientId=%d " + "AND PurgedFiles=0"; + +/* + * List of SQL commands terminated by NULL for deleting + * temporary tables and indicies + */ +static char *drop_deltabs[] = { + "DROP TABLE DelCandidates", + "DROP INDEX DelInx1", + NULL}; + +/* + * List of SQL commands to create temp table and indicies + */ +static char *create_deltabs[] = { + "CREATE TABLE DelCandidates (" + "JobId INTEGER UNSIGNED NOT NULL, " + "PurgedFiles TINYINT, " + "FileSetId INTEGER UNSIGNED)", + "CREATE INDEX DelInx1 ON DelCandidates (JobId)", + NULL}; + + +/* + * Fill candidates table with all Files subject to being deleted + */ +static char *insert_delcand = + "INSERT INTO DelCandidates " + "SELECT JobId, PurgedFiles, FileSetId FROM Job " + "WHERE StartDay < %s " + "AND ClientId=%d"; + +/* + * Select files from the DelCandidates table that have a + * more recent backup -- i.e. are not the only backup. + * This is the list of files to delete. + */ +static char *select_del = + "SELECT DelCandidates.JobId " + "FROM Job,DelCandidates " + "WHERE Job.StartDay >= %s " + "AND Job.ClientId=%d " + "AND Job.Level='F' " + "AND Job.JobStatus='T' " + "AND Job.FileSetId=DelCandidates.FileSetId"; + +/* In memory list of JobIds */ +struct s_file_del_ctx { + JobId_t *JobId; + int num_ids; /* ids stored */ + int max_ids; /* size of array */ + int num_del; /* number deleted */ + int tot_ids; /* total to process */ +}; + +struct s_job_del_ctx { + JobId_t *JobId; /* array of JobIds */ + char *PurgedFiles; /* Array of PurgedFile flags */ + int num_ids; /* ids stored */ + int max_ids; /* size of array */ + int num_del; /* number deleted */ + int tot_ids; /* total to process */ +}; + +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 + */ +static int file_count_handler(void *ctx, int num_fields, char **row) +{ + struct s_file_del_ctx *del = (struct s_file_del_ctx *)ctx; + del->tot_ids++; + return 0; +} + + +/* + * Called here to make in memory list of JobIds to be + * deleted and the associated PurgedFiles flag. + * 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 job_delete_handler(void *ctx, int num_fields, char **row) +{ + struct s_job_del_ctx *del = (struct s_job_del_ctx *)ctx; + + 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 = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * del->max_ids); + del->PurgedFiles = (char *)brealloc(del->PurgedFiles, del->max_ids); + } + del->JobId[del->num_ids] = (JobId_t)strtod(row[0], NULL); + del->PurgedFiles[del->num_ids++] = (char)atoi(row[0]); + return 0; +} + +static int file_delete_handler(void *ctx, int num_fields, char **row) +{ + struct s_file_del_ctx *del = (struct s_file_del_ctx *)ctx; + + 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 = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * + del->max_ids); + } + del->JobId[del->num_ids++] = (JobId_t)strtod(row[0], NULL); + return 0; +} + +/* + * Prune records from database + */ +int prunecmd(UAContext *ua, char *cmd) +{ + CLIENT *client; + POOL_DBR pr; + MEDIA_DBR mr; + + static char *keywords[] = { + N_("files"), + N_("jobs"), + N_("volume"), + NULL}; + if (!open_db(ua)) { + return 1; + } + switch (find_arg_keyword(ua, keywords)) { + case 0: + client = select_client_resource(ua); + prune_files(ua, client); + return 1; + case 1: + client = select_client_resource(ua); + prune_jobs(ua, client); + return 1; + case 2: + if (!select_pool_and_media_dbr(ua, &pr, &mr)) { + return 1; + } + prune_volume(ua, &pr, &mr); + return 1; + default: + break; + } + switch (do_keyword_prompt(ua, _("Choose item to prune"), keywords)) { + case 0: + client = select_client_resource(ua); + if (!client) { + return 1; + } + prune_files(ua, client); + break; + case 1: + client = select_client_resource(ua); + if (!client) { + return 1; + } + prune_jobs(ua, client); + break; + case 2: + if (!select_pool_and_media_dbr(ua, &pr, &mr)) { + return 1; + } + prune_volume(ua, &pr, &mr); + return 1; + } + return 1; +} + +/* + * Prune File records from the database. For any Job which + * is older than the retention period, we unconditionally delete + * all File records for that Job. This is simple enough that no + * temporary tables are needed. We simply make an in memory list of + * the JobIds meeting the prune conditions, then delete all File records + * pointing to each of those JobIds. + */ +int prune_files(UAContext *ua, CLIENT *client) +{ + struct s_file_del_ctx del; + char *query = (char *)get_pool_memory(PM_MESSAGE); + int i; + struct tm tm; + uint64_t today, period; + time_t now; + CLIENT_DBR cr; + char ed1[50]; + + memset(&cr, 0, sizeof(cr)); + strcpy(cr.Name, client->hdr.name); + if (!db_create_client_record(ua->db, &cr)) { + return 0; + } + + period = client->FileRetention; + now = time(NULL); + localtime_r(&now, &tm); + 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))); + + Mmsg(&query, select_job, + edit_uint64(today - period/(3600*24), ed1), cr.ClientId); + + Dmsg1(050, "select sql=%s\n", query); + + if (!db_sql_query(ua->db, query, file_count_handler, (void *)&del)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + Dmsg0(050, "Count failed\n"); + goto bail_out; + } + + if (del.tot_ids == 0) { + bsendmsg(ua, _("No Files found for client %s to prune from %s catalog.\n"), + client->hdr.name, client->catalog->hdr.name); + goto bail_out; + } + + if (del.tot_ids < MAX_DEL_LIST_LEN) { + del.max_ids = del.tot_ids + 1; + } else { + del.max_ids = MAX_DEL_LIST_LEN; + } + del.tot_ids = 0; + + del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); + + db_sql_query(ua->db, query, file_delete_handler, (void *)&del); + + 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); + /* + * Now mark Job as having files purged. This is necessary to + * avoid having too many Jobs to process in future prunings. If + * we don't do this, the number of JobId's in our in memory list + * will grow very large. + */ + Mmsg(&query, "UPDATE Job Set PurgedFiles=1 WHERE JobId=%d", del.JobId[i]); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Del sql=%s\n", query); + } + bsendmsg(ua, _("%d Files for client %s pruned from %s catalog.\n"), del.num_ids, + client->hdr.name, client->catalog->hdr.name); + +bail_out: + if (del.JobId) { + free(del.JobId); + } + free_pool_memory(query); + return 1; +} + + +static void drop_temp_tables(UAContext *ua) +{ + int i; + for (i=0; drop_deltabs[i]; i++) { + db_sql_query(ua->db, drop_deltabs[i], NULL, (void *)NULL); + } +} + +static int create_temp_tables(UAContext *ua) +{ + int i; + /* Create temp tables and indicies */ + for (i=0; create_deltabs[i]; i++) { + if (!db_sql_query(ua->db, create_deltabs[i], NULL, (void *)NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + Dmsg0(050, "create DelTables table failed\n"); + return 0; + } + } + return 1; +} + + + +/* + * Purging Jobs is a bit more complicated than purging Files + * because we delete Job records only if there is a more current + * backup of the FileSet. Otherwise, we keep the Job record. + * In other words, we never delete the only Job record that + * contains a current backup of a FileSet. This prevents the + * Volume from being recycled and destroying a current backup. + */ +int prune_jobs(UAContext *ua, CLIENT *client) +{ + struct s_job_del_ctx del; + struct s_count_ctx cnt; + char *query = (char *)get_pool_memory(PM_MESSAGE); + int i; + struct tm tm; + uint64_t today, period; + time_t now; + CLIENT_DBR cr; + char ed1[50]; + + memset(&cr, 0, sizeof(cr)); + strcpy(cr.Name, client->hdr.name); + if (!db_create_client_record(ua->db, &cr)) { + return 0; + } + + 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) - + 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))); + + /* Drop any previous temporary tables still there */ + drop_temp_tables(ua); + + /* Create temp tables and indicies */ + if (!create_temp_tables(ua)) { + goto bail_out; + } + + /* + * Select all files that are older than the JobRetention period + * and stuff them into the "DeletionCandidates" table. + */ + edit_uint64(today - period/(3600*24), ed1); + Mmsg(&query, insert_delcand, ed1, cr.ClientId); + + if (!db_sql_query(ua->db, query, NULL, (void *)NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + Dmsg0(050, "insert delcand failed\n"); + goto bail_out; + } + + strcpy(query, "SELECT count(*) FROM DelCandidates"); + + Dmsg1(100, "select sql=%s\n", query); + + 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, _("No Jobs for client %s found to prune from %s catalog.\n"), + client->hdr.name, client->catalog->hdr.name); + 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); + del.PurgedFiles = (char *)malloc(del.max_ids); + + Mmsg(&query, select_del, ed1, cr.ClientId); + db_sql_query(ua->db, query, job_delete_handler, (void *)&del); + + /* + * OK, now we have the list of JobId's to be pruned, first check + * if the Files have been purged, if not, purge (delete) them. + * Then delete the Job entry, and finally and JobMedia records. + */ + for (i=0; i < del.num_ids; i++) { + Dmsg1(050, "Delete JobId=%d\n", del.JobId[i]); + if (!del.PurgedFiles[i]) { + Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Del sql=%s\n", query); + } + + Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Del sql=%s\n", query); + + 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); + } + bsendmsg(ua, _("%d Jobs for client %s pruned from %s catalog.\n"), del.num_ids, + client->hdr.name, client->catalog->hdr.name); + +bail_out: + drop_temp_tables(ua); + if (del.JobId) { + free(del.JobId); + } + if (del.PurgedFiles) { + free(del.PurgedFiles); + } + free_pool_memory(query); + return 1; +} + +/* + * Prune volumes + */ +int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) +{ + char *query = (char *)get_pool_memory(PM_MESSAGE); + struct s_count_ctx cnt; + + 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); + } else { + bsendmsg(ua, "There are still %d Jobs on Volume %s. It is not purged.\n", + cnt.count, mr->VolumeName); + } +bail_out: + free_pool_memory(query); + return 1; +} diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c new file mode 100644 index 0000000000..eab8d01c63 --- /dev/null +++ b/bacula/src/dird/ua_purge.c @@ -0,0 +1,425 @@ +/* + * + * Bacula Director -- User Agent Database Purge Command + * + * Purges Files from specific JobIds + * or + * Purges Jobs from Volumes + * + * Kern Sibbald, February MMII + */ + +/* + Copyright (C) 2002 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "dird.h" +#include "ua.h" + +/* Forward referenced functions */ +int purge_files_from_client(UAContext *ua, CLIENT *client); +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); + + +#define MAX_DEL_LIST_LEN 1000000 + + +static char *select_jobsfiles_from_client = + "SELECT JobId FROM Job " + "WHERE ClientId=%d " + "AND PurgedFiles=0"; + +static char *select_jobs_from_client = + "SELECT JobId, PurgedFiles FROM Job " + "WHERE ClientId=%d"; + + +/* In memory list of JobIds */ +struct s_file_del_ctx { + JobId_t *JobId; + int num_ids; /* ids stored */ + int max_ids; /* size of array */ + int num_del; /* number deleted */ + int tot_ids; /* total to process */ +}; + +struct s_job_del_ctx { + JobId_t *JobId; /* array of JobIds */ + char *PurgedFiles; /* Array of PurgedFile flags */ + int num_ids; /* ids stored */ + int max_ids; /* size of array */ + int num_del; /* number deleted */ + int tot_ids; /* total to process */ +}; + +struct s_count_ctx { + int count; +}; + + +/* + * Called here to count entries to be deleted + */ +static int file_count_handler(void *ctx, int num_fields, char **row) +{ + struct s_file_del_ctx *del = (struct s_file_del_ctx *)ctx; + del->tot_ids++; + return 0; +} + + +static int job_count_handler(void *ctx, int num_fields, char **row) +{ + struct s_job_del_ctx *del = (struct s_job_del_ctx *)ctx; + del->tot_ids++; + return 0; +} + + +/* + * Called here to make in memory list of JobIds to be + * deleted and the associated PurgedFiles flag. + * 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 job_delete_handler(void *ctx, int num_fields, char **row) +{ + struct s_job_del_ctx *del = (struct s_job_del_ctx *)ctx; + + 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 = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * del->max_ids); + del->PurgedFiles = (char *)brealloc(del->PurgedFiles, del->max_ids); + } + del->JobId[del->num_ids] = (JobId_t)strtod(row[0], NULL); + del->PurgedFiles[del->num_ids++] = (char)atoi(row[0]); + return 0; +} + +static int file_delete_handler(void *ctx, int num_fields, char **row) +{ + struct s_file_del_ctx *del = (struct s_file_del_ctx *)ctx; + + 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 = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * + del->max_ids); + } + del->JobId[del->num_ids++] = (JobId_t)strtod(row[0], NULL); + 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] + * + * N.B. Not all above is implemented yet. + */ +int purgecmd(UAContext *ua, char *cmd) +{ + CLIENT *client; + MEDIA_DBR mr; + POOL_DBR pr; + JOB_DBR jr; + static char *keywords[] = { + N_("files"), + N_("jobs"), + NULL}; + + static char *files_keywords[] = { + N_("Job"), + N_("JobId"), + N_("Client"), + N_("Volume"), + NULL}; + + static char *jobs_keywords[] = { + N_("Client"), + N_("Volume"), + NULL}; + + bsendmsg(ua, _( + "This command is DANGEROUUS!\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" + "should use the PRUNE command instead.\n")); + + if (!open_db(ua)) { + return 1; + } + switch (find_arg_keyword(ua, keywords)) { + /* Files */ + case 0: + switch(find_arg_keyword(ua, files_keywords)) { + case 0: /* Job */ + case 1: + if (get_job_dbr(ua, &jr)) { + purge_files_from_job(ua, &jr); + } + return 1; + case 2: /* client */ + client = select_client_resource(ua); + purge_files_from_client(ua, client); + return 1; + case 3: + if (select_pool_and_media_dbr(ua, &pr, &mr)) { + purge_files_from_volume(ua, &pr, &mr); + } + return 1; + } + /* Jobs */ + case 1: + switch(find_arg_keyword(ua, jobs_keywords)) { + case 0: /* client */ + client = select_client_resource(ua); + purge_jobs_from_client(ua, client); + return 1; + case 1: + if (select_pool_and_media_dbr(ua, &pr, &mr)) { + purge_jobs_from_volume(ua, &pr, &mr); + } + return 1; + } + default: + break; + } + switch (do_keyword_prompt(ua, _("Choose item to purge"), keywords)) { + case 0: + client = select_client_resource(ua); + if (!client) { + return 1; + } + purge_files_from_client(ua, client); + break; + case 1: + client = select_client_resource(ua); + if (!client) { + return 1; + } + purge_jobs_from_client(ua, client); + break; + } + return 1; +} + +/* + * Prune File records from the database. For any Job which + * is older than the retention period, we unconditionally delete + * all File records for that Job. This is simple enough that no + * temporary tables are needed. We simply make an in memory list of + * the JobIds meeting the prune conditions, then delete all File records + * pointing to each of those JobIds. + */ +int purge_files_from_client(UAContext *ua, CLIENT *client) +{ + struct s_file_del_ctx del; + char *query = (char *)get_pool_memory(PM_MESSAGE); + int i; + CLIENT_DBR cr; + + memset(&cr, 0, sizeof(cr)); + 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); + + if (!db_sql_query(ua->db, query, file_count_handler, (void *)&del)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + Dmsg0(050, "Count failed\n"); + goto bail_out; + } + + if (del.tot_ids == 0) { + bsendmsg(ua, _("No Files found for client %s to purge from %s catalog.\n"), + client->hdr.name, client->catalog->hdr.name); + goto bail_out; + } + + if (del.tot_ids < MAX_DEL_LIST_LEN) { + del.max_ids = del.tot_ids + 1; + } else { + del.max_ids = MAX_DEL_LIST_LEN; + } + del.tot_ids = 0; + + del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); + + db_sql_query(ua->db, query, file_delete_handler, (void *)&del); + + 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); + /* + * Now mark Job as having files purged. This is necessary to + * avoid having too many Jobs to process in future prunings. If + * we don't do this, the number of JobId's in our in memory list + * will grow very large. + */ + Mmsg(&query, "UPDATE Job Set PurgedFiles=1 WHERE JobId=%d", del.JobId[i]); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Del sql=%s\n", query); + } + bsendmsg(ua, _("%d Files for client %s purged from %s catalog.\n"), del.num_ids, + client->hdr.name, client->catalog->hdr.name); + +bail_out: + if (del.JobId) { + free(del.JobId); + } + free_pool_memory(query); + return 1; +} + + + +/* + * Purging Jobs is a bit more complicated than purging Files + * because we delete Job records only if there is a more current + * backup of the FileSet. Otherwise, we keep the Job record. + * In other words, we never delete the only Job record that + * contains a current backup of a FileSet. This prevents the + * Volume from being recycled and destroying a current backup. + */ +int purge_jobs_from_client(UAContext *ua, CLIENT *client) +{ + struct s_job_del_ctx del; + char *query = (char *)get_pool_memory(PM_MESSAGE); + int i; + CLIENT_DBR cr; + + memset(&cr, 0, sizeof(cr)); + 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); + + if (!db_sql_query(ua->db, query, job_count_handler, (void *)&del)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + Dmsg0(050, "Count failed\n"); + goto bail_out; + } + if (del.tot_ids == 0) { + bsendmsg(ua, _("No Jobs found for client %s to purge from %s catalog.\n"), + client->hdr.name, client->catalog->hdr.name); + goto bail_out; + } + + if (del.tot_ids < MAX_DEL_LIST_LEN) { + del.max_ids = del.tot_ids + 1; + } else { + del.max_ids = MAX_DEL_LIST_LEN; + } + + del.tot_ids = 0; + + + + del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); + del.PurgedFiles = (char *)malloc(del.max_ids); + + db_sql_query(ua->db, query, job_delete_handler, (void *)&del); + + /* + * OK, now we have the list of JobId's to be purged, first check + * if the Files have been purged, if not, purge (delete) them. + * Then delete the Job entry, and finally and JobMedia records. + */ + for (i=0; i < del.num_ids; i++) { + Dmsg1(050, "Delete JobId=%d\n", del.JobId[i]); + if (!del.PurgedFiles[i]) { + Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Del sql=%s\n", query); + } + + Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]); + db_sql_query(ua->db, query, NULL, (void *)NULL); + Dmsg1(050, "Del sql=%s\n", query); + + 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); + } + bsendmsg(ua, _("%d Jobs for client %s purged from %s catalog.\n"), del.num_ids, + client->hdr.name, client->catalog->hdr.name); + +bail_out: + if (del.JobId) { + free(del.JobId); + } + if (del.PurgedFiles) { + free(del.PurgedFiles); + } + free_pool_memory(query); + return 1; +} + +void purge_files_from_job(UAContext *ua, JOB_DBR *jr) +{ + char *query = (char *)get_pool_memory(PM_MESSAGE); + + Mmsg(&query, "DELETE FROM File WHERE JobId=%d", jr->JobId); + db_sql_query(ua->db, query, NULL, (void *)NULL); + + Mmsg(&query, "UPDATE Job Set PurgedFiles=1 WHERE JobId=%d", jr->JobId); + db_sql_query(ua->db, query, NULL, (void *)NULL); + + free_pool_memory(query); +} diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index cb2693cdf6..9ad7b6b6e7 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -208,9 +208,6 @@ CLIENT *get_client_resource(UAContext *ua) return select_client_resource(ua); } - - - /* Scan what the user has entered looking for: * * pool= @@ -287,6 +284,47 @@ int select_pool_dbr(UAContext *ua, POOL_DBR *pr) return opr.PoolId; } +/* + * Select a Pool and a Media (Volume) record from the database + */ +int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) +{ + int found = FALSE; + int i; + + memset(pr, 0, sizeof(POOL_DBR)); + memset(mr, 0, sizeof(MEDIA_DBR)); + + /* Get the pool, possibly from pool= */ + if (!get_pool_dbr(ua, pr)) { + return 0; + } + mr->PoolId = pr->PoolId; + + /* See if a volume name is specified as an argument */ + for (i=1; iargc; i++) { + if (strcasecmp(ua->argk[i], _("volume")) == 0 && ua->argv[i]) { + found = TRUE; + break; + } + } + if (found) { + strcpy(mr->VolumeName, ua->argv[i]); + } else { + db_list_media_records(ua->db, mr, prtit, ua); + if (!get_cmd(ua, _("Enter the Volume name to delete: "))) { + return 01; + } + strcpy(mr->VolumeName, ua->cmd); + } + mr->MediaId = 0; + if (!db_get_media_record(ua->db, mr)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + return 0; + } + return 1; +} + /* * This routine is ONLY used in the create command. @@ -321,6 +359,63 @@ POOL *get_pool_resource(UAContext *ua) return pool; } +/* + * List all jobs and ask user to select one + */ +int select_job_dbr(UAContext *ua, JOB_DBR *jr) +{ + db_list_job_records(ua->db, jr, prtit, ua); + if (!get_cmd(ua, _("Enter the JobId to select: "))) { + return 0; + } + jr->JobId = atoi(ua->cmd); + if (!db_get_job_record(ua->db, jr)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + return 0; + } + return jr->JobId; + +} + + +/* Scan what the user has entered looking for: + * + * jobid=nn + * + * if error or not found, put up a list of Jobs + * to choose from. + * + * returns: 0 on error + * JobId on success and fills in JOB_DBR + */ +int get_job_dbr(UAContext *ua, JOB_DBR *jr) +{ + int i; + + for (i=1; iargc; i++) { + if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) { + jr->JobId = 0; + strcpy(jr->Job, ua->argv[i]); + } else if (strcasecmp(ua->argk[i], _("jobid")) == 0 && ua->argv[i]) { + jr->JobId = atoi(ua->argv[i]); + } else { + continue; + } + if (!db_get_job_record(ua->db, jr)) { + bsendmsg(ua, _("Could not find Job %s: ERR=%s"), ua->argv[i], + db_strerror(ua->db)); + jr->JobId = 0; + break; + } + return jr->JobId; + } + + if (!select_job_dbr(ua, jr)) { /* try once more */ + return 0; + } + return jr->JobId; +} + diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index a05ee54b1c..eb8b651f71 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -220,8 +220,8 @@ static void do_director_status(UAContext *ua, char *cmd) } bsendmsg(ua, _(" Files=%s Bytes=%s Termination Status=%s\n"), - edit_uint_with_commas(last_job.JobFiles, b1), - edit_uint_with_commas(last_job.JobBytes, b2), + edit_uint64_with_commas(last_job.JobFiles, b1), + edit_uint64_with_commas(last_job.JobBytes, b2), termstat); } lock_jcr_chain(); diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 825758a3f1..b9d3a7de0f 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -306,7 +306,7 @@ Termination: %s\n"), jcr->client->hdr.name, sdt, edt, - edit_uint_with_commas(jcr->jr.JobFiles, ec1), + edit_uint64_with_commas(jcr->jr.JobFiles, ec1), term_msg); Dmsg0(100, "Leave verify_cleanup()\n"); diff --git a/bacula/src/filed/status.c b/bacula/src/filed/status.c index da15c6fe65..832f7511f9 100755 --- a/bacula/src/filed/status.c +++ b/bacula/src/filed/status.c @@ -71,8 +71,8 @@ static void do_status(void sendit(char *msg, int len, void *sarg), void *arg) } len = Mmsg(&msg, _(" Files=%s Bytes=%s Termination Status=%s\n"), - edit_uint_with_commas(last_job.JobFiles, b1), - edit_uint_with_commas(last_job.JobBytes, b2), + edit_uint64_with_commas(last_job.JobFiles, b1), + edit_uint64_with_commas(last_job.JobBytes, b2), termstat); sendit(msg, len, arg); } @@ -96,12 +96,12 @@ static void do_status(void sendit(char *msg, int len, void *sarg), void *arg) } bps = njcr->JobBytes / sec; len = Mmsg(&msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"), - edit_uint_with_commas(njcr->JobFiles, b1), - edit_uint_with_commas(njcr->JobBytes, b2), - edit_uint_with_commas(bps, b3)); + edit_uint64_with_commas(njcr->JobFiles, b1), + edit_uint64_with_commas(njcr->JobBytes, b2), + edit_uint64_with_commas(bps, b3)); sendit(msg, len, arg); len = Mmsg(&msg, _(" Files Examined=%s\n"), - edit_uint_with_commas(njcr->num_files_examined, b1)); + edit_uint64_with_commas(njcr->num_files_examined, b1)); sendit(msg, len, arg); if (njcr->JobFiles > 0) { len = Mmsg(&msg, _(" Processing file: %s\n"), njcr->last_fname); diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 115cb327f9..2f0ec19bb0 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -22,128 +22,128 @@ */ /* base64.c */ -void base64_init __PROTO((void)); -int to_base64 __PROTO((intmax_t value, char *where)); -int from_base64 __PROTO((intmax_t *value, char *where)); -void encode_stat __PROTO((char *buf, struct stat *statp)); -void decode_stat __PROTO((char *buf, struct stat *statp)); -int bin_to_base64 __PROTO((char *buf, char *bin, int len)); +void base64_init __PROTO((void)); +int to_base64 __PROTO((intmax_t value, char *where)); +int from_base64 __PROTO((intmax_t *value, char *where)); +void encode_stat __PROTO((char *buf, struct stat *statp)); +void decode_stat __PROTO((char *buf, struct stat *statp)); +int bin_to_base64 __PROTO((char *buf, char *bin, int len)); /* bmisc.c */ -void *b_malloc (char *file, int line, size_t size); +void *b_malloc (char *file, int line, size_t size); #ifndef DEBUG -void *bmalloc (size_t size); +void *bmalloc (size_t size); #endif -void *brealloc (void *buf, size_t size); -void *bcalloc (size_t size1, size_t size2); -int bsnprintf (char *str, size_t size, const char *format, ...); -int bvsnprintf (char *str, size_t size, const char *format, va_list ap); -int pool_sprintf (char *pool_buf, char *fmt, ...); -int create_pid_file (char *dir, char *progname, int port, char *errmsg); -int delete_pid_file (char *dir, char *progname, int port); +void *brealloc (void *buf, size_t size); +void *bcalloc (size_t size1, size_t size2); +int bsnprintf (char *str, size_t size, const char *format, ...); +int bvsnprintf (char *str, size_t size, const char *format, va_list ap); +int pool_sprintf (char *pool_buf, char *fmt, ...); +int create_pid_file (char *dir, char *progname, int port, char *errmsg); +int delete_pid_file (char *dir, char *progname, int port); /* bnet.c */ -int32_t bnet_recv __PROTO((BSOCK *bsock)); -int bnet_send __PROTO((BSOCK *bsock)); -int bnet_fsend (BSOCK *bs, char *fmt, ...); -int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); -int bnet_sig (BSOCK *bs, int sig); -BSOCK * bnet_connect (void *jcr, int retry_interval, - int max_retry_time, char *name, char *host, char *service, - int port, int verbose); -int bnet_wait_data (BSOCK *bsock, int sec); -void bnet_close __PROTO((BSOCK *bsock)); -BSOCK * init_bsock __PROTO((int sockfd, char *who, char *ip, int port)); -BSOCK * dup_bsock __PROTO((BSOCK *bsock)); -void term_bsock __PROTO((BSOCK *bsock)); -char * bnet_strerror __PROTO((BSOCK *bsock)); -char * bnet_sig_to_ascii __PROTO((BSOCK *bsock)); -int bnet_wait_data __PROTO((BSOCK *bsock, int sec)); +int32_t bnet_recv __PROTO((BSOCK *bsock)); +int bnet_send __PROTO((BSOCK *bsock)); +int bnet_fsend (BSOCK *bs, char *fmt, ...); +int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); +int bnet_sig (BSOCK *bs, int sig); +BSOCK * bnet_connect (void *jcr, int retry_interval, + int max_retry_time, char *name, char *host, char *service, + int port, int verbose); +int bnet_wait_data (BSOCK *bsock, int sec); +void bnet_close __PROTO((BSOCK *bsock)); +BSOCK * init_bsock __PROTO((int sockfd, char *who, char *ip, int port)); +BSOCK * dup_bsock __PROTO((BSOCK *bsock)); +void term_bsock __PROTO((BSOCK *bsock)); +char * bnet_strerror __PROTO((BSOCK *bsock)); +char * bnet_sig_to_ascii __PROTO((BSOCK *bsock)); +int bnet_wait_data __PROTO((BSOCK *bsock, int sec)); /* cram-md5.c */ int cram_md5_get_auth(BSOCK *bs, char *password); int cram_md5_auth(BSOCK *bs, char *password); void hmac_md5(uint8_t* text, int text_len, uint8_t* key, - int key_len, uint8_t *hmac); + int key_len, uint8_t *hmac); /* create_file.c */ int create_file(void *jcr, char *fname, char *ofile, char *lname, - int type, struct stat *statp, int *ofd); + int type, struct stat *statp, int *ofd); int set_statp(void *jcr, char *fname, char *ofile, char *lname, int type, - struct stat *statp); + struct stat *statp); /* crc32.c */ uint32_t bcrc32(uint8_t *buf, int len); /* daemon.c */ -void daemon_start __PROTO(()); +void daemon_start __PROTO(()); /* lex.c */ -LEX * lex_close_file __PROTO((LEX *lf)); -LEX * lex_open_file __PROTO((LEX *lf, char *fname)); -int lex_get_char __PROTO((LEX *lf)); -void lex_unget_char __PROTO((LEX *lf)); -char * lex_tok_to_str __PROTO((int token)); -int lex_get_token __PROTO((LEX *lf)); +LEX * lex_close_file __PROTO((LEX *lf)); +LEX * lex_open_file __PROTO((LEX *lf, char *fname)); +int lex_get_char __PROTO((LEX *lf)); +void lex_unget_char __PROTO((LEX *lf)); +char * lex_tok_to_str __PROTO((int token)); +int lex_get_token __PROTO((LEX *lf)); /* makepath.c */ int make_path( - void *jcr, - const char *argpath, - int mode, - int parent_mode, - uid_t owner, - gid_t group, - int preserve_existing, - char *verbose_fmt_string); + void *jcr, + const char *argpath, + int mode, + int parent_mode, + uid_t owner, + gid_t group, + int preserve_existing, + char *verbose_fmt_string); /* message.c */ -void my_name_is __PROTO((int argc, char *argv[], char *name)); -void init_msg __PROTO((void *jcr)); -void term_msg __PROTO((void)); -void close_msg __PROTO((void *jcr)); -void add_msg_dest __PROTO((int dest, int type, char *where, char *dest_code)); -void rem_msg_dest __PROTO((int dest, int type, char *where)); -void Jmsg (void *jcr, int type, int level, char *fmt, ...); -void dispatch_message __PROTO((void *jcr, int type, int level, char *buf)); -void init_console_msg __PROTO((char *wd)); +void my_name_is __PROTO((int argc, char *argv[], char *name)); +void init_msg __PROTO((void *jcr)); +void term_msg __PROTO((void)); +void close_msg __PROTO((void *jcr)); +void add_msg_dest __PROTO((int dest, int type, char *where, char *dest_code)); +void rem_msg_dest __PROTO((int dest, int type, char *where)); +void Jmsg (void *jcr, int type, int level, char *fmt, ...); +void dispatch_message __PROTO((void *jcr, int type, int level, char *buf)); +void init_console_msg __PROTO((char *wd)); /* bnet_server.c */ -void bnet_thread_server(int port, int max_clients, workq_t *client_wq, - void handle_client_request(void *bsock)); -void bnet_server __PROTO((int port, void handle_client_request(BSOCK *bsock))); -int net_connect __PROTO((int port)); -BSOCK * bnet_bind __PROTO((int port)); -BSOCK * bnet_accept __PROTO((BSOCK *bsock, char *who)); +void bnet_thread_server(int port, int max_clients, workq_t *client_wq, + void handle_client_request(void *bsock)); +void bnet_server __PROTO((int port, void handle_client_request(BSOCK *bsock))); +int net_connect __PROTO((int port)); +BSOCK * bnet_bind __PROTO((int port)); +BSOCK * bnet_accept __PROTO((BSOCK *bsock, char *who)); /* signal.c */ -void init_signals __PROTO((void terminate(int sig))); -void init_stack_dump (void); +void init_signals __PROTO((void terminate(int sig))); +void init_stack_dump (void); /* util.c */ -void lcase __PROTO((char *str)); -void bash_spaces __PROTO((char *str)); -void unbash_spaces __PROTO((char *str)); -void strip_trailing_junk __PROTO((char *str)); -void strip_trailing_slashes __PROTO((char *dir)); -int skip_spaces __PROTO((char **msg)); -int skip_nonspaces __PROTO((char **msg)); -int fstrsch __PROTO((char *a, char *b)); -char * encode_time __PROTO((time_t time, char *buf)); -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)); -char * edit_uint (uint64_t val, char *buf); -int do_shell_expansion (char *name); -int is_a_number (const char *num); +void lcase __PROTO((char *str)); +void bash_spaces __PROTO((char *str)); +void unbash_spaces __PROTO((char *str)); +void strip_trailing_junk __PROTO((char *str)); +void strip_trailing_slashes __PROTO((char *dir)); +int skip_spaces __PROTO((char **msg)); +int skip_nonspaces __PROTO((char **msg)); +int fstrsch __PROTO((char *a, char *b)); +char * encode_time __PROTO((time_t time, char *buf)); +char * encode_mode __PROTO((mode_t mode, char *buf)); +char * edit_uint64_with_commas __PROTO((uint64_t val, char *buf)); +char * add_commas __PROTO((char *val, char *buf)); +char * edit_uint64 (uint64_t val, char *buf); +int do_shell_expansion (char *name); +int is_a_number (const char *num); /* - *void print_ls_output __PROTO((char *fname, char *lname, int type, struct stat *statp)); + *void print_ls_output __PROTO((char *fname, char *lname, int type, struct stat *statp)); */ /* watchdog.c */ diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index 99b0d42dbb..aaa7d72679 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -65,7 +65,7 @@ int is_a_number(const char *n) * 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) +char *edit_uint64_with_commas(uint64_t val, char *buf) { sprintf(buf, "%" lld, val); return add_commas(buf, buf); @@ -76,7 +76,7 @@ char *edit_uint_with_commas(uint64_t val, char *buf) * must be at least 27 bytes long. The incoming number * is always widened to 64 bits. */ -char *edit_uint(uint64_t val, char *buf) +char *edit_uint64(uint64_t val, char *buf) { sprintf(buf, "%" lld, val); return buf; diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index c577e6dfab..629fff8515 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -569,8 +569,8 @@ int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) /* Inform User about end of media */ Jmsg(jcr, M_INFO, 0, _("End of media on Volume %s Bytes=%s Blocks=%s.\n"), - PrevVolName, edit_uint_with_commas(dev->VolCatInfo.VolCatBytes, b1), - edit_uint_with_commas(dev->VolCatInfo.VolCatBlocks, b2)); + PrevVolName, edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1), + edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2)); if (!dev_is_tape(dev)) { /* If file, */ close_dev(dev); /* yes, close it */ diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 7713d9626f..4b81b14369 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -620,8 +620,8 @@ static int status_cmd(JCR *jcr) } bnet_fsend(user, _(" Files=%s Bytes=%s Termination Status=%s\n"), - edit_uint_with_commas(last_job.JobFiles, b1), - edit_uint_with_commas(last_job.JobBytes, b2), + edit_uint64_with_commas(last_job.JobFiles, b1), + edit_uint64_with_commas(last_job.JobBytes, b2), termstat); } @@ -665,12 +665,12 @@ static int status_cmd(JCR *jcr) } bpb = dev->VolCatInfo.VolCatBytes / bpb; bnet_fsend(user, _(" Total Bytes=%s Blocks=%s Bytes/block=%s\n"), - edit_uint_with_commas(dev->VolCatInfo.VolCatBytes, b1), - edit_uint_with_commas(dev->VolCatInfo.VolCatBlocks, b2), - edit_uint_with_commas(bpb, b3)); + edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1), + edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), + edit_uint64_with_commas(bpb, b3)); bnet_fsend(user, _(" Positioned at File=%s Block=%s\n"), - edit_uint_with_commas(dev->file, b1), - edit_uint_with_commas(dev->block_num, b2)); + edit_uint64_with_commas(dev->file, b1), + edit_uint64_with_commas(dev->block_num, b2)); } else { bnet_fsend(user, _("Device %s is not open.\n"), dev_name(dev)); @@ -696,9 +696,9 @@ static int status_cmd(JCR *jcr) } bps = jcr->JobBytes / sec; bnet_fsend(user, _(" Files=%s Bytes=%s Bytes/sec=%s\n"), - edit_uint_with_commas(jcr->JobFiles, b1), - edit_uint_with_commas(jcr->JobBytes, b2), - edit_uint_with_commas(bps, b3)); + edit_uint64_with_commas(jcr->JobFiles, b1), + edit_uint64_with_commas(jcr->JobBytes, b2), + edit_uint64_with_commas(bps, b3)); found = 1; #ifdef DEBUG if (jcr->file_bsock) { diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 45e22a9020..8287cdffe2 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -597,13 +597,13 @@ StartFile : %s\n\ EndFile : %s\n\ JobErrors : %s\n\ ", - edit_uint_with_commas(label.JobFiles, ec1), - edit_uint_with_commas(label.JobBytes, ec2), - edit_uint_with_commas(label.start_block, ec3), - edit_uint_with_commas(label.end_block, ec4), - edit_uint_with_commas(label.start_file, ec5), - edit_uint_with_commas(label.end_file, ec6), - edit_uint_with_commas(label.JobErrors, ec7)); + edit_uint64_with_commas(label.JobFiles, ec1), + edit_uint64_with_commas(label.JobBytes, ec2), + edit_uint64_with_commas(label.start_block, ec3), + edit_uint64_with_commas(label.end_block, ec4), + edit_uint64_with_commas(label.start_file, ec5), + edit_uint64_with_commas(label.end_file, ec6), + edit_uint64_with_commas(label.JobErrors, ec7)); } dt.julian_day_number = label.write_date; dt.julian_day_fraction = label.write_time;