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];
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"),
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);
}
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);
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);
POOL *pool;
int restore_jobs;
uint32_t selected_files;
+ char *comment;
char *where;
char *RegexWhere;
RBSR *bsr;
{ NT_("query"), querycmd, _("Query catalog"), NT_(""), false},
{ NT_("restore"), restore_cmd, _("Restore files"),
NT_("where=</path> client=<client> storage=<storage> bootstrap=<file>"
- "\n\tjobid=<jobid> done select all"), false},
+ "\n\tcomment=<text> jobid=<jobid> done select all"), false},
{ NT_("relabel"), relabel_cmd, _("Relabel a tape"),
NT_("storage=<storage-name> oldvolume=<old-volume-name>\n\tvolume=<newvolume-name> pool=<pool>"), false},
{ NT_("reload"), reload_cmd, _("Reload conf file"), NT_(""), true},
{ NT_("run"), run_cmd, _("Run a job"),
NT_("job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
- "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tyes"), false}, /* need to be check */
+ "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tcomment=<text> yes"), false},
{ NT_("status"), status_cmd, _("Report status"),
NT_("all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> slots | days=nnn"), true},
{
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;
+}
int restore_cmd(UAContext *ua, const char *cmd)
{
RESTORE_CTX rx; /* restore context */
+ POOL_MEM buf;
JOB *job;
int i;
JCR *jcr = ua->jcr;
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];
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) {
"regexwhere", /* 18 */
"restoreclient", /* 19 */
"copies", /* 20 */
+ "comment", /* 21 */
NULL
};
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;
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);
"restoreclient", /* 24 */
"pluginoptions", /* 25 */
"spooldata", /* 26 */
+ "comment", /* 27 */
NULL};
#define YES_POS 14
rc.verify_job_name = NULL;
rc.previous_job_name = NULL;
rc.spool_data_set = 0;
-
+ rc.comment = NULL;
for (i=1; i<ua->argc; i++) {
Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
ua->send_msg(_("Invalid spooldata flag.\n"));
}
break;
+ case 27: /* comment */
+ rc.comment = ua->argv[i];
+ kw_ok = true;
default:
break;
}
} /* 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) {
}
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) {
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 */