From 0af84b856321071939b45ad087802031b8547c6e Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Mon, 18 Jan 2010 16:19:29 +0100 Subject: [PATCH] Add comment= option to restore and run commands --- bacula/src/cats/sql_create.c | 13 ++++++--- bacula/src/dird/job.c | 9 ++++++- bacula/src/dird/protos.h | 1 + bacula/src/dird/ua.h | 1 + bacula/src/dird/ua_cmds.c | 4 +-- bacula/src/dird/ua_input.c | 36 +++++++++++++++++++++++++ bacula/src/dird/ua_restore.c | 52 +++++++++++++++++++----------------- bacula/src/dird/ua_run.c | 20 +++++++++++--- bacula/src/dird/ua_status.c | 10 +++++-- bacula/src/jcr.h | 1 + 10 files changed, 112 insertions(+), 35 deletions(-) diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 736db4420f..c7c7e71070 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -66,10 +66,12 @@ static int db_create_filename_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar); bool db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { + POOL_MEM buf; char dt[MAX_TIME_LENGTH]; time_t stime; struct tm tm; bool ok; + int len; utime_t JobTDate; char ed1[30],ed2[30]; @@ -82,13 +84,18 @@ db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm); JobTDate = (utime_t)stime; + len = strlen(jcr->comment); + buf.check_size(len*2+1); + db_escape_string(jcr, mdb, buf.c_str(), jcr->comment, len); + /* Must create it */ Mmsg(mdb->cmd, -"INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate,ClientId) " -"VALUES ('%s','%s','%c','%c','%c','%s',%s,%s)", +"INSERT INTO Job (Job,Name,Type,Level,JobStatus,SchedTime,JobTDate," + "ClientId,Comment) " +"VALUES ('%s','%s','%c','%c','%c','%s',%s,%s,'%s')", jr->Job, jr->Name, (char)(jr->JobType), (char)(jr->JobLevel), (char)(jr->JobStatus), dt, edit_uint64(JobTDate, ed1), - edit_int64(jr->ClientId, ed2)); + edit_int64(jr->ClientId, ed2), buf.c_str()); if (!INSERT_DB(jcr, mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create DB Job record %s failed. ERR=%s\n"), diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 0860e7d69b..331cfd10c7 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -140,7 +140,10 @@ bool setup_job(JCR *jcr) goto bail_out; } Dmsg0(150, "DB opened\n"); - + if (!jcr->comment) { + jcr->comment = get_pool_memory(PM_MESSAGE); + *jcr->comment = '\0'; + } if (!jcr->fname) { jcr->fname = get_pool_memory(PM_FNAME); } @@ -965,6 +968,10 @@ void dird_free_jcr_pointers(JCR *jcr) bnet_close(jcr->store_bsock); jcr->store_bsock = NULL; } + if (jcr->comment) { + free_pool_memory(jcr->comment); + jcr->comment = NULL; + } if (jcr->fname) { Dmsg0(200, "Free JCR fname\n"); free_pool_memory(jcr->fname); diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 6d99a859d8..9f84950337 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -211,6 +211,7 @@ bool get_yesno(UAContext *ua, const char *prompt); bool is_yesno(char *val, int *ret); int get_enabled(UAContext *ua, const char *val); void parse_ua_args(UAContext *ua); +bool is_comment_legal(UAContext *ua, const char *name); /* ua_label.c */ bool is_volume_name_legal(UAContext *ua, const char *name); diff --git a/bacula/src/dird/ua.h b/bacula/src/dird/ua.h index 31ca5b49e4..522ac87a7b 100644 --- a/bacula/src/dird/ua.h +++ b/bacula/src/dird/ua.h @@ -112,6 +112,7 @@ struct RESTORE_CTX { POOL *pool; int restore_jobs; uint32_t selected_files; + char *comment; char *where; char *RegexWhere; RBSR *bsr; diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 34d25595c6..2a8ebec0ef 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -157,7 +157,7 @@ static struct cmdstruct commands[] = { /* C { NT_("query"), querycmd, _("Query catalog"), NT_(""), false}, { NT_("restore"), restore_cmd, _("Restore files"), NT_("where= client= storage= bootstrap=" - "\n\tjobid= done select all"), false}, + "\n\tcomment= jobid= done select all"), false}, { NT_("relabel"), relabel_cmd, _("Relabel a tape"), NT_("storage= oldvolume=\n\tvolume= pool="), false}, @@ -166,7 +166,7 @@ static struct cmdstruct commands[] = { /* C { NT_("reload"), reload_cmd, _("Reload conf file"), NT_(""), true}, { NT_("run"), run_cmd, _("Run a job"), NT_("job= client=\n\tfileset= level=\n\tstorage=" - "where=\n\twhen=\n\tyes"), false}, /* need to be check */ + "where=\n\twhen=\n\tcomment= yes"), false}, { NT_("status"), status_cmd, _("Report status"), NT_("all | dir= | director | client= | storage= slots | days=nnn"), true}, diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index b87c73a2bc..ef081144df 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -192,3 +192,39 @@ void parse_ua_args(UAContext *ua) { parse_args(ua->cmd, &ua->args, &ua->argc, ua->argk, ua->argv, MAX_CMD_ARGS); } + +/* + * Check if the comment has legal characters + * If ua is non-NULL send the message + */ +bool is_comment_legal(UAContext *ua, const char *name) +{ + int len; + const char *p; + const char *forbid = "'<>&\\\""; + + /* Restrict the characters permitted in the comment */ + for (p=name; *p; p++) { + if (!strchr(forbid, (int)(*p))) { + continue; + } + if (ua) { + ua->error_msg(_("Illegal character \"%c\" in a comment.\n"), *p); + } + return 0; + } + len = strlen(name); + if (len >= MAX_NAME_LENGTH) { + if (ua) { + ua->error_msg(_("Comment too long.\n")); + } + return 0; + } + if (len == 0) { + if (ua) { + ua->error_msg(_("Comment must be at least one character long.\n")); + } + return 0; + } + return 1; +} diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 653804a502..c2348d89f9 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -79,6 +79,7 @@ static void get_and_display_basejobs(UAContext *ua, RESTORE_CTX *rx); int restore_cmd(UAContext *ua, const char *cmd) { RESTORE_CTX rx; /* restore context */ + POOL_MEM buf; JOB *job; int i; JCR *jcr = ua->jcr; @@ -95,6 +96,14 @@ int restore_cmd(UAContext *ua, const char *cmd) rx.query = get_pool_memory(PM_FNAME); rx.bsr = new_bsr(); + i = find_arg_with_value(ua, "comment"); + if (i >= 0) { + rx.comment = ua->argv[i]; + if (!is_comment_legal(ua, rx.comment)) { + goto bail_out; + } + } + i = find_arg_with_value(ua, "where"); if (i >= 0) { rx.where = ua->argv[i]; @@ -227,37 +236,31 @@ int restore_cmd(UAContext *ua, const char *cmd) escaped_bsr_name = escape_filename(jcr->RestoreBootstrap); + Mmsg(ua->cmd, + "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" + " bootstrap=\"%s\" files=%u catalog=\"%s\"", + job->name(), rx.ClientName, rx.RestoreClientName, + rx.store?rx.store->name():"", + escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, + rx.selected_files, ua->catalog->name()); + /* Build run command */ + pm_strcpy(buf, ""); if (rx.RegexWhere) { escaped_where_name = escape_filename(rx.RegexWhere); - Mmsg(ua->cmd, - "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" - " bootstrap=\"%s\" regexwhere=\"%s\" files=%u catalog=\"%s\"", - job->name(), rx.ClientName, rx.RestoreClientName, - rx.store?rx.store->name():"", - escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, - escaped_where_name ? escaped_where_name : rx.RegexWhere, - rx.selected_files, ua->catalog->name()); + Mmsg(buf, " regexwhere=\"%s\"", + escaped_where_name ? escaped_where_name : rx.RegexWhere); } else if (rx.where) { escaped_where_name = escape_filename(rx.where); - Mmsg(ua->cmd, - "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" - " bootstrap=\"%s\" where=\"%s\" files=%u catalog=\"%s\"", - job->name(), rx.ClientName, rx.RestoreClientName, - rx.store?rx.store->name():"", - escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, - escaped_where_name ? escaped_where_name : rx.where, - rx.selected_files, ua->catalog->name()); + Mmsg(buf," where=\"%s\"", + escaped_where_name ? escaped_where_name : rx.where); + } + pm_strcat(ua->cmd, buf); - } else { - Mmsg(ua->cmd, - "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" - " bootstrap=\"%s\" files=%u catalog=\"%s\"", - job->name(), rx.ClientName, rx.RestoreClientName, - rx.store?rx.store->name():"", - escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, - rx.selected_files, ua->catalog->name()); + if (rx.comment) { + Mmsg(buf, " comment=\"%s\"", rx.comment); + pm_strcat(ua->cmd, buf); } if (escaped_bsr_name != NULL) { @@ -452,6 +455,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx) "regexwhere", /* 18 */ "restoreclient", /* 19 */ "copies", /* 20 */ + "comment", /* 21 */ NULL }; diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 5a25811eb4..be7b5e89a0 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -41,7 +41,7 @@ class run_ctx { public: char *job_name, *level_name, *jid, *store_name, *pool_name; char *where, *fileset_name, *client_name, *bootstrap, *regexwhere; - char *restore_client_name; + char *restore_client_name, *comment; const char *replace; char *when, *verify_job_name, *catalog_name; char *previous_job_name; @@ -438,6 +438,12 @@ static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc) jcr->catalog = rc.catalog; pm_strcpy(jcr->catalog_source, _("User input")); } + + if (!jcr->comment) { + jcr->comment = get_pool_memory(PM_MESSAGE); + } + pm_strcpy(jcr->comment, rc.comment); + if (rc.where) { if (jcr->where) { free(jcr->where); @@ -1012,6 +1018,7 @@ static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc) "restoreclient", /* 24 */ "pluginoptions", /* 25 */ "spooldata", /* 26 */ + "comment", /* 27 */ NULL}; #define YES_POS 14 @@ -1026,7 +1033,7 @@ static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc) rc.verify_job_name = NULL; rc.previous_job_name = NULL; rc.spool_data_set = 0; - + rc.comment = NULL; for (i=1; iargc; i++) { Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]); @@ -1244,6 +1251,9 @@ static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc) ua->send_msg(_("Invalid spooldata flag.\n")); } break; + case 27: /* comment */ + rc.comment = ua->argv[i]; + kw_ok = true; default: break; } @@ -1269,7 +1279,11 @@ static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc) } /* end argc loop */ Dmsg0(800, "Done scan.\n"); - + if (rc.comment) { + if (!is_comment_legal(ua, rc.comment)) { + return false; + } + } if (rc.catalog_name) { rc.catalog = GetCatalogResWithName(rc.catalog_name); if (rc.catalog == NULL) { diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index 3ff5f30be5..deda34f742 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -786,11 +786,17 @@ static void list_running_jobs(UAContext *ua) } if (ua->api) { - ua->send_msg(_("%6d\t%-6s\t%-20s\t%s\n"), - jcr->JobId, level, jcr->Job, msg); + bash_spaces(jcr->comment); + ua->send_msg(_("%6d\t%-6s\t%-20s\t%s\t%s\n"), + jcr->JobId, level, jcr->Job, msg, jcr->comment); + unbash_spaces(jcr->comment); } else { ua->send_msg(_("%6d %-6s %-20s %s\n"), jcr->JobId, level, jcr->Job, msg); + /* Display comments if any */ + if (*jcr->comment) { + ua->send_msg(_(" %-30s\n"), jcr->comment); + } } if (pool_mem) { diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 4513e800f6..1ab7759867 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -274,6 +274,7 @@ public: save_pkt *plugin_sp; /* plugin save packet */ char *plugin_options; /* user set options for plugin */ bool cmd_plugin; /* Set when processing a command Plugin = */ + POOLMEM *comment; /* Comment for this Job */ /* Daemon specific part of JCR */ /* This should be empty in the library */ -- 2.39.5