+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);
+ }