+ foreach_dlist(sp, &sched) {
+ prt_runtime(ua, sp);
+ }
+ if (num_jobs == 0 && !ua->api) {
+ ua->send_msg(_("No Scheduled Jobs.\n"));
+ }
+ if (!ua->api) ua->send_msg("====\n");
+ Dmsg0(200, "Leave list_sched_jobs_runs()\n");
+}
+
+static void list_running_jobs(UAContext *ua)
+{
+ JCR *jcr;
+ int njobs = 0;
+ const char *msg;
+ char *emsg; /* edited message */
+ char dt[MAX_TIME_LENGTH];
+ char level[10];
+ bool pool_mem = false;
+
+ Dmsg0(200, "enter list_run_jobs()\n");
+ if (!ua->api) ua->send_msg(_("\nRunning Jobs:\n"));
+ foreach_jcr(jcr) {
+ if (jcr->JobId == 0) { /* this is us */
+ /* this is a console or other control job. We only show console
+ * jobs in the status output.
+ */
+ if (jcr->JobType == JT_CONSOLE && !ua->api) {
+ bstrftime_nc(dt, sizeof(dt), jcr->start_time);
+ ua->send_msg(_("Console connected at %s\n"), dt);
+ }
+ continue;
+ }
+ njobs++;
+ }
+ endeach_jcr(jcr);
+
+ if (njobs == 0) {
+ /* Note the following message is used in regress -- don't change */
+ if (!ua->api) ua->send_msg(_("No Jobs running.\n====\n"));
+ Dmsg0(200, "leave list_run_jobs()\n");
+ return;
+ }
+ njobs = 0;
+ if (!ua->api) {
+ ua->send_msg(_(" JobId Level Name Status\n"));
+ ua->send_msg(_("======================================================================\n"));
+ }
+ foreach_jcr(jcr) {
+ if (jcr->JobId == 0 || !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
+ continue;
+ }
+ njobs++;
+ switch (jcr->JobStatus) {
+ case JS_Created:
+ msg = _("is waiting execution");
+ break;
+ case JS_Running:
+ msg = _("is running");
+ break;
+ case JS_Blocked:
+ msg = _("is blocked");
+ break;
+ case JS_Terminated:
+ msg = _("has terminated");
+ break;
+ case JS_ErrorTerminated:
+ msg = _("has erred");
+ break;
+ case JS_Error:
+ msg = _("has errors");
+ break;
+ case JS_FatalError:
+ msg = _("has a fatal error");
+ break;
+ case JS_Differences:
+ msg = _("has verify differences");
+ break;
+ case JS_Canceled:
+ msg = _("has been canceled");
+ break;
+ case JS_WaitFD:
+ emsg = (char *) get_pool_memory(PM_FNAME);
+ if (!jcr->client) {
+ Mmsg(emsg, _("is waiting on Client"));
+ } else {
+ Mmsg(emsg, _("is waiting on Client %s"), jcr->client->name());
+ }
+ pool_mem = true;
+ msg = emsg;
+ break;
+ case JS_WaitSD:
+ emsg = (char *) get_pool_memory(PM_FNAME);
+ if (jcr->wstore) {
+ Mmsg(emsg, _("is waiting on Storage %s"), jcr->wstore->name());
+ } else if (jcr->rstore) {
+ Mmsg(emsg, _("is waiting on Storage %s"), jcr->rstore->name());
+ } else {
+ Mmsg(emsg, _("is waiting on Storage"));
+ }
+ pool_mem = true;
+ msg = emsg;
+ break;
+ case JS_WaitStoreRes:
+ msg = _("is waiting on max Storage jobs");
+ break;
+ case JS_WaitClientRes:
+ msg = _("is waiting on max Client jobs");
+ break;
+ case JS_WaitJobRes:
+ msg = _("is waiting on max Job jobs");
+ break;
+ case JS_WaitMaxJobs:
+ msg = _("is waiting on max total jobs");
+ break;
+ case JS_WaitStartTime:
+ msg = _("is waiting for its start time");
+ break;
+ case JS_WaitPriority:
+ msg = _("is waiting for higher priority jobs to finish");
+ break;
+ case JS_DataCommitting:
+ msg = _("SD committing Data");
+ break;
+ case JS_DataDespooling:
+ msg = _("SD despooling Data");
+ break;
+ case JS_AttrDespooling:
+ msg = _("SD despooling Attributes");
+ break;
+ case JS_AttrInserting:
+ msg = _("Dir inserting Attributes");
+ break;
+
+ default:
+ emsg = (char *)get_pool_memory(PM_FNAME);
+ Mmsg(emsg, _("is in unknown state %c"), jcr->JobStatus);
+ pool_mem = true;
+ msg = emsg;
+ break;
+ }
+ /*
+ * Now report Storage daemon status code
+ */
+ switch (jcr->SDJobStatus) {
+ case JS_WaitMount:
+ if (pool_mem) {
+ free_pool_memory(emsg);
+ pool_mem = false;
+ }
+ msg = _("is waiting for a mount request");
+ break;
+ case JS_WaitMedia:
+ if (pool_mem) {
+ free_pool_memory(emsg);
+ pool_mem = false;
+ }
+ msg = _("is waiting for an appendable Volume");
+ break;
+ case JS_WaitFD:
+ if (!pool_mem) {
+ emsg = (char *)get_pool_memory(PM_FNAME);
+ pool_mem = true;
+ }
+ if (!jcr->client || !jcr->wstore) {
+ Mmsg(emsg, _("is waiting for Client to connect to Storage daemon"));
+ } else {
+ Mmsg(emsg, _("is waiting for Client %s to connect to Storage %s"),
+ jcr->client->name(), jcr->wstore->name());
+ }
+ msg = emsg;
+ break;
+ case JS_DataCommitting:
+ msg = _("SD committing Data");
+ break;
+ case JS_DataDespooling:
+ msg = _("SD despooling Data");
+ break;
+ case JS_AttrDespooling:
+ msg = _("SD despooling Attributes");
+ break;
+ case JS_AttrInserting:
+ msg = _("Dir inserting Attributes");
+ break;
+ }
+ switch (jcr->JobType) {
+ case JT_ADMIN:
+ case JT_RESTORE:
+ bstrncpy(level, " ", sizeof(level));
+ break;
+ default:
+ bstrncpy(level, level_to_str(jcr->JobLevel), sizeof(level));
+ level[7] = 0;
+ break;
+ }
+
+ if (ua->api) {
+ ua->send_msg(_("%6d\t%-6s\t%-20s\t%s\n"),
+ jcr->JobId, level, jcr->Job, msg);
+ } else {
+ ua->send_msg(_("%6d %-6s %-20s %s\n"),
+ jcr->JobId, level, jcr->Job, msg);
+ }
+
+ if (pool_mem) {
+ free_pool_memory(emsg);
+ pool_mem = false;
+ }
+ }
+ endeach_jcr(jcr);
+ if (!ua->api) ua->send_msg("====\n");
+ Dmsg0(200, "leave list_run_jobs()\n");
+}
+
+static void list_terminated_jobs(UAContext *ua)
+{
+ char dt[MAX_TIME_LENGTH], b1[30], b2[30];
+ char level[10];
+
+ if (last_jobs->empty()) {
+ if (!ua->api) ua->send_msg(_("No Terminated Jobs.\n"));
+ return;
+ }
+ lock_last_jobs_list();
+ struct s_last_job *je;
+ if (!ua->api) {
+ ua->send_msg(_("\nTerminated Jobs:\n"));
+ ua->send_msg(_(" JobId Level Files Bytes Status Finished Name \n"));
+ ua->send_msg(_("====================================================================\n"));
+ }
+ foreach_dlist(je, last_jobs) {
+ char JobName[MAX_NAME_LENGTH];
+ const char *termstat;
+
+ bstrncpy(JobName, je->Job, sizeof(JobName));
+ /* There are three periods after the Job name */
+ char *p;
+ for (int i=0; i<3; i++) {
+ if ((p=strrchr(JobName, '.')) != NULL) {
+ *p = 0;
+ }
+ }
+
+ if (!acl_access_ok(ua, Job_ACL, JobName)) {
+ continue;
+ }
+
+ bstrftime_nc(dt, sizeof(dt), je->end_time);
+ switch (je->JobType) {
+ case JT_ADMIN:
+ case JT_RESTORE:
+ bstrncpy(level, " ", sizeof(level));
+ break;
+ default:
+ bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
+ level[4] = 0;
+ break;
+ }
+ switch (je->JobStatus) {
+ case JS_Created:
+ termstat = _("Created");
+ break;
+ case JS_FatalError:
+ case JS_ErrorTerminated:
+ termstat = _("Error");
+ break;
+ case JS_Differences:
+ termstat = _("Diffs");
+ break;
+ case JS_Canceled:
+ termstat = _("Cancel");
+ break;
+ case JS_Terminated:
+ termstat = _("OK");
+ break;
+ default:
+ termstat = _("Other");
+ break;
+ }
+ if (ua->api) {
+ ua->send_msg(_("%6d\t%-6s\t%8s\t%10s\t%-7s\t%-8s\t%s\n"),
+ je->JobId,
+ level,
+ edit_uint64_with_commas(je->JobFiles, b1),
+ edit_uint64_with_suffix(je->JobBytes, b2),
+ termstat,
+ dt, JobName);
+ } else {
+ ua->send_msg(_("%6d %-6s %8s %10s %-7s %-8s %s\n"),
+ je->JobId,
+ level,
+ edit_uint64_with_commas(je->JobFiles, b1),
+ edit_uint64_with_suffix(je->JobBytes, b2),
+ termstat,
+ dt, JobName);
+ }
+ }
+ if (!ua->api) ua->send_msg(_("\n"));
+ unlock_last_jobs_list();