int main(int argc, char *argv[]) { char *str[] = {"3", "3n", "3 hours", "3.5 day", "3 week", "3 m", "3 q", "3 years"}; utime_t val; char buf[100]; char outval[100]; for (int i=0; i<8; i++) { strcpy(buf, str[i]); if (!duration_to_utime(buf, &val)) { printf("Error return from duration_to_utime for in=%s\n", str[i]); continue; } edit_utime(val, outval); printf("in=%s val=%" lld " outval=%s\n", str[i], val, outval); } }
static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr) { char ed1[150], ed2[50]; POOL_MEM query(PM_MESSAGE); if (!duration_to_utime(val, &mr->VolRetention)) { ua->error_msg(_("Invalid retention period specified: %s\n"), val); return; } Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s", edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId,ed2)); if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New retention period is: %s\n"), edit_utime(mr->VolRetention, ed1, sizeof(ed1))); } }
/* * Confirm a retention period */ bool confirm_retention(UAContext *ua, utime_t *ret, const char *msg) { bool retval; char ed1[100]; int yes_in_arg; yes_in_arg = find_arg(ua, NT_("yes")); for ( ;; ) { ua->info_msg(_("The current %s retention period is: %s\n"), msg, edit_utime(*ret, ed1, sizeof(ed1))); if (yes_in_arg != -1) { return true; } if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) { return false; } if (bstrcasecmp(ua->cmd, _("mod"))) { if (!get_cmd(ua, _("Enter new retention period: "))) { return false; } if (!duration_to_utime(ua->cmd, ret)) { ua->error_msg(_("Invalid period.\n")); continue; } continue; } if (is_yesno(ua->cmd, &retval)) { return retval; } } return true; }
/* * Pruning Jobs is a bit more complicated than purging Files * because we delete Job records only if there is a more current * backup of the FileSet. Otherwise, we keep the Job record. * In other words, we never delete the only Job record that * contains a current backup of a FileSet. This prevents the * Volume from being recycled and destroying a current backup. * * For Verify Jobs, we do not delete the last InitCatalog. * * For Restore Jobs there are no restrictions. */ int prune_jobs(UAContext *ua, CLIENTRES *client, POOLRES *pool, int JobType) { POOL_MEM query(PM_MESSAGE); POOL_MEM sql_where(PM_MESSAGE); POOL_MEM sql_from(PM_MESSAGE); utime_t period; char ed1[50]; alist *jobids_check=NULL; struct accurate_check_ctx *elt; db_list_ctx jobids, tempids; JOB_DBR jr; struct del_ctx del; memset(&del, 0, sizeof(del)); if (pool && pool->JobRetention > 0) { period = pool->JobRetention; } else if (client) { period = client->JobRetention; } else { /* should specify at least pool or client */ return false; } db_lock(ua->db); if (!prune_set_filter(ua, client, pool, period, &sql_from, &sql_where)) { goto bail_out; } /* Drop any previous temporary tables still there */ drop_temp_tables(ua); /* Create temp tables and indicies */ if (!create_temp_tables(ua)) { goto bail_out; } edit_utime(period, ed1, sizeof(ed1)); Jmsg(ua->jcr, M_INFO, 0, _("Begin pruning Jobs older than %s.\n"), ed1); del.max_ids = 100; del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); del.PurgedFiles = (char *)malloc(del.max_ids); /* * Select all files that are older than the JobRetention period * and add them into the "DeletionCandidates" table. */ Mmsg(query, "INSERT INTO DelCandidates " "SELECT JobId,PurgedFiles,FileSetId,JobFiles,JobStatus " "FROM Job %s " /* JOIN Pool/Client */ "WHERE Type IN ('B', 'C', 'M', 'V', 'D', 'R', 'c', 'm', 'g') " " %s ", /* Pool/Client + JobTDate */ sql_from.c_str(), sql_where.c_str()); Dmsg1(050, "select sql=%s\n", query.c_str()); if (!db_sql_query(ua->db, query.c_str())) { if (ua->verbose) { ua->error_msg("%s", db_strerror(ua->db)); } goto bail_out; } /* Now, for the selection, we discard some of them in order to be always * able to restore files. (ie, last full, last diff, last incrs) * Note: The DISTINCT could be more useful if we don't get FileSetId */ jobids_check = New(alist(10, owned_by_alist)); Mmsg(query, "SELECT DISTINCT Job.Name, FileSet, Client.Name, Job.FileSetId, " "Job.ClientId, Job.Type " "FROM DelCandidates " "JOIN Job USING (JobId) " "JOIN Client USING (ClientId) " "JOIN FileSet ON (Job.FileSetId = FileSet.FileSetId) " "WHERE Job.Type IN ('B') " /* Look only Backup jobs */ "AND Job.JobStatus IN ('T', 'W') " /* Look only useful jobs */ ); /* The job_select_handler will skip jobs or filesets that are no longer * in the configuration file. Interesting ClientId/FileSetId will be * added to jobids_check (currently disabled in 6.0.7b) */ if (!db_sql_query(ua->db, query.c_str(), job_select_handler, jobids_check)) { ua->error_msg("%s", db_strerror(ua->db)); } /* For this selection, we exclude current jobs used for restore or * accurate. This will prevent to prune the last full backup used for * current backup & restore */ memset(&jr, 0, sizeof(jr)); /* To find useful jobs, we do like an incremental */ jr.JobLevel = L_INCREMENTAL; foreach_alist(elt, jobids_check) { jr.ClientId = elt->ClientId; /* should be always the same */ jr.FileSetId = elt->FileSetId; db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids); jobids.add(tempids); }
/* * Generic function which generates a restore summary message. * Used by: * - native_restore_cleanup e.g. normal restores * - ndmp_restore_cleanup e.g. NDMP restores */ void generate_restore_summary(JCR *jcr, int msg_type, const char *term_msg) { char sdt[MAX_TIME_LENGTH], edt[MAX_TIME_LENGTH]; char ec1[30], ec2[30], ec3[30], elapsed[50]; char fd_term_msg[100], sd_term_msg[100]; utime_t RunTime; double kbps; bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime); bstrftimes(edt, sizeof(edt), jcr->jr.EndTime); RunTime = jcr->jr.EndTime - jcr->jr.StartTime; if (RunTime <= 0) { kbps = 0; } else { kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime); } if (kbps < 0.05) { kbps = 0; } jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg)); switch (jcr->getJobProtocol()) { case PT_NDMP: Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n" " Build OS: %s %s %s\n" " JobId: %d\n" " Job: %s\n" " Restore Client: %s\n" " Start time: %s\n" " End time: %s\n" " Elapsed time: %s\n" " Files Expected: %s\n" " Files Restored: %s\n" " Bytes Restored: %s\n" " Rate: %.1f KB/s\n" " SD termination status: %s\n" " Termination: %s\n\n"), BAREOS, my_name, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER, jcr->jr.JobId, jcr->jr.Job, jcr->res.client->name(), sdt, edt, edit_utime(RunTime, elapsed, sizeof(elapsed)), edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1), edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2), edit_uint64_with_commas(jcr->jr.JobBytes, ec3), (float)kbps, sd_term_msg, term_msg); break; default: Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n" " Build OS: %s %s %s\n" " JobId: %d\n" " Job: %s\n" " Restore Client: %s\n" " Start time: %s\n" " End time: %s\n" " Elapsed time: %s\n" " Files Expected: %s\n" " Files Restored: %s\n" " Bytes Restored: %s\n" " Rate: %.1f KB/s\n" " FD Errors: %d\n" " FD termination status: %s\n" " SD termination status: %s\n" " Termination: %s\n\n"), BAREOS, my_name, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER, jcr->jr.JobId, jcr->jr.Job, jcr->res.client->name(), sdt, edt, edit_utime(RunTime, elapsed, sizeof(elapsed)), edit_uint64_with_commas((uint64_t)jcr->ExpectedFiles, ec1), edit_uint64_with_commas((uint64_t)jcr->jr.JobFiles, ec2), edit_uint64_with_commas(jcr->jr.JobBytes, ec3), (float)kbps, jcr->JobErrors, fd_term_msg, sd_term_msg, term_msg); break; } }
/* * Update a media record -- allows you to change the * Volume status. E.g. if you want Bacula to stop * writing on the volume, set it to anything other * than Append. */ static int update_volume(UAContext *ua) { MEDIA_DBR mr; POOL *pool; POOL_DBR pr; POOLMEM *query; POOL_MEM ret; char buf[1000]; char ed1[130]; bool done = false; int i; const char *kw[] = { NT_("VolStatus"), /* 0 */ NT_("VolRetention"), /* 1 */ NT_("VolUse"), /* 2 */ NT_("MaxVolJobs"), /* 3 */ NT_("MaxVolFiles"), /* 4 */ NT_("MaxVolBytes"), /* 5 */ NT_("Recycle"), /* 6 */ NT_("InChanger"), /* 7 */ NT_("Slot"), /* 8 */ NT_("Pool"), /* 9 */ NT_("FromPool"), /* 10 */ NT_("AllFromPool"), /* 11 !!! see below !!! */ NT_("Enabled"), /* 12 */ NT_("RecyclePool"), /* 13 */ NT_("ActionOnPurge"), /* 14 */ NULL }; #define AllFromPool 11 /* keep this updated with above */ for (i=0; kw[i]; i++) { int j; POOL_DBR pr; if ((j=find_arg_with_value(ua, kw[i])) > 0) { /* If all from pool don't select a media record */ if (i != AllFromPool && !select_media_dbr(ua, &mr)) { return 0; } switch (i) { case 0: update_volstatus(ua, ua->argv[j], &mr); break; case 1: update_volretention(ua, ua->argv[j], &mr); break; case 2: update_voluseduration(ua, ua->argv[j], &mr); break; case 3: update_volmaxjobs(ua, ua->argv[j], &mr); break; case 4: update_volmaxfiles(ua, ua->argv[j], &mr); break; case 5: update_volmaxbytes(ua, ua->argv[j], &mr); break; case 6: update_volrecycle(ua, ua->argv[j], &mr); break; case 7: update_volinchanger(ua, ua->argv[j], &mr); break; case 8: update_volslot(ua, ua->argv[j], &mr); break; case 9: memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.PoolId; if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); break; } update_vol_pool(ua, ua->argv[j], &mr, &pr); break; case 10: update_vol_from_pool(ua, &mr); return 1; case 11: update_all_vols_from_pool(ua, ua->argv[j]); return 1; case 12: update_volenabled(ua, ua->argv[j], &mr); break; case 13: update_vol_recyclepool(ua, ua->argv[j], &mr); break; case 14: update_vol_actiononpurge(ua, ua->argv[j], &mr); break; } done = true; } } /* Allow user to simply update all volumes */ if (find_arg(ua, NT_("fromallpools")) > 0) { update_all_vols(ua); return 1; } for ( ; !done; ) { start_prompt(ua, _("Parameters to modify:\n")); add_prompt(ua, _("Volume Status")); /* 0 */ add_prompt(ua, _("Volume Retention Period")); /* 1 */ add_prompt(ua, _("Volume Use Duration")); /* 2 */ add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */ add_prompt(ua, _("Maximum Volume Files")); /* 4 */ add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */ add_prompt(ua, _("Recycle Flag")); /* 6 */ add_prompt(ua, _("Slot")); /* 7 */ add_prompt(ua, _("InChanger Flag")); /* 8 */ add_prompt(ua, _("Volume Files")); /* 9 */ add_prompt(ua, _("Pool")); /* 10 */ add_prompt(ua, _("Volume from Pool")); /* 11 */ add_prompt(ua, _("All Volumes from Pool")); /* 12 */ add_prompt(ua, _("All Volumes from all Pools")); /* 13 */ add_prompt(ua, _("Enabled")), /* 14 */ add_prompt(ua, _("RecyclePool")), /* 15 */ add_prompt(ua, _("Action On Purge")), /* 16 */ add_prompt(ua, _("Done")); /* 17 */ i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0); /* For All Volumes, All Volumes from Pool, and Done, we don't need * a Volume record */ if ( i != 12 && i != 13 && i != 17) { if (!select_media_dbr(ua, &mr)) { /* Get Volume record */ return 0; } ua->info_msg(_("Updating Volume \"%s\"\n"), mr.VolumeName); } switch (i) { case 0: /* Volume Status */ /* Modify Volume Status */ ua->info_msg(_("Current Volume status is: %s\n"), mr.VolStatus); start_prompt(ua, _("Possible Values are:\n")); add_prompt(ua, NT_("Append")); add_prompt(ua, NT_("Archive")); add_prompt(ua, NT_("Disabled")); add_prompt(ua, NT_("Full")); add_prompt(ua, NT_("Used")); add_prompt(ua, NT_("Cleaning")); if (strcmp(mr.VolStatus, NT_("Purged")) == 0) { add_prompt(ua, NT_("Recycle")); } add_prompt(ua, NT_("Read-Only")); if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) { return 1; } update_volstatus(ua, ua->cmd, &mr); break; case 1: /* Retention */ ua->info_msg(_("Current retention period is: %s\n"), edit_utime(mr.VolRetention, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Enter Volume Retention period: "))) { return 0; } update_volretention(ua, ua->cmd, &mr); break; case 2: /* Use Duration */ ua->info_msg(_("Current use duration is: %s\n"), edit_utime(mr.VolUseDuration, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Enter Volume Use Duration: "))) { return 0; } update_voluseduration(ua, ua->cmd, &mr); break; case 3: /* Max Jobs */ ua->info_msg(_("Current max jobs is: %u\n"), mr.MaxVolJobs); if (!get_pint(ua, _("Enter new Maximum Jobs: "))) { return 0; } update_volmaxjobs(ua, ua->cmd, &mr); break; case 4: /* Max Files */ ua->info_msg(_("Current max files is: %u\n"), mr.MaxVolFiles); if (!get_pint(ua, _("Enter new Maximum Files: "))) { return 0; } update_volmaxfiles(ua, ua->cmd, &mr); break; case 5: /* Max Bytes */ ua->info_msg(_("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1)); if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) { return 0; } update_volmaxbytes(ua, ua->cmd, &mr); break; case 6: /* Recycle */ ua->info_msg(_("Current recycle flag is: %s\n"), mr.Recycle==1?_("yes"):_("no")); if (!get_yesno(ua, _("Enter new Recycle status: "))) { return 0; } update_volrecycle(ua, ua->cmd, &mr); break; case 7: /* Slot */ ua->info_msg(_("Current Slot is: %d\n"), mr.Slot); if (!get_pint(ua, _("Enter new Slot: "))) { return 0; } update_volslot(ua, ua->cmd, &mr); break; case 8: /* InChanger */ ua->info_msg(_("Current InChanger flag is: %d\n"), mr.InChanger); bsnprintf(buf, sizeof(buf), _("Set InChanger flag for Volume \"%s\": yes/no: "), mr.VolumeName); if (!get_yesno(ua, buf)) { return 0; } mr.InChanger = ua->pint32_val; /* * Make sure to use db_update... rather than doing this directly, * so that any Slot is handled correctly. */ if (!db_update_media_record(ua->jcr, ua->db, &mr)) { ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db)); } else { ua->info_msg(_("New InChanger flag is: %d\n"), mr.InChanger); } break; case 9: /* Volume Files */ int32_t VolFiles; ua->warning_msg(_("Warning changing Volume Files can result\n" "in loss of data on your Volume\n\n")); ua->info_msg(_("Current Volume Files is: %u\n"), mr.VolFiles); if (!get_pint(ua, _("Enter new number of Files for Volume: "))) { return 0; } VolFiles = ua->pint32_val; if (VolFiles != (int)(mr.VolFiles + 1)) { ua->warning_msg(_("Normally, you should only increase Volume Files by one!\n")); if (!get_yesno(ua, _("Increase Volume Files? (yes/no): ")) || ua->pint32_val == 0) { break; } } query = get_pool_memory(PM_MESSAGE); Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s", VolFiles, edit_int64(mr.MediaId, ed1)); if (!db_sql_query(ua->db, query, NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New Volume Files is: %u\n"), VolFiles); } free_pool_memory(query); break; case 10: /* Volume's Pool */ memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.PoolId; if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); return 0; } ua->info_msg(_("Current Pool is: %s\n"), pr.Name); if (!get_cmd(ua, _("Enter new Pool name: "))) { return 0; } update_vol_pool(ua, ua->cmd, &mr, &pr); return 1; case 11: update_vol_from_pool(ua, &mr); return 1; case 12: pool = select_pool_resource(ua); if (pool) { update_all_vols_from_pool(ua, pool->name()); } return 1; case 13: update_all_vols(ua); return 1; case 14: ua->info_msg(_("Current Enabled is: %d\n"), mr.Enabled); if (!get_cmd(ua, _("Enter new Enabled: "))) { return 0; } if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) { mr.Enabled = 1; } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) { mr.Enabled = 0; } else if (strcasecmp(ua->cmd, "archived") == 0) { mr.Enabled = 2; } else { mr.Enabled = atoi(ua->cmd); } update_volenabled(ua, ua->cmd, &mr); break; case 15: memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.RecyclePoolId; if (db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->info_msg(_("Current RecyclePool is: %s\n"), pr.Name); } else { ua->info_msg(_("No current RecyclePool\n")); } if (!select_pool_dbr(ua, &pr, NT_("recyclepool"))) { return 0; } update_vol_recyclepool(ua, pr.Name, &mr); return 1; case 16: pm_strcpy(ret, ""); ua->info_msg(_("Current ActionOnPurge is: %s\n"), action_on_purge_to_string(mr.ActionOnPurge, ret)); if (!get_cmd(ua, _("Enter new ActionOnPurge (one of: Truncate, None): "))) { return 0; } update_vol_actiononpurge(ua, ua->cmd, &mr); break; default: /* Done or error */ ua->info_msg(_("Selection terminated.\n")); return 1; } } return 1; }
/* * Populate the text in the window */ void MediaInfo::populateForm() { utime_t t; time_t ttime; QString stat, LastWritten; struct tm tm; char buf[256]; QString query = "SELECT MediaId, VolumeName, Pool.Name, MediaType, FirstWritten," "LastWritten, VolMounts, VolBytes, Media.Enabled," "Location.Location, VolStatus, RecyclePool.Name, Media.Recycle, " "VolReadTime/1000000, VolWriteTime/1000000, Media.VolUseDuration, " "Media.MaxVolJobs, Media.MaxVolFiles, Media.MaxVolBytes, " "Media.VolRetention,InChanger,Slot " "FROM Media JOIN Pool USING (PoolId) LEFT JOIN Pool AS RecyclePool " "ON (Media.RecyclePoolId=RecyclePool.PoolId) " "LEFT JOIN Location ON (Media.LocationId=Location.LocationId) " "WHERE Media.VolumeName='" + m_mediaName + "'"; if (mainWin->m_sqlDebug) { Pmsg1(000, "MediaInfo query cmd : %s\n",query.toUtf8().data()); } QStringList results; if (m_console->sql_cmd(query, results)) { QString resultline; QStringList fieldlist; foreach (resultline, results) { // should have only one result fieldlist = resultline.split("\t"); QStringListIterator fld(fieldlist); m_mediaId = fld.next(); label_VolumeName->setText(fld.next()); label_Pool->setText(fld.next()); label_MediaType->setText(fld.next()); label_FirstWritten->setText(fld.next()); LastWritten = fld.next(); label_LastWritten->setText(LastWritten); // label_VolFiles->setText(fld.next()); label_VolMounts->setText(fld.next()); label_VolBytes->setText(convertBytesSI(fld.next().toULongLong())); label_Enabled->setPixmap(QPixmap(":/images/inflag" + fld.next() + ".png")); label_Location->setText(fld.next()); label_VolStatus->setText(fld.next()); label_RecyclePool->setText(fld.next()); chkbox_Recycle->setCheckState(fld.next().toInt()?Qt::Checked:Qt::Unchecked); edit_utime(fld.next().toULongLong(), buf, sizeof(buf)); label_VolReadTime->setText(QString(buf)); edit_utime(fld.next().toULongLong(), buf, sizeof(buf)); label_VolWriteTime->setText(QString(buf)); edit_utime(fld.next().toULongLong(), buf, sizeof(buf)); label_VolUseDuration->setText(QString(buf)); label_MaxVolJobs->setText(fld.next()); label_MaxVolFiles->setText(fld.next()); label_MaxVolBytes->setText(fld.next()); stat = fld.next(); edit_utime(stat.toULongLong(), buf, sizeof(buf)); label_VolRetention->setText(QString(buf)); if (LastWritten != "") { t = str_to_utime(LastWritten.toAscii().data()); t = t + stat.toULongLong(); ttime = t; localtime_r(&ttime, &tm); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); label_Expire->setText(QString(buf)); } label_Online->setPixmap(QPixmap(":/images/inflag"+fld.next()+".png")); // label_VolFiles->setText(fld.next()); // label_VolErrors->setText(fld.next()); // stat=fld.next(); // jobstatus_to_ascii_gui(stat[0].toAscii(), buf, sizeof(buf)); // stat = buf; // }
/* * Release resources allocated during backup. */ void backup_cleanup(JCR *jcr, int TermCode) { char sdt[50], edt[50], schedt[50]; char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50]; char ec6[30], ec7[30], ec8[30], elapsed[50]; char term_code[100], fd_term_msg[100], sd_term_msg[100]; const char *term_msg; int msg_type = M_INFO; MEDIA_DBR mr; CLIENT_DBR cr; double kbps, compression; utime_t RunTime; if (jcr->get_JobLevel() == L_VIRTUAL_FULL) { vbackup_cleanup(jcr, TermCode); return; } Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode); memset(&mr, 0, sizeof(mr)); memset(&cr, 0, sizeof(cr)); update_job_end(jcr, TermCode); if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"), db_strerror(jcr->db)); set_jcr_job_status(jcr, JS_ErrorTerminated); } bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name)); if (!db_get_client_record(jcr, jcr->db, &cr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting Client record for Job report: ERR=%s"), db_strerror(jcr->db)); } bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName)); if (!db_get_media_record(jcr, jcr->db, &mr)) { Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"), mr.VolumeName, db_strerror(jcr->db)); set_jcr_job_status(jcr, JS_ErrorTerminated); } update_bootstrap_file(jcr); switch (jcr->JobStatus) { case JS_Terminated: if (jcr->JobErrors || jcr->SDErrors) { term_msg = _("Backup OK -- with warnings"); } else { term_msg = _("Backup OK"); } break; case JS_Warnings: term_msg = _("Backup OK -- with warnings"); break; case JS_FatalError: case JS_ErrorTerminated: term_msg = _("*** Backup Error ***"); msg_type = M_ERROR; /* Generate error message */ if (jcr->store_bsock) { jcr->store_bsock->signal(BNET_TERMINATE); if (jcr->SD_msg_chan) { pthread_cancel(jcr->SD_msg_chan); } } break; case JS_Canceled: term_msg = _("Backup Canceled"); if (jcr->store_bsock) { jcr->store_bsock->signal(BNET_TERMINATE); if (jcr->SD_msg_chan) { pthread_cancel(jcr->SD_msg_chan); } } break; default: term_msg = term_code; sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus); break; } bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime); bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime); bstrftimes(edt, sizeof(edt), jcr->jr.EndTime); RunTime = jcr->jr.EndTime - jcr->jr.StartTime; if (RunTime <= 0) { kbps = 0; } else { kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime); } if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) { /* * Note, if the job has erred, most likely it did not write any * tape, so suppress this "error" message since in that case * it is normal. Or look at it the other way, only for a * normal exit should we complain about this error. */ if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); } jcr->VolumeName[0] = 0; /* none */ } if (jcr->ReadBytes == 0) { bstrncpy(compress, "None", sizeof(compress)); } else { compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes); if (compression < 0.5) { bstrncpy(compress, "None", sizeof(compress)); } else { bsnprintf(compress, sizeof(compress), "%.1f %%", compression); } } jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg)); // bmicrosleep(15, 0); /* for debugging SIGHUP */ Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n" " Build OS: %s %s %s\n" " JobId: %d\n" " Job: %s\n" " Backup Level: %s%s\n" " Client: \"%s\" %s\n" " FileSet: \"%s\" %s\n" " Pool: \"%s\" (From %s)\n" " Catalog: \"%s\" (From %s)\n" " Storage: \"%s\" (From %s)\n" " Scheduled time: %s\n" " Start time: %s\n" " End time: %s\n" " Elapsed time: %s\n" " Priority: %d\n" " FD Files Written: %s\n" " SD Files Written: %s\n" " FD Bytes Written: %s (%sB)\n" " SD Bytes Written: %s (%sB)\n" " Rate: %.1f KB/s\n" " Software Compression: %s\n" " VSS: %s\n" " Encryption: %s\n" " Accurate: %s\n" " Volume name(s): %s\n" " Volume Session Id: %d\n" " Volume Session Time: %d\n" " Last Volume Bytes: %s (%sB)\n" " Non-fatal FD errors: %d\n" " SD Errors: %d\n" " FD termination status: %s\n" " SD termination status: %s\n" " Termination: %s\n\n"), BACULA, my_name, VERSION, LSMDATE, edt, HOST_OS, DISTNAME, DISTVER, jcr->jr.JobId, jcr->jr.Job, level_to_str(jcr->get_JobLevel()), jcr->since, jcr->client->name(), cr.Uname, jcr->fileset->name(), jcr->FSCreateTime, jcr->pool->name(), jcr->pool_source, jcr->catalog->name(), jcr->catalog_source, jcr->wstore->name(), jcr->wstore_source, schedt, sdt, edt, edit_utime(RunTime, elapsed, sizeof(elapsed)), jcr->JobPriority, edit_uint64_with_commas(jcr->jr.JobFiles, ec1), edit_uint64_with_commas(jcr->SDJobFiles, ec2), edit_uint64_with_commas(jcr->jr.JobBytes, ec3), edit_uint64_with_suffix(jcr->jr.JobBytes, ec4), edit_uint64_with_commas(jcr->SDJobBytes, ec5), edit_uint64_with_suffix(jcr->SDJobBytes, ec6), kbps, compress, jcr->VSS?_("yes"):_("no"), jcr->Encrypt?_("yes"):_("no"), jcr->accurate?_("yes"):_("no"), jcr->VolumeName, jcr->VolSessionId, jcr->VolSessionTime, edit_uint64_with_commas(mr.VolBytes, ec7), edit_uint64_with_suffix(mr.VolBytes, ec8), jcr->JobErrors, jcr->SDErrors, fd_term_msg, sd_term_msg, term_msg); Dmsg0(100, "Leave backup_cleanup()\n"); }