void term_last_jobs_list() { if (last_jobs) { lock_last_jobs_list(); while (!last_jobs->empty()) { void *je = last_jobs->first(); last_jobs->remove(je); free(je); } delete last_jobs; last_jobs = NULL; unlock_last_jobs_list(); } if (jcrs) { delete jcrs; jcrs = NULL; } }
uint64_t write_last_jobs_list(int fd, uint64_t addr) { struct s_last_job *je; uint32_t num; ssize_t status; Dmsg1(100, "write_last_jobs seek to %d\n", (int)addr); if (lseek(fd, (boffset_t)addr, SEEK_SET) < 0) { return 0; } if (last_jobs) { lock_last_jobs_list(); /* * First record is number of entires */ num = last_jobs->size(); if (write(fd, &num, sizeof(num)) != sizeof(num)) { berrno be; Pmsg1(000, "Error writing num_items: ERR=%s\n", be.bstrerror()); goto bail_out; } foreach_dlist(je, last_jobs) { if (write(fd, je, sizeof(struct s_last_job)) != sizeof(struct s_last_job)) { berrno be; Pmsg1(000, "Error writing job: ERR=%s\n", be.bstrerror()); goto bail_out; } } unlock_last_jobs_list(); } /* * Return current address */ status = lseek(fd, 0, SEEK_CUR); if (status < 0) { status = 0; } return status; bail_out: unlock_last_jobs_list(); return 0; }
bool read_last_jobs_list(int fd, uint64_t addr) { struct s_last_job *je, job; uint32_t num; bool ok = true; Dmsg1(100, "read_last_jobs seek to %d\n", (int)addr); if (addr == 0 || lseek(fd, (boffset_t)addr, SEEK_SET) < 0) { return false; } if (read(fd, &num, sizeof(num)) != sizeof(num)) { return false; } Dmsg1(100, "Read num_items=%d\n", num); if (num > 4 * max_last_jobs) { /* sanity check */ return false; } lock_last_jobs_list(); for ( ; num; num--) { if (read(fd, &job, sizeof(job)) != sizeof(job)) { berrno be; Pmsg1(000, "Read job entry. ERR=%s\n", be.bstrerror()); ok = false; break; } if (job.JobId > 0) { je = (struct s_last_job *)malloc(sizeof(struct s_last_job)); memcpy((char *)je, (char *)&job, sizeof(job)); if (!last_jobs) { init_last_jobs_list(); } last_jobs->append(je); if (last_jobs->size() > max_last_jobs) { je = (struct s_last_job *)last_jobs->first(); last_jobs->remove(je); free(je); } } } unlock_last_jobs_list(); return ok; }
void b_free_jcr(const char *file, int line, JCR *jcr) { struct s_last_job *je; Dmsg3(dbglvl, "Enter free_jcr jid=%u from %s:%d\n", jcr->JobId, file, line); #else void free_jcr(JCR *jcr) { struct s_last_job *je; Dmsg3(dbglvl, "Enter free_jcr jid=%u use_count=%d Job=%s\n", jcr->JobId, jcr->use_count(), jcr->Job); #endif lock_jcr_chain(); jcr->dec_use_count(); /* decrement use count */ if (jcr->use_count() < 0) { Jmsg2(jcr, M_ERROR, 0, _("JCR use_count=%d JobId=%d\n"), jcr->use_count(), jcr->JobId); } if (jcr->JobId > 0) { Dmsg3(dbglvl, "Dec free_jcr jid=%u use_count=%d Job=%s\n", jcr->JobId, jcr->use_count(), jcr->Job); } if (jcr->use_count() > 0) { /* if in use */ unlock_jcr_chain(); return; } if (jcr->JobId > 0) { Dmsg3(dbglvl, "remove jcr jid=%u use_count=%d Job=%s\n", jcr->JobId, jcr->use_count(), jcr->Job); } remove_jcr(jcr); /* remove Jcr from chain */ unlock_jcr_chain(); dequeue_messages(jcr); job_end_pop(jcr); /* pop and call hooked routines */ Dmsg1(dbglvl, "End job=%d\n", jcr->JobId); /* * Keep some statistics */ switch (jcr->getJobType()) { case JT_BACKUP: case JT_VERIFY: case JT_RESTORE: case JT_MIGRATE: case JT_COPY: case JT_ADMIN: /* * Keep list of last jobs, but not Console where JobId==0 */ if (jcr->JobId > 0) { lock_last_jobs_list(); num_jobs_run++; je = (struct s_last_job *)malloc(sizeof(struct s_last_job)); memset(je, 0, sizeof(struct s_last_job)); /* zero in case unset fields */ je->Errors = jcr->JobErrors; je->JobType = jcr->getJobType(); je->JobId = jcr->JobId; je->VolSessionId = jcr->VolSessionId; je->VolSessionTime = jcr->VolSessionTime; bstrncpy(je->Job, jcr->Job, sizeof(je->Job)); je->JobFiles = jcr->JobFiles; je->JobBytes = jcr->JobBytes; je->JobStatus = jcr->JobStatus; je->JobLevel = jcr->getJobLevel(); je->start_time = jcr->start_time; je->end_time = time(NULL); if (!last_jobs) { init_last_jobs_list(); } last_jobs->append(je); if (last_jobs->size() > max_last_jobs) { je = (struct s_last_job *)last_jobs->first(); last_jobs->remove(je); free(je); } unlock_last_jobs_list(); } break; default: break; } close_msg(jcr); /* close messages for this job */ if (jcr->daemon_free_jcr) { jcr->daemon_free_jcr(jcr); /* call daemon free routine */ } free_common_jcr(jcr); close_msg(NULL); /* flush any daemon messages */ Dmsg0(dbglvl, "Exit free_jcr\n"); } /* * Remove jcr from thread specific data, but * but make sure it is us who are attached. */ void remove_jcr_from_tsd(JCR *jcr) { JCR *tjcr = get_jcr_from_tsd(); if (tjcr == jcr) { set_jcr_in_tsd(INVALID_JCR); } }
static void list_terminated_jobs(STATUS_PKT *sp) { int len; struct s_last_job *je; POOL_MEM msg(PM_MESSAGE); char level[10], dt[MAX_TIME_LENGTH], b1[30], b2[30]; if (!sp->api) { len = pm_strcpy(msg, _("\nTerminated Jobs:\n")); sendit(msg, len, sp); } if (last_jobs->size() == 0) { if (!sp->api) { len = pm_strcpy(msg, _("====\n")); sendit(msg, len, sp); } return; } lock_last_jobs_list(); if (!sp->api) { len = pm_strcpy(msg, _(" JobId Level Files Bytes Status Finished Name \n")); sendit(msg, len, sp); len = pm_strcpy(msg, _("======================================================================\n")); sendit(msg, len, sp); } foreach_dlist(je, last_jobs) { char *p; char JobName[MAX_NAME_LENGTH]; const char *termstat; 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; } bstrncpy(JobName, je->Job, sizeof(JobName)); /* * There are three periods after the Job name */ for (int i=0; i<3; i++) { if ((p=strrchr(JobName, '.')) != NULL) { *p = 0; } } if (sp->api) { len = Mmsg(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 { len = Mmsg(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); } sendit(msg, len, sp); }