+++ /dev/null
-Index: src/dird/ua.h
-===================================================================
---- src/dird/ua.h (révision 7720)
-+++ src/dird/ua.h (copie de travail)
-@@ -60,6 +60,7 @@
- bool verbose; /* set for normal UA verbosity */
- bool batch; /* set for non-interactive mode */
- bool gui; /* set if talking to GUI program */
-+ bool runscript; /* set if we are in runscript */
- uint32_t pint32_val; /* positive integer */
- int32_t int32_val; /* positive/negative */
- int64_t int64_val; /* big int */
-Index: src/dird/job.c
-===================================================================
---- src/dird/job.c (révision 7720)
-+++ src/dird/job.c (copie de travail)
-@@ -1372,6 +1372,8 @@
- bool ok;
-
- ua = new_ua_context(jcr);
-+ /* run from runscript and check if commands are autorized */
-+ ua->runscript = true;
- Mmsg(ua->cmd, "%s", cmd);
- Dmsg1(100, "Console command: %s\n", ua->cmd);
- parse_ua_args(ua);
-Index: src/dird/ua_cmds.c
-===================================================================
---- src/dird/ua_cmds.c (révision 7720)
-+++ src/dird/ua_cmds.c (copie de travail)
-@@ -96,50 +96,50 @@
- int quit_cmd(UAContext *ua, const char *cmd);
-
-
--struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; };
--static struct cmdstruct commands[] = {
-- { NT_("add"), add_cmd, _("add media to a pool")},
-- { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages")},
-- { NT_("automount"), automount_cmd, _("automount [on|off] -- after label")},
-- { NT_("cancel"), cancel_cmd, _("cancel [<jobid=nnn> | <job=name>] -- cancel a job")},
-- { NT_("create"), create_cmd, _("create DB Pool from resource")},
-- { NT_("delete"), delete_cmd, _("delete [pool=<pool-name> | media volume=<volume-name>]")},
-- { NT_("disable"), disable_cmd, _("disable <job=name> -- disable a job")},
-- { NT_("enable"), enable_cmd, _("enable <job=name> -- enable a job")},
-- { NT_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing")},
-- { NT_("exit"), quit_cmd, _("exit = quit")},
-- { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode")},
-- { NT_("help"), help_cmd, _("print this command")},
-- { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog")},
-- { NT_("label"), label_cmd, _("label a tape")},
-- { NT_("llist"), llist_cmd, _("full or long list like list command")},
-- { NT_("messages"), messagescmd, _("messages")},
-- { NT_("memory"), memory_cmd, _("print current memory usage")},
-- { NT_("mount"), mount_cmd, _("mount <storage-name>")},
-- { NT_("prune"), prunecmd, _("prune expired records from catalog")},
-- { NT_("purge"), purgecmd, _("purge records from catalog")},
-- { NT_("python"), python_cmd, _("python control commands")},
-- { NT_("quit"), quit_cmd, _("quit")},
-- { NT_("query"), querycmd, _("query catalog")},
-- { NT_("restore"), restore_cmd, _("restore files")},
-- { NT_("relabel"), relabel_cmd, _("relabel a tape")},
-- { NT_("release"), release_cmd, _("release <storage-name>")},
-- { NT_("reload"), reload_cmd, _("reload conf file")},
-- { NT_("run"), run_cmd, _("run <job-name>")},
-- { NT_("status"), status_cmd, _("status [storage | client]=<name>")},
-- { NT_("setdebug"), setdebug_cmd, _("sets debug level")},
-- { NT_("setip"), setip_cmd, _("sets new client address -- if authorized")},
-- { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]")},
-- { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")},
-- { NT_("time"), time_cmd, _("print current time")},
-- { NT_("trace"), trace_cmd, _("turn on/off trace to file")},
-- { NT_("unmount"), unmount_cmd, _("unmount <storage-name>")},
-- { NT_("umount"), unmount_cmd, _("umount <storage-name> for old-time Unix guys")},
-- { NT_("update"), update_cmd, _("update Volume, Pool or slots")},
-- { NT_("use"), use_cmd, _("use catalog xxx")},
-- { NT_("var"), var_cmd, _("does variable expansion")},
-- { NT_("version"), version_cmd, _("print Director version")},
-- { NT_("wait"), wait_cmd, _("wait until no jobs are running [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>]")},
-+struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; const bool use_in_rs;};
-+static struct cmdstruct commands[] = { /* Can use it in Console RunScript*/
-+ { NT_("add"), add_cmd, _("add media to a pool"), false},
-+ { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages"),false},
-+ { NT_("automount"), automount_cmd, _("automount [on|off] -- after label"), false},
-+ { NT_("cancel"), cancel_cmd, _("cancel [<jobid=nnn> | <job=name>] -- cancel a job"), false},
-+ { NT_("create"), create_cmd, _("create DB Pool from resource"), false},
-+ { NT_("delete"), delete_cmd, _("delete [pool=<pool-name> | media volume=<volume-name>]"), true},
-+ { NT_("disable"), disable_cmd, _("disable <job=name> -- disable a job"), true},
-+ { NT_("enable"), enable_cmd, _("enable <job=name> -- enable a job"), true},
-+ { NT_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing"), true},
-+ { NT_("exit"), quit_cmd, _("exit = quit"), false},
-+ { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode"), false},
-+ { NT_("help"), help_cmd, _("print this command"), false},
-+ { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog"), true},
-+ { NT_("label"), label_cmd, _("label a tape"), false},
-+ { NT_("llist"), llist_cmd, _("full or long list like list command"), true},
-+ { NT_("messages"), messagescmd, _("messages"), false},
-+ { NT_("memory"), memory_cmd, _("print current memory usage"), true},
-+ { NT_("mount"), mount_cmd, _("mount <storage-name>"), false},
-+ { NT_("prune"), prunecmd, _("prune expired records from catalog"), true},
-+ { NT_("purge"), purgecmd, _("purge records from catalog"), true},
-+ { NT_("python"), python_cmd, _("python control commands"), false},
-+ { NT_("quit"), quit_cmd, _("quit"), false},
-+ { NT_("query"), querycmd, _("query catalog"), false},
-+ { NT_("restore"), restore_cmd, _("restore files"), false},
-+ { NT_("relabel"), relabel_cmd, _("relabel a tape"), false},
-+ { NT_("release"), release_cmd, _("release <storage-name>"), false},
-+ { NT_("reload"), reload_cmd, _("reload conf file"), true},
-+ { NT_("run"), run_cmd, _("run <job-name>"), false},
-+ { NT_("status"), status_cmd, _("status [storage | client]=<name>"), true},
-+ { NT_("setdebug"), setdebug_cmd, _("sets debug level"), true},
-+ { NT_("setip"), setip_cmd, _("sets new client address -- if authorized"), false},
-+ { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]"), true},
-+ { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog"), false},
-+ { NT_("time"), time_cmd, _("print current time"), true},
-+ { NT_("trace"), trace_cmd, _("turn on/off trace to file"), true},
-+ { NT_("unmount"), unmount_cmd, _("unmount <storage-name>"), false},
-+ { NT_("umount"), unmount_cmd, _("umount <storage-name> for old-time Unix guys"),false},
-+ { NT_("update"), update_cmd, _("update Volume, Pool or slots"), true},
-+ { NT_("use"), use_cmd, _("use catalog xxx"), false},
-+ { NT_("var"), var_cmd, _("does variable expansion"), false},
-+ { NT_("version"), version_cmd, _("print Director version"), true},
-+ { NT_("wait"), wait_cmd, _("wait until no jobs are running [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>]"), false},
- };
- #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
-
-@@ -174,6 +174,11 @@
- !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
- break;
- }
-+ /* Check if this command is authorized in RunScript */
-+ if (ua->runscript && !commands[i].use_in_rs) {
-+ ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
-+ break;
-+ }
- if (ua->api) user->signal(BNET_CMD_BEGIN);
- ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
- found = true;
-Index: src/dird/ua_dotcmds.c
-===================================================================
---- src/dird/ua_dotcmds.c (révision 7720)
-+++ src/dird/ua_dotcmds.c (copie de travail)
-@@ -69,26 +69,26 @@
- static bool dot_quit_cmd(UAContext *ua, const char *cmd);
- static bool dot_help_cmd(UAContext *ua, const char *cmd);
-
--struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help; };
--static struct cmdstruct commands[] = {
-- { NT_(".api"), api_cmd, NULL},
-- { NT_(".backups"), backupscmd, NULL},
-- { NT_(".clients"), clientscmd, NULL},
-- { NT_(".defaults"), defaultscmd, NULL},
-- { NT_(".die"), diecmd, NULL},
-- { NT_(".exit"), dot_quit_cmd, NULL},
-- { NT_(".filesets"), filesetscmd, NULL},
-- { NT_(".help"), dot_help_cmd, NULL},
-- { NT_(".jobs"), jobscmd, NULL},
-- { NT_(".levels"), levelscmd, NULL},
-- { NT_(".messages"), getmsgscmd, NULL},
-- { NT_(".msgs"), msgscmd, NULL},
-- { NT_(".pools"), poolscmd, NULL},
-- { NT_(".quit"), dot_quit_cmd, NULL},
-- { NT_(".sql"), sql_cmd, NULL},
-- { NT_(".status"), dot_status_cmd, NULL},
-- { NT_(".storage"), storagecmd, NULL},
-- { NT_(".types"), typescmd, NULL}
-+struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
-+static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
-+ { NT_(".api"), api_cmd, NULL, false},
-+ { NT_(".backups"), backupscmd, NULL, false},
-+ { NT_(".clients"), clientscmd, NULL, true},
-+ { NT_(".defaults"), defaultscmd, NULL, false},
-+ { NT_(".die"), diecmd, NULL, false},
-+ { NT_(".exit"), dot_quit_cmd, NULL, false},
-+ { NT_(".filesets"), filesetscmd, NULL, false},
-+ { NT_(".help"), dot_help_cmd, NULL, false},
-+ { NT_(".jobs"), jobscmd, NULL, true},
-+ { NT_(".levels"), levelscmd, NULL, false},
-+ { NT_(".messages"), getmsgscmd, NULL, false},
-+ { NT_(".msgs"), msgscmd, NULL, false},
-+ { NT_(".pools"), poolscmd, NULL, true},
-+ { NT_(".quit"), dot_quit_cmd, NULL, false},
-+ { NT_(".sql"), sql_cmd, NULL, false},
-+ { NT_(".status"), dot_status_cmd, NULL, false},
-+ { NT_(".storage"), storagecmd, NULL, true},
-+ { NT_(".types"), typescmd, NULL, false}
- };
- #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
-
-@@ -116,6 +116,11 @@
- }
- for (i=0; i<comsize; i++) { /* search for command */
- if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
-+ /* Check if this command is authorized in RunScript */
-+ if (ua->runscript && !commands[i].use_in_rs) {
-+ ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
-+ break;
-+ }
- bool gui = ua->gui;
- /* Check if command permitted, but "quit" is always OK */
- if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
+++ /dev/null
-Index: src/dird/ua_update.c
-===================================================================
---- src/dird/ua_update.c (révision 7144)
-+++ src/dird/ua_update.c (copie de travail)
-@@ -42,6 +42,7 @@
- static int update_volume(UAContext *ua);
- static bool update_pool(UAContext *ua);
- static bool update_job(UAContext *ua);
-+static bool update_stats(UAContext *ua);
-
- /*
- * Update a Pool Record in the database.
-@@ -53,6 +54,8 @@
- * changes pool info for volume
- * update slots [scan=...]
- * updates autochanger slots
-+ * update stats [days=...]
-+ * updates long term statistics
- */
- int update_cmd(UAContext *ua, const char *cmd)
- {
-@@ -62,6 +65,7 @@
- NT_("pool"), /* 2 */
- NT_("slots"), /* 3 */
- NT_("jobid"), /* 4 */
-+ NT_("stats"), /* 5 */
- NULL};
-
- if (!open_client_db(ua)) {
-@@ -82,6 +86,9 @@
- case 4:
- update_job(ua);
- return 1;
-+ case 5:
-+ update_stats(ua);
-+ return 1;
- default:
- break;
- }
-@@ -90,6 +97,7 @@
- add_prompt(ua, _("Volume parameters"));
- add_prompt(ua, _("Pool from resource"));
- add_prompt(ua, _("Slots from autochanger"));
-+ add_prompt(ua, _("Long term statistics"));
- switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
- case 0:
- update_volume(ua);
-@@ -100,6 +108,9 @@
- case 2:
- update_slots(ua);
- break;
-+ case 3:
-+ update_stats(ua);
-+ break;
- default:
- break;
- }
-@@ -789,6 +800,24 @@
- }
-
- /*
-+ * Update long term statistics
-+ */
-+static bool update_stats(UAContext *ua)
-+{
-+ int i = find_arg_with_value(ua, NT_("days"));
-+ utime_t since=0;
-+
-+ if (i >= 0) {
-+ since = atoi(ua->argv[i]) * 24*60*60;
-+ }
-+
-+ int nb = db_update_stats(ua->jcr, ua->db, since);
-+ ua->info_msg(_("Updating %i job(s).\n"), nb);
-+
-+ return true;
-+}
-+
-+/*
- * Update pool record -- pull info from current POOL resource
- */
- static bool update_pool(UAContext *ua)
-Index: src/cats/sql_update.c
-===================================================================
---- src/cats/sql_update.c (révision 7144)
-+++ src/cats/sql_update.c (copie de travail)
-@@ -126,6 +126,28 @@
- }
-
- /*
-+ * Update Long term statistics with all jobs that were run before
-+ * age seconds
-+ */
-+int
-+db_update_stats(JCR *jcr, B_DB *mdb, time_t age)
-+{
-+ char ed1[30];
-+ utime_t now = (utime_t)time(NULL);
-+ edit_uint64(now - age, ed1);
-+
-+ Mmsg(mdb->cmd,
-+ "INSERT INTO JobStat "
-+ "SELECT * "
-+ "FROM Job "
-+ "WHERE JobStatus IN ('T', 'f', 'A', 'E') "
-+ "AND JobId NOT IN (SELECT JobId FROM JobStat) "
-+ "AND JobTDate < %s ", ed1);
-+ QUERY_DB(jcr, mdb, mdb->cmd); /* TODO: get a message ? */
-+ return sql_affected_rows(mdb);
-+}
-+
-+/*
- * Given an incoming integer, set the string buffer to either NULL or the value
- *
- */
-@@ -134,7 +156,6 @@
- bsnprintf(s, n, id ? "%s" : "NULL", edit_int64(id, ed1));
- }
-
--
- /*
- * Update the Job record at end of Job
- *
-@@ -292,7 +313,6 @@
- {
- int stat;
- char ed1[50];
--
- db_lock(mdb);
- Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
- sr->AutoChanger, edit_int64(sr->StorageId, ed1));
-Index: src/cats/protos.h
-===================================================================
---- src/cats/protos.h (révision 7144)
-+++ src/cats/protos.h (copie de travail)
-@@ -134,5 +134,6 @@
- int db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest, int type);
- int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
- void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
-+int db_update_stats(JCR *jcr, B_DB *mdb, time_t age);
-
- #endif /* __SQL_PROTOS_H */
+++ /dev/null
-Index: patches/testing/maxschedruntime.patch
-===================================================================
---- patches/testing/maxschedruntime.patch (revision 6731)
-+++ patches/testing/maxschedruntime.patch (working copy)
-@@ -1,305 +0,0 @@
--Index: src/dird/getmsg.c
--===================================================================
----- src/dird/getmsg.c (révision 4696)
--+++ src/dird/getmsg.c (copie de travail)
--@@ -70,6 +70,33 @@
--
-- static char OK_msg[] = "1000 OK\n";
--
--+
--+void set_jcr_sd_job_status(JCR *jcr, int SDJobStatus)
--+{
--+ bool set_waittime=false;
--+ Dmsg2(800, "set_jcr_sd_job_status(%s, %c)\n", jcr->Job, SDJobStatus);
--+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
--+ switch (SDJobStatus) {
--+ case JS_WaitMedia:
--+ case JS_WaitMount:
--+ case JS_WaitMaxJobs:
--+ set_waittime = true;
--+ default:
--+ break;
--+ }
--+
--+ if (job_waiting(jcr)) {
--+ set_waittime = false;
--+ }
--+
--+ if (set_waittime) {
--+ /* set it before JobStatus */
--+ Dmsg0(800, "Setting wait_time\n");
--+ jcr->wait_time = time(NULL);
--+ }
--+ jcr->SDJobStatus = SDJobStatus;
--+}
--+
-- /*
-- * Get a message
-- * Call appropriate processing routine
--@@ -230,7 +257,7 @@
-- int JobStatus;
-- char Job[MAX_NAME_LENGTH];
-- if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
--- jcr->SDJobStatus = JobStatus; /* current status */
--+ set_jcr_sd_job_status(jcr,JobStatus); /* current status */
-- } else {
-- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
-- }
--Index: src/dird/job.c
--===================================================================
----- src/dird/job.c (révision 4696)
--+++ src/dird/job.c (copie de travail)
--@@ -41,8 +41,9 @@
-- static void *job_thread(void *arg);
-- static void job_monitor_watchdog(watchdog_t *self);
-- static void job_monitor_destructor(watchdog_t *self);
---static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
---static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
--+static bool job_check_maxwaittime(JCR *jcr);
--+static bool job_check_maxruntime(JCR *jcr);
--+static bool job_check_maxschedruntime(JCR *jcr);
--
-- /* Imported subroutines */
-- extern void term_scheduler();
--@@ -250,6 +251,11 @@
-- Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
-- }
--
--+ if (job_check_maxschedruntime(jcr)) {
--+ set_jcr_job_status(jcr, JS_Canceled);
--+ Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
--+ }
--+
-- /* TODO : check if it is used somewhere */
-- if (jcr->job->RunScripts == NULL) {
-- Dmsg0(200, "Warning, job->RunScripts is empty\n");
--@@ -450,15 +456,20 @@
-- }
--
-- /* check MaxWaitTime */
--- if (job_check_maxwaittime(control_jcr, jcr)) {
--+ if (job_check_maxwaittime(jcr)) {
-- set_jcr_job_status(jcr, JS_Canceled);
-- Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
-- cancel = true;
-- /* check MaxRunTime */
--- } else if (job_check_maxruntime(control_jcr, jcr)) {
--+ } else if (job_check_maxruntime(jcr)) {
-- set_jcr_job_status(jcr, JS_Canceled);
-- Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
-- cancel = true;
--+ /* check MaxSchedRunTime */
--+ } else if (job_check_maxschedruntime(jcr)) {
--+ set_jcr_job_status(jcr, JS_Canceled);
--+ Jmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
--+ cancel = true;
-- }
--
-- if (cancel) {
--@@ -479,29 +490,30 @@
-- * Check if the maxwaittime has expired and it is possible
-- * to cancel the job.
-- */
---static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
--+static bool job_check_maxwaittime(JCR *jcr)
-- {
-- bool cancel = false;
-- JOB *job = jcr->job;
--
--- if (job_canceled(jcr)) {
--- return false; /* already canceled */
--+ if (!job_waiting(jcr)) {
--+ return false;
-- }
-- if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
-- job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
-- return false;
-- }
--+ Dmsg3(20, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
-- if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
--- (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
--+ (watchdog_time - jcr->wait_time) >= job->FullMaxWaitTime) {
-- cancel = true;
-- } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
--- (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
--+ (watchdog_time - jcr->wait_time) >= job->DiffMaxWaitTime) {
-- cancel = true;
-- } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
--- (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
--+ (watchdog_time - jcr->wait_time) >= job->IncMaxWaitTime) {
-- cancel = true;
-- } else if (job->MaxWaitTime != 0 &&
--- (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
--+ (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
-- cancel = true;
-- }
--
--@@ -512,7 +524,7 @@
-- * Check if maxruntime has expired and if the job can be
-- * canceled.
-- */
---static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
--+static bool job_check_maxruntime(JCR *jcr)
-- {
-- if (jcr->job->MaxRunTime == 0 || job_canceled(jcr)) {
-- return false;
--@@ -527,6 +539,24 @@
-- }
--
-- /*
--+ * Check if MaxSchedRunTime has expired and if the job can be
--+ * canceled.
--+ */
--+static bool job_check_maxschedruntime(JCR *jcr)
--+{
--+ if (jcr->job->MaxSchedRunTime == 0 || job_canceled(jcr)) {
--+ return false;
--+ }
--+ if ((watchdog_time - jcr->sched_time) < jcr->job->MaxSchedRunTime) {
--+ Dmsg3(200, "Job %p (%s) with MaxSchedRunTime %d not expired\n",
--+ jcr, jcr->Job, jcr->job->MaxSchedRunTime);
--+ return false;
--+ }
--+
--+ return true;
--+}
--+
--+/*
-- * Get or create a Pool record with the given name.
-- * Returns: 0 on error
-- * poolid if OK
--Index: src/dird/dird_conf.c
--===================================================================
----- src/dird/dird_conf.c (révision 4696)
--+++ src/dird/dird_conf.c (copie de travail)
--@@ -281,6 +281,7 @@
-- {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
-- {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
-- {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
--+ {"maxschedruntime", store_time, ITEM(res_job.MaxSchedRunTime), 0, 0, 0},
-- {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
-- {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
-- {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
--@@ -627,6 +628,15 @@
-- if (res->res_job.WriteBootstrap) {
-- sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
-- }
--+ if (res->res_job.MaxRunTime) {
--+ sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
--+ }
--+ if (res->res_job.MaxWaitTime) {
--+ sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
--+ }
--+ if (res->res_job.MaxStartDelay) {
--+ sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
--+ }
-- if (res->res_job.storage) {
-- STORE *store;
-- foreach_alist(store, res->res_job.storage) {
--Index: src/dird/dird_conf.h
--===================================================================
----- src/dird/dird_conf.h (révision 4696)
--+++ src/dird/dird_conf.h (copie de travail)
--@@ -371,6 +371,7 @@
-- char *WriteVerifyList; /* List of changed files */
-- };
-- int replace; /* How (overwrite, ..) */
--+ utime_t MaxSchedRunTime; /* max run time in seconds from Scheduled time*/
-- utime_t MaxRunTime; /* max run time in seconds */
-- utime_t MaxWaitTime; /* max blocking time in seconds */
-- utime_t FullMaxWaitTime; /* Max Full job wait time */
--Index: src/jcr.h
--===================================================================
----- src/jcr.h (révision 4696)
--+++ src/jcr.h (copie de travail)
--@@ -105,6 +105,22 @@
-- jcr->JobStatus == JS_ErrorTerminated || \
-- jcr->JobStatus == JS_FatalError)
--
--+#define job_waiting(jcr) \
--+ (jcr->JobStatus == JS_WaitFD || \
--+ jcr->JobStatus == JS_WaitSD || \
--+ jcr->JobStatus == JS_WaitMedia || \
--+ jcr->JobStatus == JS_WaitMount || \
--+ jcr->JobStatus == JS_WaitStoreRes || \
--+ jcr->JobStatus == JS_WaitJobRes || \
--+ jcr->JobStatus == JS_WaitClientRes|| \
--+ jcr->JobStatus == JS_WaitMaxJobs || \
--+ jcr->JobStatus == JS_WaitPriority || \
--+ jcr->SDJobStatus == JS_WaitMedia || \
--+ jcr->SDJobStatus == JS_WaitMount || \
--+ jcr->SDJobStatus == JS_WaitMaxJobs)
--+
--+
--+
-- #define foreach_jcr(jcr) \
-- for (jcr=jcr_walk_start(); jcr; (jcr=jcr_walk_next(jcr)) )
--
--@@ -166,6 +182,7 @@
-- time_t start_time; /* when job actually started */
-- time_t run_time; /* used for computing speed */
-- time_t end_time; /* job end time */
--+ time_t wait_time; /* when job have started to wait */
-- POOLMEM *client_name; /* client name */
-- POOLMEM *RestoreBootstrap; /* Bootstrap file to restore */
-- POOLMEM *stime; /* start time for incremental/differential */
--Index: src/lib/jcr.c
--===================================================================
----- src/lib/jcr.c (révision 4696)
--+++ src/lib/jcr.c (copie de travail)
--@@ -546,18 +546,54 @@
--
-- void set_jcr_job_status(JCR *jcr, int JobStatus)
-- {
--+ bool set_waittime=false;
--+ Dmsg2(800, "set_jcr_job_status(%s, %c)\n", jcr->Job, JobStatus);
--+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
--+ switch (JobStatus) {
--+ case JS_WaitFD:
--+ case JS_WaitSD:
--+ case JS_WaitMedia:
--+ case JS_WaitMount:
--+ case JS_WaitStoreRes:
--+ case JS_WaitJobRes:
--+ case JS_WaitClientRes:
--+ case JS_WaitMaxJobs:
--+ case JS_WaitPriority:
--+ set_waittime = true;
--+ default:
--+ break;
--+ }
--+
--+ switch (jcr->JobStatus) {
-- /*
-- * For a set of errors, ... keep the current status
-- * so it isn't lost. For all others, set it.
-- */
--- switch (jcr->JobStatus) {
-- case JS_ErrorTerminated:
-- case JS_Error:
-- case JS_FatalError:
-- case JS_Differences:
-- case JS_Canceled:
-- break;
--+ /*
--+ * For a set of Wait situation, keep old time.
--+ */
--+ case JS_WaitFD:
--+ case JS_WaitSD:
--+ case JS_WaitMedia:
--+ case JS_WaitMount:
--+ case JS_WaitStoreRes:
--+ case JS_WaitJobRes:
--+ case JS_WaitClientRes:
--+ case JS_WaitMaxJobs:
--+ case JS_WaitPriority:
--+ set_waittime = false; /* keep old time */
-- default:
--+ if (set_waittime) {
--+ /* set it before JobStatus */
--+ Dmsg0(800, "Setting wait_time\n");
--+ jcr->wait_time = time(NULL);
--+ }
-- jcr->JobStatus = JobStatus;
-- }
-- }
-Index: src/dird/getmsg.c
-===================================================================
---- src/dird/getmsg.c (revision 6731)
-+++ src/dird/getmsg.c (working copy)
-@@ -70,6 +70,33 @@
-
- static char OK_msg[] = "1000 OK\n";
-
-+
-+void set_jcr_sd_job_status(JCR *jcr, int SDJobStatus)
-+{
-+ bool set_waittime=false;
-+ Dmsg2(800, "set_jcr_sd_job_status(%s, %c)\n", jcr->Job, SDJobStatus);
-+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
-+ switch (SDJobStatus) {
-+ case JS_WaitMedia:
-+ case JS_WaitMount:
-+ case JS_WaitMaxJobs:
-+ set_waittime = true;
-+ default:
-+ break;
-+ }
-+
-+ if (job_waiting(jcr)) {
-+ set_waittime = false;
-+ }
-+
-+ if (set_waittime) {
-+ /* set it before JobStatus */
-+ Dmsg0(800, "Setting wait_time\n");
-+ jcr->wait_time = time(NULL);
-+ }
-+ jcr->SDJobStatus = SDJobStatus;
-+}
-+
- /*
- * Get a message
- * Call appropriate processing routine
-@@ -230,7 +257,7 @@
- int JobStatus;
- char Job[MAX_NAME_LENGTH];
- if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
-- jcr->SDJobStatus = JobStatus; /* current status */
-+ set_jcr_sd_job_status(jcr,JobStatus); /* current status */
- } else {
- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- }
-Index: src/dird/job.c
-===================================================================
---- src/dird/job.c (revision 6731)
-+++ src/dird/job.c (working copy)
-@@ -41,8 +41,9 @@
- static void *job_thread(void *arg);
- static void job_monitor_watchdog(watchdog_t *self);
- static void job_monitor_destructor(watchdog_t *self);
--static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
--static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
-+static bool job_check_maxwaittime(JCR *jcr);
-+static bool job_check_maxruntime(JCR *jcr);
-+static bool job_check_maxschedruntime(JCR *jcr);
-
- /* Imported subroutines */
- extern void term_scheduler();
-@@ -253,6 +254,11 @@
- Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
- }
-
-+ if (job_check_maxschedruntime(jcr)) {
-+ set_jcr_job_status(jcr, JS_Canceled);
-+ Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
-+ }
-+
- /* TODO : check if it is used somewhere */
- if (jcr->job->RunScripts == NULL) {
- Dmsg0(200, "Warning, job->RunScripts is empty\n");
-@@ -493,15 +499,20 @@
- }
-
- /* check MaxWaitTime */
-- if (job_check_maxwaittime(control_jcr, jcr)) {
-+ if (job_check_maxwaittime(jcr)) {
- set_jcr_job_status(jcr, JS_Canceled);
- Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
- cancel = true;
- /* check MaxRunTime */
-- } else if (job_check_maxruntime(control_jcr, jcr)) {
-+ } else if (job_check_maxruntime(jcr)) {
- set_jcr_job_status(jcr, JS_Canceled);
- Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
- cancel = true;
-+ /* check MaxSchedRunTime */
-+ } else if (job_check_maxschedruntime(jcr)) {
-+ set_jcr_job_status(jcr, JS_Canceled);
-+ Jmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
-+ cancel = true;
- }
-
- if (cancel) {
-@@ -522,47 +533,71 @@
- * Check if the maxwaittime has expired and it is possible
- * to cancel the job.
- */
--static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
-+static bool job_check_maxwaittime(JCR *jcr)
- {
- bool cancel = false;
- JOB *job = jcr->job;
-
-- if (job_canceled(jcr)) {
-- return false; /* already canceled */
-+ if (!job_waiting(jcr)) {
-+ return false;
- }
-- if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
-- job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
-+ Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
-+ if (job->MaxWaitTime != 0 &&
-+ (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
-+ cancel = true;
-+ }
-+
-+ return cancel;
-+}
-+
-+/*
-+ * Check if maxruntime has expired and if the job can be
-+ * canceled.
-+ */
-+static bool job_check_maxruntime(JCR *jcr)
-+{
-+ bool cancel = false;
-+ JOB *job = jcr->job;
-+
-+ if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
- return false;
-- }
-- if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
-+ }
-+ if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
-+ job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
-+ return false;
-+ }
-+ Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
-+ watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
-+ job->IncMaxRunTime, job->DiffMaxRunTime);
-+
-+ if (jcr->JobLevel == L_FULL && job->FullMaxRunTime != 0 &&
-+ (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
- cancel = true;
-- } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
-+ } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
-+ (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
- cancel = true;
-- } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
-+ } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
-+ (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
- cancel = true;
-- } else if (job->MaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
-+ } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
- cancel = true;
- }
--
-+
- return cancel;
- }
-
- /*
-- * Check if maxruntime has expired and if the job can be
-+ * Check if MaxSchedRunTime has expired and if the job can be
- * canceled.
- */
--static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
-+static bool job_check_maxschedruntime(JCR *jcr)
- {
-- if (jcr->job->MaxRunTime == 0 || job_canceled(jcr) || jcr->JobStatus == JS_Created) {
-+ if (jcr->job->MaxSchedRunTime == 0 || job_canceled(jcr)) {
- return false;
- }
-- if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
-- Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
-- jcr, jcr->Job, jcr->job->MaxRunTime);
-+ if ((watchdog_time - jcr->sched_time) < jcr->job->MaxSchedRunTime) {
-+ Dmsg3(200, "Job %p (%s) with MaxSchedRunTime %d not expired\n",
-+ jcr, jcr->Job, jcr->job->MaxSchedRunTime);
- return false;
- }
-
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c (revision 6731)
-+++ src/dird/dird_conf.c (working copy)
-@@ -289,10 +289,15 @@
- {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
- {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
- {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
-+ {"maxschedruntime", store_time, ITEM(res_job.MaxSchedRunTime), 0, 0, 0},
- {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
-- {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
-- {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
-- {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
-+ /* xxxMaxWaitTime are deprecated */
-+ {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
-+ {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
-+ {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
-+ {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
-+ {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
-+ {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
- {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
- {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
- {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
-@@ -666,6 +671,15 @@
- if (res->res_job.PluginOptions) {
- sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
- }
-+ if (res->res_job.MaxRunTime) {
-+ sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
-+ }
-+ if (res->res_job.MaxWaitTime) {
-+ sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
-+ }
-+ if (res->res_job.MaxStartDelay) {
-+ sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
-+ }
- if (res->res_job.storage) {
- STORE *store;
- foreach_alist(store, res->res_job.storage) {
-Index: src/dird/dird_conf.h
-===================================================================
---- src/dird/dird_conf.h (revision 6731)
-+++ src/dird/dird_conf.h (working copy)
-@@ -384,10 +384,11 @@
- };
- utime_t MaxRunTime; /* max run time in seconds */
- utime_t MaxWaitTime; /* max blocking time in seconds */
-- utime_t FullMaxWaitTime; /* Max Full job wait time */
-- utime_t DiffMaxWaitTime; /* Max Differential job wait time */
-- utime_t IncMaxWaitTime; /* Max Incremental job wait time */
-+ utime_t FullMaxRunTime; /* Max Full job run time */
-+ utime_t DiffMaxRunTime; /* Max Differential job run time */
-+ utime_t IncMaxRunTime; /* Max Incremental job run time */
- utime_t MaxStartDelay; /* max start delay in seconds */
-+ utime_t MaxSchedRunTime; /* max run time in seconds from Scheduled time*/
- utime_t RescheduleInterval; /* Reschedule interval */
- utime_t JobRetention; /* job retention period in seconds */
- utime_t MaxFullInterval; /* Maximum time interval between Fulls */
-Index: src/jcr.h
-===================================================================
---- src/jcr.h (revision 6731)
-+++ src/jcr.h (working copy)
-@@ -109,6 +109,22 @@
- jcr->JobStatus == JS_ErrorTerminated || \
- jcr->JobStatus == JS_FatalError)
-
-+#define job_waiting(jcr) \
-+ (jcr->JobStatus == JS_WaitFD || \
-+ jcr->JobStatus == JS_WaitSD || \
-+ jcr->JobStatus == JS_WaitMedia || \
-+ jcr->JobStatus == JS_WaitMount || \
-+ jcr->JobStatus == JS_WaitStoreRes || \
-+ jcr->JobStatus == JS_WaitJobRes || \
-+ jcr->JobStatus == JS_WaitClientRes|| \
-+ jcr->JobStatus == JS_WaitMaxJobs || \
-+ jcr->JobStatus == JS_WaitPriority || \
-+ jcr->SDJobStatus == JS_WaitMedia || \
-+ jcr->SDJobStatus == JS_WaitMount || \
-+ jcr->SDJobStatus == JS_WaitMaxJobs)
-+
-+
-+
- #define foreach_jcr(jcr) \
- for (jcr=jcr_walk_start(); jcr; (jcr=jcr_walk_next(jcr)) )
-
-@@ -188,6 +204,7 @@
- time_t start_time; /* when job actually started */
- time_t run_time; /* used for computing speed */
- time_t end_time; /* job end time */
-+ time_t wait_time; /* when job have started to wait */
- POOLMEM *client_name; /* client name */
- POOLMEM *RestoreBootstrap; /* Bootstrap file to restore */
- POOLMEM *stime; /* start time for incremental/differential */
-Index: src/lib/jcr.c
-===================================================================
---- src/lib/jcr.c (revision 6731)
-+++ src/lib/jcr.c (working copy)
-@@ -632,6 +632,24 @@
-
- void set_jcr_job_status(JCR *jcr, int JobStatus)
- {
-+ bool set_waittime=false;
-+ Dmsg2(800, "set_jcr_job_status(%s, %c)\n", jcr->Job, JobStatus);
-+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
-+ switch (JobStatus) {
-+ case JS_WaitFD:
-+ case JS_WaitSD:
-+ case JS_WaitMedia:
-+ case JS_WaitMount:
-+ case JS_WaitStoreRes:
-+ case JS_WaitJobRes:
-+ case JS_WaitClientRes:
-+ case JS_WaitMaxJobs:
-+ case JS_WaitPriority:
-+ set_waittime = true;
-+ default:
-+ break;
-+ }
-+
- /*
- * For a set of errors, ... keep the current status
- * so it isn't lost. For all others, set it.
-@@ -652,10 +670,29 @@
- /* Override more minor status */
- jcr->JobStatus = JobStatus;
- break;
-+ default:
-+ break;
- }
-- break;
-+ /*
-+ * For a set of Wait situation, keep old time.
-+ */
-+ case JS_WaitFD:
-+ case JS_WaitSD:
-+ case JS_WaitMedia:
-+ case JS_WaitMount:
-+ case JS_WaitStoreRes:
-+ case JS_WaitJobRes:
-+ case JS_WaitClientRes:
-+ case JS_WaitMaxJobs:
-+ case JS_WaitPriority:
-+ set_waittime = false; /* keep old time */
- default:
- jcr->JobStatus = JobStatus;
-+ if (set_waittime) {
-+ /* set it before JobStatus */
-+ Dmsg0(800, "Setting wait_time\n");
-+ jcr->wait_time = time(NULL);
-+ }
- }
- Dmsg3(100, "jid=%u OnExit JobStatus=%c set=%c\n", (uint32_t)jcr->JobId,
- jcr->JobStatus, JobStatus);
+++ /dev/null
-Index: src/dird/getmsg.c
-===================================================================
---- src/dird/getmsg.c (révision 4696)
-+++ src/dird/getmsg.c (copie de travail)
-@@ -70,6 +70,33 @@
-
- static char OK_msg[] = "1000 OK\n";
-
-+
-+void set_jcr_sd_job_status(JCR *jcr, int SDJobStatus)
-+{
-+ bool set_waittime=false;
-+ Dmsg2(800, "set_jcr_sd_job_status(%s, %c)\n", jcr->Job, SDJobStatus);
-+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
-+ switch (SDJobStatus) {
-+ case JS_WaitMedia:
-+ case JS_WaitMount:
-+ case JS_WaitMaxJobs:
-+ set_waittime = true;
-+ default:
-+ break;
-+ }
-+
-+ if (job_waiting(jcr)) {
-+ set_waittime = false;
-+ }
-+
-+ if (set_waittime) {
-+ /* set it before JobStatus */
-+ Dmsg0(800, "Setting wait_time\n");
-+ jcr->wait_time = time(NULL);
-+ }
-+ jcr->SDJobStatus = SDJobStatus;
-+}
-+
- /*
- * Get a message
- * Call appropriate processing routine
-@@ -230,7 +257,7 @@
- int JobStatus;
- char Job[MAX_NAME_LENGTH];
- if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
-- jcr->SDJobStatus = JobStatus; /* current status */
-+ set_jcr_sd_job_status(jcr,JobStatus); /* current status */
- } else {
- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- }
-Index: src/dird/job.c
-===================================================================
---- src/dird/job.c (révision 4696)
-+++ src/dird/job.c (copie de travail)
-@@ -484,24 +484,25 @@
- bool cancel = false;
- JOB *job = jcr->job;
-
-- if (job_canceled(jcr)) {
-- return false; /* already canceled */
-+ if (!job_waiting(jcr)) {
-+ return false;
- }
- if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
- job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
- return false;
- }
-+ Dmsg3(20, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
- if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
-+ (watchdog_time - jcr->wait_time) >= job->FullMaxWaitTime) {
- cancel = true;
- } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
-+ (watchdog_time - jcr->wait_time) >= job->DiffMaxWaitTime) {
- cancel = true;
- } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
-+ (watchdog_time - jcr->wait_time) >= job->IncMaxWaitTime) {
- cancel = true;
- } else if (job->MaxWaitTime != 0 &&
-- (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
-+ (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
- cancel = true;
- }
-
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c (révision 4696)
-+++ src/dird/dird_conf.c (copie de travail)
-@@ -627,6 +627,15 @@
- if (res->res_job.WriteBootstrap) {
- sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
- }
-+ if (res->res_job.MaxRunTime) {
-+ sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
-+ }
-+ if (res->res_job.MaxWaitTime) {
-+ sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
-+ }
-+ if (res->res_job.MaxStartDelay) {
-+ sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
-+ }
- if (res->res_job.storage) {
- STORE *store;
- foreach_alist(store, res->res_job.storage) {
-Index: src/jcr.h
-===================================================================
---- src/jcr.h (révision 4696)
-+++ src/jcr.h (copie de travail)
-@@ -105,6 +105,22 @@
- jcr->JobStatus == JS_ErrorTerminated || \
- jcr->JobStatus == JS_FatalError)
-
-+#define job_waiting(jcr) \
-+ (jcr->JobStatus == JS_WaitFD || \
-+ jcr->JobStatus == JS_WaitSD || \
-+ jcr->JobStatus == JS_WaitMedia || \
-+ jcr->JobStatus == JS_WaitMount || \
-+ jcr->JobStatus == JS_WaitStoreRes || \
-+ jcr->JobStatus == JS_WaitJobRes || \
-+ jcr->JobStatus == JS_WaitClientRes|| \
-+ jcr->JobStatus == JS_WaitMaxJobs || \
-+ jcr->JobStatus == JS_WaitPriority || \
-+ jcr->SDJobStatus == JS_WaitMedia || \
-+ jcr->SDJobStatus == JS_WaitMount || \
-+ jcr->SDJobStatus == JS_WaitMaxJobs)
-+
-+
-+
- #define foreach_jcr(jcr) \
- for (jcr=jcr_walk_start(); jcr; (jcr=jcr_walk_next(jcr)) )
-
-@@ -166,6 +182,7 @@
- time_t start_time; /* when job actually started */
- time_t run_time; /* used for computing speed */
- time_t end_time; /* job end time */
-+ time_t wait_time; /* when job have started to wait */
- POOLMEM *client_name; /* client name */
- POOLMEM *RestoreBootstrap; /* Bootstrap file to restore */
- POOLMEM *stime; /* start time for incremental/differential */
-Index: src/lib/jcr.c
-===================================================================
---- src/lib/jcr.c (révision 4696)
-+++ src/lib/jcr.c (copie de travail)
-@@ -546,18 +546,54 @@
-
- void set_jcr_job_status(JCR *jcr, int JobStatus)
- {
-+ bool set_waittime=false;
-+ Dmsg2(800, "set_jcr_job_status(%s, %c)\n", jcr->Job, JobStatus);
-+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
-+ switch (JobStatus) {
-+ case JS_WaitFD:
-+ case JS_WaitSD:
-+ case JS_WaitMedia:
-+ case JS_WaitMount:
-+ case JS_WaitStoreRes:
-+ case JS_WaitJobRes:
-+ case JS_WaitClientRes:
-+ case JS_WaitMaxJobs:
-+ case JS_WaitPriority:
-+ set_waittime = true;
-+ default:
-+ break;
-+ }
-+
-+ switch (jcr->JobStatus) {
- /*
- * For a set of errors, ... keep the current status
- * so it isn't lost. For all others, set it.
- */
-- switch (jcr->JobStatus) {
- case JS_ErrorTerminated:
- case JS_Error:
- case JS_FatalError:
- case JS_Differences:
- case JS_Canceled:
- break;
-+ /*
-+ * For a set of Wait situation, keep old time.
-+ */
-+ case JS_WaitFD:
-+ case JS_WaitSD:
-+ case JS_WaitMedia:
-+ case JS_WaitMount:
-+ case JS_WaitStoreRes:
-+ case JS_WaitJobRes:
-+ case JS_WaitClientRes:
-+ case JS_WaitMaxJobs:
-+ case JS_WaitPriority:
-+ set_waittime = false; /* keep old time */
- default:
-+ if (set_waittime) {
-+ /* set it before JobStatus */
-+ Dmsg0(800, "Setting wait_time\n");
-+ jcr->wait_time = time(NULL);
-+ }
- jcr->JobStatus = JobStatus;
- }
- }
+++ /dev/null
-Index: src/dird/ua_label.c
-===================================================================
---- src/dird/ua_label.c (révision 7144)
-+++ src/dird/ua_label.c (copie de travail)
-@@ -1015,3 +1015,142 @@
- return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
- strlen(ua->jcr->pool->cleaning_prefix)) == 0;
- }
-+
-+
-+/*
-+ * Print slots from AutoChanger
-+ */
-+void status_slots(UAContext *ua, STORE *store_r)
-+{
-+ USTORE store;
-+ POOL_DBR pr;
-+ vol_list_t *vl, *vol_list = NULL;
-+ MEDIA_DBR mr;
-+ char *slot_list;
-+ int max_slots;
-+ int drive;
-+ int i=1;
-+
-+ if (!open_client_db(ua)) {
-+ return;
-+ }
-+ store.store = store_r;
-+
-+ pm_strcpy(store.store_source, _("command line"));
-+ set_wstorage(ua->jcr, &store);
-+ drive = get_storage_drive(ua, store.store);
-+
-+ max_slots = get_num_slots_from_SD(ua);
-+
-+ if (max_slots <= 0) {
-+ ua->warning_msg(_("No slots in changer to scan.\n"));
-+ return;
-+ }
-+ slot_list = (char *)malloc(max_slots+1);
-+ if (!get_user_slot_list(ua, slot_list, max_slots)) {
-+ free(slot_list);
-+ return;
-+ }
-+
-+ vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);
-+
-+ if (!vol_list) {
-+ ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
-+ goto bail_out;
-+ }
-+ if (!ua->api) {
-+ ua->info_msg(_(" Slot | Volume Name | Status | Type | Pool | Loaded |\n"));
-+ ua->info_msg(_("------+------------------+-----------+------------+--------------------+---------|\n"));
-+ }
-+ /* Walk through the list getting the media records */
-+ for (vl=vol_list; vl; vl=vl->next) {
-+ if (vl->Slot > max_slots) {
-+ ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
-+ vl->Slot, max_slots);
-+ continue;
-+ }
-+ /* Check if user wants us to look at this slot */
-+ if (!slot_list[vl->Slot]) {
-+ Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
-+ continue;
-+ }
-+
-+ slot_list[vl->Slot] = 0; /* clear Slot */
-+
-+ if (!vl->VolName) {
-+ Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
-+ if (!ua->api) {
-+ ua->info_msg(_(" %4i%c| %16s | %9s | %10s | %18s | %i |\n"),
-+ vl->Slot, '*',
-+ "?", "?", "?", "?", 0);
-+ } else {
-+ ua->info_msg(_("%i||||||\n"), vl->Slot);
-+ }
-+ continue;
-+ }
-+
-+ /* Hope that slots are ordered */
-+ for (; i < vl->Slot; i++) {
-+ if (slot_list[i]) {
-+ if (!ua->api) {
-+ ua->info_msg(_(" %4i | %16s | %9s | %10s | %18s | %i |\n"),
-+ i, "", "", "", "", 0);
-+ } else {
-+ ua->info_msg(_("%i||||||\n"), i);
-+ }
-+ slot_list[i]=0;
-+ }
-+ }
-+
-+ memset(&mr, 0, sizeof(mr));
-+ bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
-+ db_lock(ua->db);
-+ if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
-+ memset(&pr, 0, sizeof(POOL_DBR));
-+ pr.PoolId = mr.PoolId;
-+ if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
-+ strcpy(pr.Name, "?");
-+ }
-+
-+ if (!ua->api) {
-+ /* Print information */
-+ ua->info_msg(_(" %4i%c| %16s | %9s | %10s | %18s | %i |\n"),
-+ vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
-+ mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name, 0);
-+ } else {
-+ ua->info_msg(_("%i|%i|%s|%s|%s|%s|%i|\n"),
-+ vl->Slot, mr.Slot, mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name, 0);
-+ }
-+
-+ db_unlock(ua->db);
-+ continue;
-+ } else { /* TODO: get information from catalog */
-+ ua->info_msg(_(" %4i%c| %16s | %9s | %10s | %18s | %i |\n"),
-+ vl->Slot, '*',
-+ mr.VolumeName, "?", "?", "?", 0);
-+ }
-+ db_unlock(ua->db);
-+ }
-+
-+ /* Display the rest of the autochanger
-+ */
-+ for (; i <= max_slots; i++) {
-+ if (slot_list[i]) {
-+ if (!ua->api) {
-+ ua->info_msg(_(" %4i | %16s | %9s | %10s | %18s | %i |\n"),
-+ i, "", "", "", "", 0);
-+ } else {
-+ ua->info_msg(_("%i||||||\n"), i);
-+ }
-+ slot_list[i]=0;
-+ }
-+ }
-+
-+bail_out:
-+
-+ free_vol_list(vol_list);
-+ free(slot_list);
-+ close_sd_bsock(ua);
-+
-+ return;
-+}
-Index: src/dird/ua_status.c
-===================================================================
---- src/dird/ua_status.c (révision 7144)
-+++ src/dird/ua_status.c (copie de travail)
-@@ -47,6 +47,7 @@
- static void do_client_status(UAContext *ua, CLIENT *client, char *cmd);
- static void do_director_status(UAContext *ua);
- static void do_all_status(UAContext *ua);
-+void status_slots(UAContext *ua, STORE *store);
-
- static char OKqstatus[] = "1000 OK .status\n";
- static char DotStatusJob[] = "JobId=%s JobStatus=%c JobErrors=%d\n";
-@@ -157,7 +158,11 @@
- } else {
- store = get_storage_resource(ua, false/*no default*/);
- if (store) {
-- do_storage_status(ua, store, NULL);
-+ if (find_arg(ua, NT_("slots")) > 0) {
-+ status_slots(ua, store);
-+ } else {
-+ do_storage_status(ua, store, NULL);
-+ }
- }
- return 1;
- }